一、实验环境
1.1 虚拟机环境
a) Vmware版本:Vmware Workstation 12.5.7
b) Ubuntu版本:9.10
c) 内核版本:2.6.31.14
d) toolchain版本:arm-linux-gcc 3.4.5
1.2 开发板
优龙FS2410开发板,UDA1341声卡
1.3 调试器
硬件:百问网OpenJTAG
软件:OpenOCD、Eclipse 3.6 Helios
二、调试过程记录
1、开发板的JP1设置为NOR启动,然后通过u-boot和DNW的USB功能把sound.bin烧写到nandflash的地址0处,把windows.wav烧写到0x60000处,
然后JP1设置为NAND启动。重新上电,耳机插入开发板 ,在串口终端的菜单里,选择:[M] MINI2440 或者 [T] TQ2440,但是耳机里没有任何声音!
2、用OpenJTAG+Eclipse调试代码
(具体方法详见:百问网OpenJTAG 调试器产品手册《Eclipse,OpenOCD,OpenJTAGv3.1 开发教程v5.pdf》2.4 使用Eclipse 调试程序:以S3C2440 的leds 程序为例)
启动调试后,报:
0x33f8028c in nand_addr (addr=
经查,是因为init.c中:#define NFADDR (*((volatile unsigned char *)0x4E00000C)),这是2440的,不是2410的。
解决办法:
修改init.c:
// #define NFCONT (*((volatile unsigned long *)0x4E000004))
// #define NFCMMD (*((volatile unsigned char *)0x4E000008))
// #define NFADDR (*((volatile unsigned char *)0x4E00000C))
// #define NFDATA (*((volatile unsigned char *)0x4E000010))
// #define NFSTAT (*((volatile unsigned char *)0x4E000020))
#define NFCMMD (*((volatile unsigned char *)0x4E000004))
#define NFADDR (*((volatile unsigned char *)0x4E000008))
#define NFDATA (*((volatile unsigned char *)0x4E00000C))
#define NFSTAT (*((volatile unsigned char *)0x4E000010))
3、再次在串口终端的菜单里,选择:[M] MINI2440 或者 [T] TQ2440,这次耳机里能听见声音了!
但是,当把sound.bin重新烧写到nandflash后,重启开发板,再试,耳机里还是没有任何声音!
4、由于eclipse不支持调试位于nand中的代码,所以只能用telnet客户端登陆到OpenOCD来调试
(具体方法详见:百问网OpenJTAG 调试器产品手册《Eclipse,OpenOCD,OpenJTAGv3.1 开发教程v5.pdf》2.2 使用OpenOCD、OpenJTAG 烧写程序、调试程序)
halt
load_image sound.bin 0x0
step 0
resume之后,有时会进入undefined instruction 异常!
有时却会pc反复的在b8,bc之间辗转:
实在找不出原因。 无奈之下,只能用step逐条语句运行,经过一系列的step(为了提高定位效率,可以用二分法),最终发现问题的症结:
查sound.dis的反汇编代码:
33f80330
33f80330: e92d41f0 push {r4, r5, r6, r7, r8, lr}
33f80334: e1823000 orr r3, r2, r0
33f80338: e1a0cb83 lsl ip, r3, #23
33f8033c: e1a0cbac lsr ip, ip, #23
33f80340: e35c0000 cmp ip, #0 ; 0x0
33f80344: e24dd008 sub sp, sp, #8 ; 0x8
33f80348: e1a05002 mov r5, r2
33f8034c: e1a04001 mov r4, r1
33f80350: 1a000031 bne 33f8041c
…
33f8041c: e28dd008 add sp, sp, #8 ; 0x8
33f80420: e8bd41f0 pop {r4, r5, r6, r7, r8, lr}
33f80424: e12fff1e bx lr
复制代码
对应于init.c的nand_read:
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { //NAND_BLOCK_MASK=511,因为K9F1208 一页大小是512字节
return ; /* 如果地址或长度不对齐,就直接返回*/
}
通过查看r2寄存器的值,可知size=0x33D4,而0x33D4& 1ff !=0 ,所以程序直接return了!最终导致nand里的代码段未能拷贝到程序的链接地址,因此程序跑飞了!
经查,调用栈是这样的:
(head.S)
mov r0, #0
ldr r1, =_start
ldr r2, =__bss_start
sub r2, r2, r1
bl copy_code_to_sdram # 会调用init.c的copy_code_to_sdram(0, _start, __bss_start) ,其中,_start即.text ,而.text 和__bss_start都定义在sound.lds中
copy_code_to_sdram(src, dst, len) # 把程序从nand读出来拷贝到内存_start地址处,长度为__bss_start-_start
nand_read(src, dest, len)
查看sound.lds,有:
…
. = ALIGN(4); //表明当前链接地址按4字节对齐
__bss_start = .;
…
遂改为:. = ALIGN(512); 再试,终于能播放声音了!
注:FS2410使用的 NAND是K9F1208, 一页大小是512字节,根据数据手册以及网文,它的读操作,支持页内任意地址读,但目前nand_read代码先不改了,等以后有时间再改。
三、总结
通过在优龙FS2410开发板上进行UDA1341声卡的裸板驱动调试,进一步了解了声卡驱动的硬件操作框架和流程,以及裸板驱动的调试方法。
裸板驱动的难点主要是:
1、 codec芯片的配置, soc的配置(包括DAI(比如IIS)、DMA),machine的配置(哪些管脚用于连接codec芯片的控制引脚(CSB、SCLK、SDIN))
2、 一旦出了问题,怎么调试?
一个比较好的办法是,用OpenJTAG+OpenOCD结合Eclipse进行源码级的调试,而如果要调试NAND里的代码,可以用telnet到OpenOCD来进行汇编级的调试(缺点是操作比较繁琐,而且还要分析汇编代码)
四、参考资料
1、韦东山 《嵌入式Linux应用开发完全手册》
2、韦东山 《Eclipse,OpenOCD,OpenJTAGv3.1 开发教程v5.pdf》
3、 NandFlash K9F1208U0A/ K9F1208U0B的读取操作