F28335BOOTROM引导模式和程序.docx
《F28335BOOTROM引导模式和程序.docx》由会员分享,可在线阅读,更多相关《F28335BOOTROM引导模式和程序.docx(17页珍藏版)》请在冰豆网上搜索。
![F28335BOOTROM引导模式和程序.docx](https://file1.bdocx.com/fileroot1/2023-1/3/eb6da36c-16a3-4117-936c-c31e2d6bced4/eb6da36c-16a3-4117-936c-c31e2d6bced41.gif)
F28335BOOTROM引导模式和程序
28335使用串口烧写程序
串口烧写是一种相对较方便的烧写方式,相对于仿真器或是CAN烧写,相对于仿真器或是USB转CAN的设备,串口是一种非常廉价的烧写方式,而且也不需要安装专业的集成开发环境CCS等,但是不能实现在线调试,因此也只适用于程序基本不用再调整或大批量的场合。
F28335的存储器映射图如下:
BOOTROM是一块8KX16的只读存储器,位于地址空间0x3FE000~0x3FFFFF,片内BOOTROM在出厂时固化了引导加载程序以及定点和浮点数据表,片上BOOTROM的存储映射如下图所示:
1.内BOOTROM数学表:
在BOOTROM中保留了4KX16位空间,用以存放浮点和IQ数据公式表,这些数据公式表有助于改善性能和节省SARAM空间。
2.CPU向量表:
CPU向量表位于ROM存储器0x3FE000~0x3FFFFF段内,如下图所示。
复位后,当VMAP=1,ENPIE=0(PIE向量表禁止)时,该向量表激活。
在内部BOOTROM引导区中能够调用的唯一向量就是位于0x3FFFC0的复位向量。
复位向量在出厂时被烧录为直接指向存储在BOOTROM空间中的InitBoot函数,该函数用于开启引导过程。
然后通过通用I/O引脚上的检验判断,决定具体引导模式。
引导模式与控制引脚之间的关系如下图所示:
Bootloader特性:
Bootloader是位于片上引导ROM中的在复位后执行的程序,用于在上电复位后,将程序代码从外部源转移到内部存储器。
这允许代码暂时存储在掉电不丢失数据的外部存储器内,然后被转移到高速存储器中执行。
引导ROM中的复位向量将程序执行重定向至InitBoot函数。
执行器件初始化之后,bootloader将检查GPIO引脚的状态以确定您需要执行哪种引导模式。
这些选项包括:
跳转至闪存、跳转至SARAM、跳转至OTP或调用其中一个片上引导加载例程。
完成选择进程后,如果已完成所需的引导加载,处理器将在所选引导模式确定的应用起点继续执行。
如果调用了bootloader,则由外设加载的输入流确定此应用起点地址。
然而,如果选择直接引导至闪存、OTP或SARAM,这些存储器块中每一个存储器块的应用起点均已预定义。
上图显示了引导进程的概述。
以下引导模式不掉用bootloader,他们会跳转至存储器中的预定义位置:
1.跳转至闪存中的分支指令:
在此模式下,引导ROM软件将针对28x操作配置器件,然后直接分支至闪存的0x33FFF6位置。
此位置刚好是128位代码安全模块(CSM)密码位置之前。
您需要预先在0x33FFF6位置处编写分支指令,以将代码执行重定向至定制的boot-loader或应用代码。
在仅有RAM的器件上,“引导至闪存”将跳转到保留存储器,因此不应当使用此选项。
2.跳转至M0SARAM
在此模式下,BOOT ROM将针对28x操作配置器件,然后直接分支至0x000000,即M0SARAM存储器块中的第一个地址。
3.跳转至OTP存储器
在此模式下直接分支至0x380400,即OTP存储器块中的第一个地址
以下引导模式将调用一个用于将数据流从外设加载至存储器的引导加载例程:
SCI-A(注意此处的SCI-A对应的是GPIO28和GPIO29)
SPI-A
I2C-A
eCAN-A
GPIO0-GPIO15并行引导。
如果使用SCI或者其他引导的话,首先需要将启动模式选择相关的引脚配置成对应的模式,然后器件退出复位状态之后,首先从复位向量处开始运行,即从0x3FFFC0处,该地址存放着BOOTROM中的第一个汇编初始引导程序InitBoot程序的入口地址,程序跳转至0x3FFC00执行InitBoot程序。
该程序主要初始化F28335器件工作的目标模式。
然后读取安全保护模块的密码,如果CSM密码被擦除(全部等于0xFFFF)则自动解锁,否则CSM仍被锁定。
对CSM密码读取完成后,初始化例程调用模式选择功能函数(SelectBoot),该函数根据GPIO的状态确定处理器引导的方式。
一旦完成SelectMode将会把入口地址返回给初始化引导。
然后初始化引导函数调用回复CPU寄存器的退出例程(ExitBoot)并退出到由引导模式确定的程序入口地址。
因此我们在使用SCI升级程序时可以分两个步骤,第一个步骤是我们需要一个Bootloader程序,第二个就是我们要升级的程序,BootLoader程序就是我们在选择引导SCI模式之后,SelectBoot之后通过串口加载的第一个程序,待ExitBoot之后会跳转到我们这个bootloader指定的地址开始执行(即将控制权交给我们的这个BootLoader程序),因此我们的BootLoader程序就肩负着串口接收我们的应用程序并将应用程序烧写到FLASH的任务。
第二个就是我们的应用程序,这个跟平常的应用程序一样,没有任何区别。
1.BootLoader程序
由上面的介绍明显知道我们的Bootloader程序是运行在RAM里面的,所以使用CCS在编写该程序的时候使用的是RAM_Link的CMD,而且该程序除了串口的处理还有包括FLASH操作的API函数,而这些函数必须要运行在RAM里面,而且在进行FLASH操作的时候要将中断全部都关掉,FLASH的API有相关的例程是烧进FLASH的还要拷贝到RAM,我们这里正好还免去了拷贝的过程,因为我们整个程序都是运行在RAM中的。
Bootloader数据流的结构:
上图就是BootLoader数据流的结构,数据流的第一个16位字称为键值,该键值用来指向Bootloader指示流入的数据流的宽度:
8位或16位(在这里SCI就是8位),对于8位数据流,键值为0x08AA,如果bootloader收到一个无效的键值,加载则中止。
则直接跳转到FLASH开始执行。
接下来的8个字(2-9)用于初始化寄存器直,如果bootloader不使用这些值,则将这些值留作将来使用。
第10个和第11个字组成了22位应用起点地址,此地址用于在完成引导加载后初始化PC,也就是我们程序的起点。
第12个字表示传输的第一个数据块的大小。
对于8位和16位数据流格式,该数据块的大小均定义为块中的16位字个数,例如,要从8位数据流中传输一个包含20个8位数据值的数据块,该块大小将为0x000A,表示有10个16位字。
第13和14个字表示程序的目的地址,后面跟的就是程序的字,直到遇到数据块长度为0的则传输结束。
上图为BOOTLoader传输流程,如果不相等会自动退出引导程序,系统会从内部FLASH存储器执行程序。
这里需要讲一下,我们的Bootloader数据流如何得到,我们正常的使用CCS编译链接得到了xx.out文件,然后使用hex2000.exe–boot–sci8--map=xx.map-oxx.hex-ixx.out(详细解释可参考TMS320C28x-Assembly-Language-Tools-User's-Guide-v6.1.pdf),当然你可以将这些命令参数写成脚本xx.cmd,然后直接执行hex2000.exexx.cmd即可。
这就会生成Intel格式的hex文件,我们需要自己对这个hex文件解析,对于生成的Hex文件都是以冒号开始,后面一个字节是数据长度,2-3字节是地址,第4字节是数据类型(00表示数据记录,01表示文件结束记录,02表示扩展段地址记录,04表示扩展线性地址记录)
首先需要一个将两个字符转换为一个字节量函数:
VoidCharToByte(char*pChar,BYTE*pByte)
{
charh,l;
h=pChar[0];
l=pChar[1];
if(l>=’0’&&l<=’9’)
l=l-‘0’;
elseif(l>=’a’&&l<=’f’)
l=l-‘a’+0xa;
elseif(l>=’A’&&l<=’F’)
l=l-‘A’+0xa;
if(h>=’0’&&h<=’9’)
h=h-‘0’;
elseif(h>=’a’&&h<=’f’)
h=h-‘a’+0xa;
elseif(h>=’A’&&h<=’F’)
h=h-‘A’+0xa;
*pByte=(BYTE)h*16+1;
}
解析的关键代码:
If(fopen_s(&myFile,filename,”r”)!
=0)
{
Printf(“打开文件%s失败!
”,filename);
}
while(!
feof(myFile))
{
++len;
fgetc(myFile);
}//将文件长度计算出来用于申请存储数据的缓冲区
rewind(myFile);
outBuf=(BYTE*)malloc(len/2);
memset(outBuf,0xff,len/2);
while(!
feof(myFile))
{
if(fgetc(myFile)==‘:
’)//:
号表示一行的开始
{
//一行的头两个字符为该行包含的数据长度
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&datalen);
//一行的第3、4个字符为数据存储起始地址的高位
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&addresshigh);
//一行的5、6个字符为数据存储起始地址的低位
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&addresslow);
//一行的7、8个字符为数据类型
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&dataType);
if(dataType==0x00)//表示普通数据
{
for(i=0;i{
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&byteData);
outBuf[adressHigh*256+adresslow+i]=byteData;
}
}
if(dataType==0x01)
{
printf(“文件结束记录!
”);
}
if(dataType==0x02)
{
printf(“不支持扩展段地址记录!
”);
return;
}
if(dataType==0x04)//本行包含扩展线性地址记录
{
//表示的是extended地址高位和低位
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&addresslinearhigh);
data[0]=fgetc(myFile);
data[1]=fgetc(myFile);
CharToByte(data,&addresslinearlow);
}
}
}
fclose(myFile);
这个只是对hex文件进行了解析,然后还需要通过串口将数据发送出去,在发送数据之前需要先发送“A”字符给DSP,等待DSP回复“A”之后,表明DSP波特率已经锁定,这时候可以将转换的数据发送给DSP,DSP在接收的时候会将接收到的数据保持原样返回给上位机,反观我们的核心板,我们的核心板上的SCI引出的不是GPIO28和GPIO29,再者就是控制发送的引脚在上电时的电平不对导致烧写不成功。
等这个程序传输完了之后,会跳转到我们这个程序指定的入口地址开始执行,此时可以进行下一步的操作,我们需要将我们的应用程序(即xx.out文件也转换成xx.hex),转换的cmd命令如:
hex2000.exe–romwidth16
-memwidth16-i-oxx.hexxx.out
转换之后的hex文件也需要按照上述转换的方式转换之后才能发送出去,因为RAM空间有限,而且一个应用程序通常都比较大,因此上位机可以一行一行的解析然后发送给DSP,DSP端接收之后根据指定的地址还有数据长度写入对应的FLASH即可。
在完成FLASH操作之后,就可以断电拨回FLASH启动正常启动看是不是正常运行了。
上述的是DSP启动过程分析,还提供了如果需要自己制作的思路及方法,上述方法仅仅做了验证,非常不完善;但是我们可以找到第三方的烧写软件,相比较而言这样的烧写软件相对来说要可靠的多,下面大致介绍一下使用C2Prog这个软件来烧写的过程:
有的CCS软件在生成的配置选项中可以找到生成IntelHEX文件的选项,但是我装的版本在选择了IntelHEX文件之后生成的HEX文件在用于烧写时提示格式不正确,在CCS的安装目录下,tools/compiler/c2000_6.2.5/bin下有需要使用的hex2000.exe用来生成HEX文件。
将这个exe拷贝到要用.out文件生成hex文件的目录下,通过命令行执行如下命令:
即可生成hex文件。
在按照上图所示根据自己实际情况配置完成后,我们要将我们板子DSP的启动方式更改为SCI-A启动方式,然后才能进行烧写。
烧写成功如上图所示。
在烧写完成之后,将拨码开关重新切换至FLASH启动方式,重新启动DSP,这时可以观察程序的运行情况。