总体来讲,问题是出在 write_hword() 函数中的最后
验证写入的数据是否与实现一致时出的错。
*addr = CMD_READ_ARRAY;
if (chip == ERR || *addr != data) // *addr != data
rc = ERR_PROG_ERROR;
if (iflag)
为什么写入的东西结果读出来不一致呢?想一下,在上一次实验中,写入的数据是18(10010B),结果读出来的是1107(10001010011B)。比较一下二进制:
18 000000
10010
1107 100010
10011
我们发觉它们的1~4位都是1001,这个是不是给我们一点提示?
NorFlash在擦除时是将所有的位都清成0,当写入数据时将对应的位置1,进行OR运行,所以叫NorFlash。与此相反的NandFlash则是在擦除时将所有位置1,写入时与写入的数据进行AND运算。
我们可以进行一个大胆的猜测,NorFlash原来这个地址上的数据并没有被擦除,原来的值为100010
000011,当我们写入18(10010)时,与100010000011进行OR运行,最终得到 100010
10011。
为了证实我的这一个推论,只要将写入前addr地址上的值打印出来就知道了。
在写数据之前,先打印一下result的值。OK, Let me have a try.
在写入数据之前,我们从地址上读出的数据是1107,这确实说明NorFlash没有被擦除,不然这个值要么是0xFFFFFFFF要么是0x00000000,怎么会是一个1107呢?
既然是没有擦除引起的,那么我就来查找一下到底是为什么没有擦除。
我们要关注:u-boot/board/my2440/flash.c 文件中的 flash_erase() 函数:
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) !=
(AMD_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 () >
CFG_FLASH_ERASE_TOUT) {
MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
chip = TMO;
break;
}
if (!chip
&& (result & 0xFFFF) & BIT_ERASE_DONE)
chip = READY;
if (!chip
&& (result & 0xFFFF) & BIT_PROGRAM_ERROR)
chip = ERR;
} while (!chip);
MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
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;
}
第一步:8~20,是在对一些基本信息进行校验。
第二步:20~29,检查Flash芯片的保护标志,如果还有扇区还处于保存状态则返回 ERR_PROTECTED 。
第三步:38~40,关中断与cache。
第四步:
42~100,正式执行擦除操作。
第五步:102~116,现场恢复
结合U-Boot命令执行结果输出:
可以分析出:
(1)程序输出了“Erasing sector 0...”说明函数执行到了第四步。
(1)程序输出了“Erasing sector 0...”说明函数执行到了第四步。
(2)程序没有输出:“Ok.”,“protected!”,也没有输出“User Interrupt!”信息,说明程序地执行擦除操作时执行了 L88 或 L92 处的 goto outahere; 直接跳到 L105去执行了。
今天到此为止,明天继续……