昨天我们查看了Flash写入失败的相关代码。我在怀疑自己是不是在配置的时候选错了芯片型号。从电路原理图上看,我们的NorFlash芯片型号是:AM29LV160DB/SST39VF1601。
经过一番查找,终于搞明白了。
在 u-boot/board/ 目录下有很多个文件夹。每一个文件夹以板子的型号命令,比如smdk2400,smdk2410,my2440等。在每一个文件夹下都有该板子单独的设备 驱动文件。在my2440这个文件夹下就有一个flash.c文件。这个文件里定义了NorFlash驱动函数。
既然我们找到了这个文件,那么我们就用AXD单步进行调试一下。
单步执行 > protect off all 时,运行到do_protect()函数。我发现在
红框所地的代码并没有执行。我查看了一下 include/configs/my2440.h文件,没有搜到CFG_FLASH_PROTECTION 宏的定义。不知道这会对烧写U-Boot到NorFlash有无影响。
我还遇到一个问题,为什么在AXD里调试U-Boot,看不到变量里的值。我记得用ADS编写代码再用AXD调试时都可以看到的嘛。如何解决?
在board/my2440/flash.c文件中搜索宏 ERR_PROG_ERROR.
可以搜到两处使用了ERR_PROG_ERROR宏:
- volatile static int write_hword (flash_info_t * info, ulong dest, ushort data)
- int flash_erase (flash_info_t * info, int s_first, int s_last)
其中write_hword()应该是在命令 “cp.b 0x30000000 0 40000”时出错的主要原因。看代码如下:
volatile 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;
*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 () > CFG_FLASH_ERASE_TOUT) {
chip = ERR | TMO;
break;
}
if (!chip && ((result & 0x80) == (data & 0x80)))
chip = READY;
if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) {
result = *addr;
if ((result & 0x80) == (data & 0x80))
chip = READY;
else
chip = ERR;
}
} while (!chip);
*addr = CMD_READ_ARRAY;
if (chip == ERR || *addr != data)
rc = ERR_PROG_ERROR;
if (iflag)
enable_interrupts ();
if (cflag)
icache_enable ();
return rc;
}
见L63~64可知,只有chip的值为ERR或则从addr地址上读出来的数据不等于data就会返回ERR_PROG_ERROR错误。
ERR只在代码的44,56两处出现。但如果执行了44行的代那,那么chip的值应该是ERR|TMO=0x03,不等于ERR。那么只有在56行这个有可能。分析一下50~57行代码的功能:
在40行 result = *addr,从addr地址上读取一个数据。在50行处检查result的第5位 ( (result & 0xFFFF ) & BIT_PROGRAM_ERROR),如果为1则表示写错误。然后在51行再读取一次,再进行一次检查。如果数据正常却将chip置为READY,否则置为ERR。
为了找到倒底是哪里出错,在将在这里加调试信息。
编译后生成u-boot.bin文件,然后复制到e:u-boot-gdbu-boot.bin。再进行调试。
在终端看到如上:
可见,得到失败的原因了,是359行处 (*addr != data) 条件不成立。不过有一点问题,如果*addr读出的值与读的次数有关就可能不太确定了。还是再小改一下:
结果再次执行,显示结果:
看来,还真是读出来的值不一致引起的。这个该怎么办呢?