加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

u-boot移植到mini2440之四

发布时间:2020-12-15 18:45:04 所属栏目:百科 来源:网络整理
导读:平台:mini2440 + sst39vf1601 日期:2012-5-24 四、nor flash移植 分析源代码是为了更好理解芯片的操作时序。 flash_init 函数,我们在分析 u-boot 启动代码时就看见过调用了这个函数,这个函数主要是将 flash 扇区的起始地址保存在一个全局数据区中,之所

平台:mini2440 + sst39vf1601 日期:2012-5-24


四、nor flash移植

分析源代码是为了更好理解芯片的操作时序。

flash_init函数,我们在分析u-boot启动代码时就看见过调用了这个函数,这个函数主要是将flash扇区的起始地址保存在一个全局数据区中,之所以其中有if判断语句判断,是因为该芯片的每个扇区大小不一样,sst39vf1601和这款芯片不同,它的每个扇区大小都是一样的,所以我们需要对这部分代码做部分修改。

sst39vf1601芯片知识补充:

sst39vf1601它是块2M大小的nofflash芯片,它有32个块,每块大小为64K。如果以扇区来看,它有512个扇区,每个扇区都是相同大小的,为4K。移植后的代码如下:

/*-----------------------------------------------------------------------
?*/

ulong flash_init (void)
{
? ? ? ? int i,j;
? ? ? ? ulong size = 0;

? ? ? ? for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
? ? ? ? ? ? ? ? ulong flashbase = 0;

? ? ? ? ? ? ? ? flash_info[i].flash_id =
#if defined(CONFIG_SST_xF1601)
? ? ? ? ? ? ? ? ? ? ? ? (SST_MANUFACT & FLASH_VENDMASK) |
? ? ? ? ? ? ? ? ? ? ? ? (SST_ID_xF1601 & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
#endif
? ? ? ? ? ? ? ? flash_info[i].size = FLASH_BANK_SIZE;
? ? ? ? ? ? ? ? flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
? ? ? ? ? ? ? ? memset (flash_info[i].protect,CONFIG_SYS_MAX_FLASH_SECT);
? ? ? ? ? ? ? ? if (i == 0)
? ? ? ? ? ? ? ? ? ? ? ? flashbase = PHYS_FLASH_1;
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? ? ? panic ("configured too many flash banks!n");
? ? ? ? ? ? ? ? for (j = 0; j < flash_info[i].sector_count; j++) {
? ? ? ? ? ? ? ? ? ? ? ? flash_info[i].start[j] = flashbase + j * MAIN_SECT_SIZE;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? size += flash_info[i].size;
? ? ? ? }

? ? ? ? flash_protect (FLAG_PROTECT_SET,
? ? ? ? ? ? ? ? ? ? ? ?CONFIG_SYS_FLASH_BASE,
? ? ? ? ? ? ? ? ? ? ? ?CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
? ? ? ? ? ? ? ? ? ? ? ?&flash_info[0]);

? ? ? ? flash_protect (FLAG_PROTECT_SET,
? ? ? ? ? ? ? ? ? ? ? ?CONFIG_ENV_ADDR,
? ? ? ? ? ? ? ? ? ? ? ?CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,&flash_info[0]);

? ? ? ? return size;
}

修改flash_print_info函数,这个函数打印flash相关信息,修改后代码如下:

/*-----------------------------------------------------------------------
?*/
void flash_print_info (flash_info_t * info)
{
? ? ? ? int i;

? ? ? ? switch (info->flash_id & FLASH_VENDMASK) {
? ? ? ? case (SST_MANUFACT & FLASH_VENDMASK):
? ? ? ? ? ? ? ? printf ("SST: ");
? ? ? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? ? ? printf ("Unknown Vendor ");
? ? ? ? ? ? ? ? break;
? ? ? ? }

? ? ? ? switch (info->flash_id & FLASH_TYPEMASK) {
? ? ? ? case (SST_ID_xF1601 & FLASH_TYPEMASK):
? ? ? ? ? ? ? ? printf ("1x SST39VF1601 (2Mbit)n");
? ? ? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? ? ? printf ("Unknown Chip Typen");
? ? ? ? ? ? ? ? goto Done;
? ? ? ? ? ? ? ? break;
? ? ? ? }

? ? ? ? printf (" ?Size: %ld MB in %d Sectorsn",
? ? ? ? ? ? ? ? info->size >> 20,info->sector_count);

? ? ? ? printf (" ?Sector Start Addresses:");
? ? ? ? for (i = 0; i < info->sector_count; i++) {
? ? ? ? ? ? ? ? if ((i % 5) == 0) {
? ? ? ? ? ? ? ? ? ? ? ? printf ("n ? ");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? printf (" %08lX%s",info->start[i],
? ? ? ? ? ? ? ? ? ? ? ? info->protect[i] ? " (RO)" : " ? ? ");
? ? ? ? }
? ? ? ? printf ("n");

? ? ? Done:;
}

接下来是擦除和写函数。


写过flash驱动的肯定看过这个表,这就是flash操作的命令表,看懂了这张表,那么你写flash驱动就没有问题了。

先说擦除,擦除有三种方式擦除,扇区擦除、块擦除和芯片擦除。所有的norflash操作都是发送上面的命令序列完成的,这三种方式擦除只是最后一个周期的命令不一样,扇区擦除对应的是30H,块擦除和芯片擦除分别对应的是50H10H。扇区擦除对应的地址是扇区地址,块擦除对应的地址是块地址,而芯片擦除地址固定为5555H

那么怎么判断擦除操作是否成功了呢?有三种判断方式,这三种方式也同样适用于写操作。

1.根据时间判断

操作命令发送之后,等待相应的一段时间,如果不出意外的话,操作就算成功。字编程、扇区擦除、块擦除和芯片擦除等待的时间分别为TBPTSETBETSCE,它们的最大值分别为10us25ms25ms50ms。也就是说这个最大等待时间都还没有完成操作的话,那么你就别等了,可能操作发送什么错误了。

2.Toggle Bit

这种方法是读取相同地址的字数据,判断DQ6是否相同,如果相同说明操作完成,如果不相同,说明操作没有完成。

3.Data# Polling

这种方法是读取DQ7值,如果值为1,操作完成,否则,操作没有完成。

还有就是需要说明的是,由于mini2440norflash连线时是A1连接到norflashA0这样错开一位连接的。所以在发送5555H2AAA和这种地址的时候需要将地址左移一位,以便norflash能收到正确的地址。

u-boot中我们可以修改驱动支持扇区擦除或者是块擦除,我们修改u-boot中的sector大小和数量即可实现。注意sectornorflash中的扇区概念是不同的,sector可以理解为擦除操作的一个基本单位。那么支持哪种擦除好呢,这就要看实际需求了,扇区擦除可以将norflash分的很细,但是块擦除操作速度更快。这里我们根据实际需要选择块作为u-boot中的基本操作单元。修改后代码如下。

支持块擦除需要修改上面的擦除命令:

//#define CMD_ERASE_CONFIRM ? ? 0x00000030
#define CMD_ERASE_CONFIRM ? ? ? 0x00000050

修改擦除函数如下:

/*-----------------------------------------------------------------------
?*/

int flash_erase (flash_info_t * info,int s_first,int s_last)
{
? ? ? ? ushort result;
? ? ? ? int iflag,cflag,prot,sect;
? ? ? ? int rc = ERR_OK;
? ? ? ? int chip;

? ? ? ? /* first look for protection bits */

? ? ? ? if (info->flash_id == FLASH_UNKNOWN)
? ? ? ? ? ? ? ? return ERR_UNKNOWN_FLASH_TYPE;

? ? ? ? if ((s_first < 0) || (s_first > s_last)) {
? ? ? ? ? ? ? ? return ERR_INVAL;
? ? ? ? }

? ? ? ? if ((info->flash_id & FLASH_VENDMASK) !=
? ? ? ? ? ? (SST_MANUFACT & FLASH_VENDMASK)) {
? ? ? ? ? ? ? ? return ERR_UNKNOWN_FLASH_VENDOR;
? ? ? ? }

? ? ? ? prot = 0;
? ? ? ? for (sect = s_first; sect <= s_last; ++sect) {
? ? ? ? ? ? ? ? if (info->protect[sect]) {
? ? ? ? ? ? ? ? ? ? ? ? prot++;
? ? ? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (prot)
? ? ? ? ? ? ? ? return ERR_PROTECTED;

? ? ? ? /*
? ? ? ? ?* Disable interrupts which might cause a timeout
? ? ? ? ?* here. Remember that our exception vectors are
? ? ? ? ?* at address 0 in the flash,and we don't want a
? ? ? ? ?* (ticker) exception to happen while the flash
? ? ? ? ?* chip is in programming mode.
? ? ? ? ?*/
? ? ? ? cflag = icache_status ();
? ? ? ? icache_disable ();
? ? ? ? iflag = disable_interrupts ();

? ? ? ? /* Start erase on unprotected sectors */
? ? ? ? for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {

? ? ? ? ? ? ? ? printf ("Erasing sector %2d ... ",sect);

? ? ? ? ? ? ? ? /* arm simple,non interrupt dependent timer */
? ? ? ? ? ? ? ? reset_timer_masked ();

? ? ? ? ? ? ? ? if (info->protect[sect] == 0) { /* not protected */
? ? ? ? ? ? ? ? ? ? ? ? vu_short *addr = (vu_short *) (info->start[sect]);

? ? ? ? ? ? ? ? ? ? ? ? MEM_FLASH_ADDR1 = CMD_UNLOCK1;
? ? ? ? ? ? ? ? ? ? ? ? MEM_FLASH_ADDR2 = CMD_UNLOCK2;
? ? ? ? ? ? ? ? ? ? ? ? MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;

? ? ? ? ? ? ? ? ? ? ? ? MEM_FLASH_ADDR1 = CMD_UNLOCK1;
? ? ? ? ? ? ? ? ? ? ? ? MEM_FLASH_ADDR2 = CMD_UNLOCK2;
? ? ? ? ? ? ? ? ? ? ? ? *addr = CMD_ERASE_CONFIRM;

? ? ? ? ? ? ? ? ? ? ? ? /* wait until flash is ready */
? ? ? ? ? ? ? ? ? ? ? ? chip = 0;

? ? ? ? ? ? ? ? ? ? ? ? do {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = *addr;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* check timeout */
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (get_timer_masked () >
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CONFIG_SYS_FLASH_ERASE_TOUT) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? chip = TMO;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!chip
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? && (result & 0xFFFF) & BIT_ERASE_DONE)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? chip = READY;

? ? ? ? ? ? ? ? ? ? ? ? } while (!chip);

? ? ? ? ? ? ? ? ? ? ? ? if (chip == ERR) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? rc = ERR_PROG_ERROR;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goto outahere;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if (chip == TMO) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? rc = ERR_TIMOUT;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goto outahere;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? printf ("ok.n");
? ? ? ? ? ? ? ? } else { ? ? ? ?/* it was protected */

? ? ? ? ? ? ? ? ? ? ? ? printf ("protected!n");
? ? ? ? ? ? ? ? }
? ? ? ? }

? ? ? ? if (ctrlc ())
? ? ? ? ? ? ? ? printf ("User Interrupt!n");

? ? ? outahere:
? ? ? ? /* allow flash to settle - wait 10 ms */
? ? ? ? udelay_masked (10000);

? ? ? ? if (iflag)
? ? ? ? ? ? ? ? enable_interrupts ();

? ? ? ? if (cflag)
? ? ? ? ? ? ? ? icache_enable ();

? ? ? ? return rc;
}

主要修改的部分是对擦除成功的判断,我们这里用到了两个方法,一个是时间,如果超过一定时间则认为擦除失败。另一个是判断DQ7的值,如果操作成功,该位将被置1

看了擦除,再来看写操作。

写操作只有字写,也就是说一次写两个字节,我们看u-boot中写函数很明显和sst39vf1601写的命令列表不一样,所以这部分肯定是要修改的。修改后代码如下:

/*-----------------------------------------------------------------------
?* Copy memory to flash
?*/

static int write_hword (flash_info_t * info,ulong dest,ushort data)
{
? ? ? ? vu_short *addr = (vu_short *) dest;
? ? ? ? ushort result;
? ? ? ? int rc = ERR_OK;
? ? ? ? int cflag,iflag;
? ? ? ? int chip;

? ? ? ? /*
? ? ? ? ?* Check if Flash is (sufficiently) erased
? ? ? ? ?*/
? ? ? ? result = *addr;
? ? ? ? if ((result & data) != data)
? ? ? ? ? ? ? ? return ERR_NOT_ERASED;

? ? ? ? /*
? ? ? ? ?* Disable interrupts which might cause a timeout
? ? ? ? ?* here. Remember that our exception vectors are
? ? ? ? ?* at address 0 in the flash,and we don't want a
? ? ? ? ?* (ticker) exception to happen while the flash
? ? ? ? ?* chip is in programming mode.
? ? ? ? ?*/
? ? ? ? cflag = icache_status ();
? ? ? ? icache_disable ();
? ? ? ? iflag = disable_interrupts ();

? ? ? ? MEM_FLASH_ADDR1 = CMD_UNLOCK1;
? ? ? ? MEM_FLASH_ADDR2 = CMD_UNLOCK2;
? ? ? ? //MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
? ? ? ? //*addr = CMD_PROGRAM;
? ? ? ? MEM_FLASH_ADDR1 = CMD_PROGRAM;
? ? ? ? *addr = data;

? ? ? ? /* arm simple,non interrupt dependent timer */
? ? ? ? reset_timer_masked ();

? ? ? ? /* wait until flash is ready */
? ? ? ? chip = 0;
? ? ? ? do {

? ? ? ? ? ? ? ? result = *addr;

? ? ? ? ? ? ? ? /* check timeout */
? ? ? ? ? ? ? ? if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) {
? ? ? ? ? ? ? ? ? ? ? ? chip = ERR | TMO;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (!chip && ((result & 0x80) == (data & 0x80)))
? ? ? ? ? ? ? ? ? ? ? ? chip = READY;

? ? ? ? } while (!chip);

? ? ? ? if (chip == ERR || *addr != data)
? ? ? ? ? ? ? ? rc = ERR_PROG_ERROR;

? ? ? ? if (iflag)
? ? ? ? ? ? ? ? enable_interrupts ();

? ? ? ? if (cflag)
? ? ? ? ? ? ? ? icache_enable ();

? ? ? ? return rc;
}

修改了命令时序和对操作是否成功做检测。

至此,整个flash驱动修改完成。

最后,还有最重要的,在配置文件中定义该芯片相关的一些宏定义,这样整个norflash驱动才算移植完成。norflash相关修改如下:

#define PHYS_FLASH_1 ? ? ? ? ? ?0x00000000 /* Flash Bank #1 */

#define CONFIG_SYS_FLASH_BASE ? ? ? ? ? PHYS_FLASH_1

/*-----------------------------------------------------------------------
?* FLASH and environment organization
?*/

#define CONFIG_SST_xF1601 ? ? ? 1 ? ? ? /* sst39vf1601 */

#define CONFIG_SYS_MAX_FLASH_BANKS ? ? ?1 ? ? ? /* max number of memory banks */
#ifdef CONFIG_SST_xF1601
#define PHYS_FLASH_SIZE ? ? ? ? 0x00200000 /* 2MB */
#define CONFIG_SYS_MAX_FLASH_SECT ? ? ? (32) ? ?/* max number of sectors on one chip */
#define CONFIG_ENV_ADDR ? ? ? ? (CONFIG_SYS_FLASH_BASE + 0x040000) /* addr of environment */
#endif

/* timeout values are in ticks */
#define CONFIG_SYS_FLASH_ERASE_TOUT ? ? (3*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
#define CONFIG_SYS_FLASH_WRITE_TOUT ? ? (CONFIG_SYS_HZ/200) /* Timeout for Flash Write */

#define CONFIG_ENV_IS_IN_FLASH ?1
#define CONFIG_ENV_SIZE ? ? ? ? 0x10000 /* Total Size of Environment Sector */

其中定义了sst39vf1601sector数目,环境变量起始地址和空间大小。

对超时检测的时间修改:

/* the PWM TImer 4 uses a counter of 15625 for 10 ms,so we need */
/* it to wrap 100 times (total 1562500) to get 1 sec. */
#define CONFIG_SYS_HZ ? ? ? ? ? ? ? ? ? 15625 //1562500

原来的1秒种太长了,还是修改成10毫秒合适。


附:完整nor flash驱动flash.c可以从这里下载flash.c

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读