OpenJTAG调试实例:解决无法擦除SST39VF1601
很多人的开发板上的NOR Flash是AM29LV800或AM29LV160,使用本网站提供的u-boot可以正常操作;
昨天,一个网友发现无法擦除SST39VF1601,比如出现以下现象:
要擦除0x2000开始的一个扇区,显示成功,但是实际上把其中的内容读出,发现不是0xff:
OpenJTAG> erase 2000 +1000
. done
Erased 1 sectors
OpenJTAG> md.l 2000
00002000: e3a03a0f e283300d e5823000 e582000c .:...0...0......
00002010: e3e0314f e5820010 e24335ff e2433603 O1.......5C..6C.
00002020: e5823008 e8bd8400 00012e7c 00000158 .0......|...X...
00002030: e3a00000 e1a0f00e e92d45f0 e3a07000 .........E-..p..
00002040: e59fa0f0 e2800007 e59f30ec e08fa00a .........0......
00002050: e79a2003 e3c05007 e5924000 e1a08003 . ...P...@......
00002060: e1540007 0a000029 e2856014 e5d40004 ..T.)....`......
00002070: e3500000 1a000022 e5943008 e1530005 ..P."....0....S.
00002080: 3a000013 e0653003 e3530014 e3a02001 ...:.0e...S.. ..
00002090: e5c42004 9a00001d e3a03a0f e283300d . .......:...0..
000020a0: e7843006 e0841006 e5814010 e594200c .0.......@... ..
000020b0: e581200c e5943008 e5c10004 e0653003 . ...0.......0e.
000020c0: e2433014 e5813008 e584100c e5845008 .0C..0.......P..
000020d0: ea00000e e594300c e3530000 02273001 .....0....S..0'.
000020e0: 13a03000 e3530000 0a000005 ebffffcf .0....S.........
000020f0: e3500000 179a3008 13a07001 15934000 ..P..0...p...@..
下面开始调试:
1. 根据SST39VF1601数据手册的擦除命令,使用u-boot的mw.w命令进行手工擦除:


在u-boot里执行(注意,之所以使用mw.w,是因为SST39VF1601是16位的;里面的地址之所以是AAAA、5554,这是由上图中的5555h、2AAAH左移1位得来的──因为CPU的ADDR1接到SST39VF1601的ADDR0):
OpenJTAG> mw.w AAAA AA
OpenJTAG> mw.w 5554 55
OpenJTAG> mw.w AAAA 80
OpenJTAG> mw.w AAAA AA
OpenJTAG> mw.w 5554 55
OpenJTAG> mw.w 2000 30
OpenJTAG>
OpenJTAG> md.l 2000
00002000: ffffffff ffffffff ffffffff ffffffff ................
00002010: ffffffff ffffffff ffffffff ffffffff ................
00002020: ffffffff ffffffff ffffffff ffffffff ................
00002030: ffffffff ffffffff ffffffff ffffffff ................
00002040: ffffffff ffffffff ffffffff ffffffff ................
00002050: ffffffff ffffffff ffffffff ffffffff ................
00002060: ffffffff ffffffff ffffffff ffffffff ................
00002070: ffffffff ffffffff ffffffff ffffffff ................
00002080: ffffffff ffffffff ffffffff ffffffff ................
00002090: ffffffff ffffffff ffffffff ffffffff ................
000020a0: ffffffff ffffffff ffffffff ffffffff ................
000020b0: ffffffff ffffffff ffffffff ffffffff ................
000020c0: ffffffff ffffffff ffffffff ffffffff ................
000020d0: ffffffff ffffffff ffffffff ffffffff ................
000020e0: ffffffff ffffffff ffffffff ffffffff ................
000020f0: ffffffff ffffffff ffffffff ffffffff ................
可见,手工擦除是成功的,这表明硬件没问题,应该是软件的BUG。
2. 找到擦除命令的代码,它在drivers/cfi_flash.c的1099行左右,如下图:


3. 按照OpenJTAG教程调试u-boot,在上述代码那里设置断点。从第1个步骤可以知道,擦除NOR Flash实质的操作就是那6个写操作。


在代码里,最终就是调用flash_write16函数6次。
4. 现在开始调试:
① 在Eclipse里,在flash_write16函数处设置断点;
② 在串口,执行“erase 2000 +1000”命令,
③ 发现Eclipse自动跳到flash_write16函数处,观察这个函数的变量,如下图:


发现写val 128即0x80时,addr是0xcaaa,与第1个步骤的“mw.w AAAA 80”相比,这是有问题的!!!
0xcaaa从何而来?应该是被擦除的地址0x2000加上0xAAAA。
可见,问题的根源应该是:不要加0x2000。
所以,代码修改如下:


重新编译u-boot,经过验证,问题解决!