DSP中内部Flash的应用研究
- 格式:doc
- 大小:56.00 KB
- 文档页数:12
1 前言
TMS320F28xx DSP片内有128 K×16 bit字的Flash、两块4 K x16bit字的单周期访问RAM(SARAM)LO和L1、一块8 Kxl6 bit字的单周期访问RAM(SARAM)HO、两块1 Kxl6 bit字的单周期访问RAM(SARAM)M0和M1。由于存储器种类多、容量大,所以从系统的高度来配置各个存储器必须有合适的方法,而这些方法一般都与片内Flash有关。另外,TMS320F28xx DSP片内有看门狗定时器模块(WDT)、引导ROM(ROM bootloader)模块、代码安全模块(CSM),要合理地使用这些模块为整个系统服务,必定也要用到Flash。
由此可以看出,Flash的地位和作用比较显著.所以本文就Flash的几种用法作了研究。
2 从Flash拷贝段到RAM
2.1拷贝中断向量
在TMS320F28xx器件中,外设扩展中断(PIE)模块管理中断请求。上电时,所有中断向量必须位于非易失性存储器(如Flash)中,但是要把中断向量拷贝到PIEVECT RAM中,这是用户代码中器件初始化程序的一部分。PIEVECT RAM是一个特定的RAM块,它在当前TMS320F28xx器件中是一个256×16的块.在数据空间中的起始地址为Ox000D00。
把中断向量连接到Flash,然后在运行时把中断向量拷贝到PIEVECT RAM中,有许多方法可以实现。一个方法是创建包含函数指针的常量C结构体,该结构体包括128个32-bit向量。如果使用DSP281x或者 DSP280x外设的结构体.这个结构体叫做PieVectTableInit,它已经在DSP281x_PieVect.c或者 DSP280x_PieVect.c创建(参看TI提供的例程)。因为这个结构体使用const类型关键词,所以它将会被编译器放置在.econst段中。运行时只需要把这个结构体拷贝到PIEVECT RAM中。C编译器运行时支持库包含名为memcpy的存储器拷贝函数,该函数可以被用来完成拷贝任务,其用法如下所示:
#include
void main()
{
//Initialize the pie_ram
PieCtrlRegs.PIECTRL.bit.ENPIE=0;//disable the PIE
asm(" EALLOW"); //enable the eallow protected register access
memcpy((void*)0x00D00,&ieVectTableInit,256);
asm("EDIS"); //disable the eallow protected register access
}
以上这个例子为PIE RAM起始地址使用的硬编码地址(hard coded address),明确指定为0x000D00。但是硬编码地址并不是较好的编程方式,用户可以使用DATA_SECTION指令创建一个非初始化的假变量(dummy variable),并把这个变量连接到PIE RAM.然后用这个假变量的名字来代替硬编码地址。例如,当使用DSP281x或者DSP280x外设结构体时,创建一个名为PieVectTable的非初始化结构体,并把该结构体连接到PIEVECT RAM。前面例子中的memcpy()函数可以被替换为:
memcpy(&ieVectTable,&ieVectTableInit,256);
注意拷贝长度是256个16-bit字.对应为128个32-bit字。
2.2初始化Flash控制寄存器
Flash控制寄存器FOPT、FPWR、:FSTDBY-WAIT、FACTIVEWAIT、 FBANKWAIT、FOTPWAIT的初始化代码不能从Flash存储器当中运行.否则就会有不可预料的结果出现。所以,Flash控制寄存器的初始化函数在运行时必须从Flash(它的装载地址)拷贝到RAM(它的运行地址)。
Flash控制寄存器由Code Security Module(CSM)保护。如果CSM被保护起来了,那么必须从被保护的RAM(例如:L0或者L1 SARAM)运行Flash控制寄存器的初始化代码,否则Flash控制寄存器的初始化代码无法访问Flash控制寄存器。要注意的是,当器件复位的时候 CSM一般都是被保护起来的,虽然使用假密码0xFFFF时ROM BOOTLOAD-ER会把它解锁。
C编译器的 CODE_SECTION指令可以用来为Flash控制寄存器的初始化函数创建独立的可连接段。例如:假定Flash控制寄存器的配置在C函数 InitFlash()中实现,并且想把这个函数放置在名为secureRamFuncs的可连接段当中。下列的C代码例程显示了 CODE_SECTION命令在Flash存储器配置中的正确用法:
#pragma CODE_SECTION(InitFlash,””secureRamFuncs)
void InitFlash(void)
{
asm("EALLOW");//Enable EALLOW protected register asscess
FlashRegs.FPWR.bit.PWR=3;//Flash set to active mode
FlashRegs.FSTATUS.bit.V3STAT=1;//Clear the 3VSTAT bit
FlashRegs.FSTDBYWAIT.bit.STDYYWAIT=0x01FF;//Sleep to standy cycles
FlashRegs.FACTIVEWAIT.bit.ACITIVEWAIT=0x01FF;//Standby to active cycles
FlashRegs.FBANKWAIT.bit.RANDWAIT=3;//F280x Random access wait states
FlashRegs.FBANKWAIT.bit.PAGEWAIT=3;//F280x Paged access wait states
FlashRegs.FOTPWAIT.bit.OTPWAIT=5;//F280x OTP wait states
FlashRegs.FOTP.bit.ENPIPE=1;//Enable the Flash pipeline
asm("EDIS");//Disable EALLOW protected register access
asm("RTP #6 || NOP");//end of InitFlash()
secureRamFuncs段可以使用用户连接命令文件(.cmd)进行连接。这个段需要独立的装载和运行地址。另外,还想让连接器生成一些全局符号,这些全局符号可以用来决定装载地址、运行地址、段长度。在实现把这个段从装载地址拷贝到它的运行地址时需要这些信息。用户连接命令文件如下所示:
**User's linker command file
SETIONS
{
secureRamFuncsOAD=FLASH,PAGE=0
RUN=SECURE_RAM,PAGE=0
RUN_START(_secureRamFuncs_runstart),
LOAD_START(_secureRamFuncs_loadstart),
LOAD_END(_secureRamFuncs_loadend)
}
在这个例子中,假定存储器Flash和SECURE_RAM都已经在用户连接命令文件中的MEMORY段中定义。这些存储器的PAGE标识符要与它们的存储器定义相匹配。在上面的例程中假定两个存储空间都已经在PAGE 0(程序存储空间)中声明过了。RUN_START、LOAD_START、LOAD_END指令将生成全局符号,这些全局符号有特定的名称,对应着相应的地址。最后,这个段必须在运行时从Flash拷贝到RAM,可以用到编译器运行支持库里面的函数memcpy()。
**User's C_source file
#include
extern unsigned int secureRamFuncs_loadstart;
extern unsigned int secureRamFuncs_loadend;
extern unsigned int secureRamFuncs_runstart;
void main(void)
{
memcpy(&secureRamFuncs_runstart&secureRamFuncs_lo
adstart&secureRamFuncs_loadend-&secureRamFuncs_loadstart);
InitFlash();
}
2.3性能最优化
常数是那些用C语言的const类型关键词声明的数据结构。编译器把所有的常数放置在.econst段中(假定为大存储模式)。当前TMS320F28xx 器件上的特殊管道(special pipelining)提高Flash上运行代码的性能时.每次访问位于片上Flash中的数据常数会占用许多周期。特别是在150 MHz TMS320F281x DSP上Flash等待状态要达到5个周期.100 MHz
TMS320F280x DSP达到3个周期。所以,访问片上RAM中的常数与常数表则成为沉重的负担。然而,分立式嵌入式系统要求所有的初始化数据(如常数)最初都是位于非易失性存储器中,所以,必须为想访问的RAM中的常数建立独立的装载和运行地址.在运行时把这些常数从片上Flash中拷贝到RAM中。这里介绍两种不同的实现方法。
方法一:在RAM中运行所有的常数阵列。
这种方法是为整个.econst段指定独立的装载和运行地址。其好处是容易使用,而坏处是RAM的使用量非常大(可能只有少量常数需要快速访问,但是用这种方法所有的常数都位于RAM)。