在介绍完AIS文件制作后,为确保DSP能正常启动,还需要进行调试。在这个过程中,有很多细节需要注意,笔者在调试过程中层遇到了很多问题,下面介绍笔者在调试AIS启动过程中的调试方法,读者可以参考。
要确保DSP能从NANDFLASH启动,并执行AIS脚本,首先要保证硬件上的连接正确,这里需要设置DSP的启动模式为NANDFLASH启动,从EMIFA的CS2启动,那么如何查看DSP是从这里启动的呢,在DSP断电重启后,在CCS中连接仿真器,不执行程序直接可以查看DSP内部寄存器的值,这里需要查看BOOTCFG,确保在上电之后是NANDFLASH启动模式,智力BOOTCFG字段MODE=0x0111,另外,如果AIS脚本执行过程中遇到了错误,比如没有找到魔术字,指令使用不正确等,可以查看BOOTCMPLT寄存器的ERR字段,只有当ERR=0时表示AIS启动正常,如果不是可以参照下表进行错误定位。
Table 1. Debugging Boot Failures
Value | Name | Description |
0x1 | ERR_UNKNOWN_COMMAND | An invalid AIS command was received |
0x2 | ERR_BAD_MAGIC_NUMBER | The AIS magic number was not detected in UART boot mode |
0x3 | ERR_TRANSMIT_SYNC | Not used |
0x4 | ERR_BAD_CRC | Getting PCI Autoinit data failed, or exceeded maximum CRC failure in AIS parsing |
0x5 | ERR_INVALID_ADDRESS_SIZE | Invalid specified address width in first word of SPI master boot |
0x6 | ERR_UNSUPPORTED_BOOTMODE | The various boot pin configurations are invalid |
0x7 | ERR_TIMEOUT_WAITING_FOR_HOST | Timeout occurred in sending or receiving data (UART, PCI,UHPI modes) |
0x8 | ERR_TIMEOUT_I2C_BUS_BUSY | Timeout waiting for bus becoming free in I2C master boot |
0x9 | ERR_TIMEOUT_MCBSP_SPI_RECEIVE | Receive timeout in SPI master boot mode |
接下来调试解析COFF文件过程,首先查看文件头,可选头两个结构体数据。按二进制读取方式读取到.out文件的头28字节如下:

可以看到,fileSecNum=23,说明共有23个段落,但一般.cmd文件中没有这么段,说明处理定义的字段,还有些其他用途的段落页加入到文件中,在下载前需要剔除掉。fileByte=28,这说明该文件有可选文件头,fileTargetID=0x0099,前面提到过,如果不确定文件头解析对不对,可以参考这个值是不是0x0099,因为工程时使用C6000的芯片,那么这个值必然是0x0099如果不是肯定就是解析出错了。其他的字段基本不会用到。
解析可选文件头:

着重查看optionExecut=145056,大概计算一下:145056/1024=141Kb,这就是代码的大小,在下载过程中需要使用至少这么大的FLASH空间,另外optionEntry=0x00023060有点不想程序入口地址,原来这是在定义结构体是定义的是int型数据,在解析时按照4字节整型读取,但实际上这个值是由两个16位地址组成,每个16位数据按小端模式存储,这样一来无论按照小端还是大端都无法解析正确,所以正能按照前面的教程中提到的方法进行解析。
剩下的就是解析所有的段落了,首先需要各个段落头,然后根据段落头读取文件中的原始数据,先不急于整个文件的读取,首先一个段落头的查看,下面选取了几个段落:
第一段:

第二段:

第三段:

第四段:

第五段

注意到secCharacter在CCS上显示的是字符串的地址,要查看字符串的内容需要另外定义一个表达是,这里定义为
(char*)Sec_header->secCharacter
意思就是显示字符串地址的内容,可以看到,运行完23次循环后,每个段落都解析正确(段落名都正确了还能有错吗?),在运行过程中建议读者在细心的查看一下secFlag的值,最好转化成二进制,将所有的值与段名都列举出来你,最后你将会发现,需要下载的段落第6位和第7位都为1,这就是为什么程序中有一句判断将secFlag于0x60进行按位与操作。
下面分析一下段落内容的提取,首先笔者将前几个段落的重要字段列举到一个表格中:
段序号
|
段中的主要字段
|
字段值
|
说明
|
1
|
段名
|
||
物理地址
|
0
|
||
大小
|
36
|
||
段数据指针
|
1154
|
=50+23*48
|
|
段标识
|
0x10
|
||
2
|
段名
|
.text
|
这个就是代码要存储的
|
物理地址
|
32
|
||
大小
|
123168
|
||
段数据指针
|
1190
|
=1154+36
|
|
段标识
|
0x520
|
||
3
|
段名
|
.const
|
|
物理地址
|
152424
|
||
大小
|
2396
|
||
段数据指针
|
124358
|
=1190+123168
|
|
段标识
|
0x340
|
||
4
|
段名
|
.data
|
已初始化数据段
|
物理地址
|
8
|
||
大小
|
0
|
||
段数据指针
|
0
|
||
段标识
|
0x380
|
||
5
|
段名
|
.bss
|
未初始化数据段
|
物理地址
|
157392
|
||
大小
|
332
|
||
段数据指针
|
0
|
||
段标识
|
0x380
|
||
6
|
段名
|
.cinit
|
|
物理地址
|
140016
|
||
大小
|
12404
|
||
段数据指针
|
126754
|
=124358+2396
|
|
段标识
|
0x340
|
||
7
|
段名
|
.pinit
|
|
物理地址
|
0
|
||
大小
|
0
|
||
段数据指针
|
139158
|
||
段标识
|
0x210
|
|
注意总结,后面的段落的物理地址,段数据指针,段名之间的关系,下面给出几个计算公式:
段落数据指针1=sizeof(FILE_HEADER)+sizeof(OPTIONAL_FILE_HEADER)+
fileHeader->secNum*sizeof(SECTION_HEADER );
段落数据指针2=段落数据指针1+secHeader->secPhyAddr;
依次递推可以得到所有的数据。
那么在需要下载那些段落呢,主要包括以下几个段落:
.text .const .data .cinit .switch .tables .vectors 用户自定义字段
到这一步如果基本上没什么问题记下来就可以解析全部的.out文件到CCS了,在解析之前,我们来看看DSP程序在内存中是什么样的,debug连接DSP电路板,读取.text代码段处的地址,查看内存地址为.text定义的地址,笔者定义的是0x80400000,得到的数据为:

然后通过解析AIS,查看AIS的.text处的内存内容:

在第一行第六个数据开始是.text解析的AIS,在查看内存时,需要根据.text段落在.out文件中的位置来计算保存为AIS后所处的内存起始地址,可以看到,上下数据完全一致,依照此方法可以查看其它各段的情况,。
当AIS脚本制作完成,就可以将AIS文件直接烧写进NANDFLASH了:
readaddr=0; //writeblock=1; writepage=0; while (readaddr < AISsize) { errors += EVM6424_NANDFLASH_writePage( writeblock,writepage, ( Uint32 )(AISbuffer + readaddr) ); readaddr += NAND_PAGESIZE; writepage ++; if (writepage >= NAND_PAGES_PER_BLOCK) { writepage=0; writeblock++; } }
还是要强调一点,根据TI的手册,AIS文件必须放在第一块以后,至于为什么就不得而知了,照着做就对了。
最后在魔术字后面填写对应的块大小和搜索起始位置即可:
((int *)AISbuffer)[1] = (AISsize/NAND_PAGESIZE+1); ((int *)AISbuffer)[2] = writeblock; ((int *)AISbuffer)[3] = 0;
好了,可以重启上电了,当出现程序无法boot后,请读者再详细看一遍TI的手册或者本教程。
参考文献:
1. COFF文件分析提取器