4.1.存储器

4.1.1.从闪存执行

TMS320F28xxx 系列专为在嵌入式控制器应用中独立运行而设计。片上闪存通常无需外部非易失性存储器和用于引导加载的主机处理器。有关如何从内部闪存运行应用程序的详细信息,请参阅应用手册从 TMS320F28xxx DSP 上的内部闪存存储器中运行应用程序

从 RAM 执行代码比从闪存执行代码要快。但是,C2000 MCU 在从闪存执行时支持代码预取和数据缓存,从而最大限度地减少开销。有关这些功能的详细信息,请参阅器件技术参考手册 (TRM) 中的“闪存和 OTP 存储器”一节。

注释

代码预取和数据缓存在上电时都会被禁用。应用软件必须启用代码预取并适当地配置等待状态。它还需要启用数据缓存。有关详细信息,请参阅 C2000Ware 中的 InitFlash() 函数。例如,F28004x 的 InitFlash()<C2000Wareinstalldirectory>/device_support/f28004x/common/source/f28004x_sysctrl.c 中定义。

表 4.1 列出了在闪存和 RAM 上执行列表 4.1 中循环的周期数。使用的编译器选项:-O3--opt_for_speed=5--abi=eabi。使用 --ramfunc=on 选项和相应的链接器命令文件从 RAM 执行代码。

表 4.1 比较闪存与 RAM 的代码执行周期数
说明 F28004x 上的周期数
未启用代码预取的闪存 72006
启用代码预取的闪存 59996
RAM 54002
执行循环的周期数(计算值) 54000
列表 4.1 用于比较闪存与 RAM 的代码执行的循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
inti;// RPT+4 NOPs BANZ iterations// Total cycles = (5 * 10 + 4 ) * 1000 = 54000 cyclesfor(i=0;i<1000;i++){asm(" RPT #3 || NOP;");// 5 cycles - RPT + 4 NOPsasm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");asm(" RPT #3 || NOP;");}

4.1.2.从 RAM 执行

4.1.2.1.代码

表 4.1 中的数据可以看出,将时间关键代码从闪存中的加载地址复制到 RAM 中执行是有益的。

ramfunc 属性是一个 TI 编译器特性,它允许代码轻松指定将在 RAM 中放置和执行的函数。该属性应用于具有 GCC 属性语法的函数,如下所示:

__attribute__((ramfunc))voidf(void){...}

--ramfunc=on 选项相当于在使用该选项编译的源文件中指定所有函数的属性,无需修改源代码。

注释

为 RAM 函数生成快速分支指令 (SBF/BF)。这些指令利用 C28x 内核上的双预取队列,将 taken 分支的周期数从 7 个减少到 4 个。

ramfunc 属性和选项在 C2000 编译器版本 15.6 及更高版本中可用。对于不支持此功能的旧编译器,CODE_SECTION pragma 可以与链接器命令文件修改结合使用。

#pragma CODE_SECTION(f, ".TI.ramfunc")voidf(void){...}

链接器命令文件设置为创建与 .TI.ramfunc 段的加载和运行地址相对应的符号。

列表 4.2 .TI.ramfunc 的链接器命令代码片段
.TI.ramfunc: LOAD=FLASH_BANK0_SEC1,RUN=RAMLS0to7,LOAD_START(RamfuncsLoadStart),LOAD_SIZE(RamfuncsLoadSize),LOAD_END(RamfuncsLoadEnd),RUN_START(RamfuncsRunStart),RUN_SIZE(RamfuncsRunSize),RUN_END(RamfuncsRunEnd),ALIGN(4)

应用程序中的代码使用 memcpy.TI.ramfunc 段从闪存中的链接地址复制到 RAM 中的运行地址。

列表 4.3 将 .TI.ramfunc 从闪存复制到 RAM
memcpy(&RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize);

4.1.2.2.数据

常量数组 - 如果访问常量数组时时间紧迫,则考虑将数组从闪存中的加载地址复制到 RAM 地址以缩短访问时间。

4.1.3.其他注意事项

  • 如果代码访问同一物理存储器中的数据,则性能会因资源冲突而下降。将代码及其访问的数据放在单独的块中以提高性能。
  • 等待状态会降低性能。大多数 SARAM 在 28x MCU 上是零等待。务必查看数据手册以查找每个物理块的等待状态及其是否适用于程序或数据访问。
  • 如果代码大量使用两个数据缓冲区,则将每个缓冲区放在不同的 RAM 块中可能有助于提高性能。这是为了减少在同一周期内对不同缓冲区的写入和读取所导致的流水线停顿。有关示例,请参阅包含两个存储器操作数的指令的数据分配