当前位置:   article > 正文

TMS320F280049C 学习笔记9 CMD文件 程序从FLASH复制到RAM中运行_f2800 cmd

f2800 cmd


实现程序从FLASH复制到RAM中运行的方法(要求使用新编译器):
在函数声明前添加一行代码:

__attribute__((ramfunc))

举例:

__attribute__((ramfunc))  // 需要添加的代码
__interrupt void adcA1ISR(void) // 想要复制到ram的程序,以ADC中断程序为例
{
}
  • 1
  • 2
  • 3
  • 4

本文后面的内容其实没必要看…………

动机

一般建议将实时性要求比较高的代码,比如中断程序,和FLASH初始化相关的代码,放在RAM上运行。[1]

在F2837xD/37xS/07x系列芯片里,它们使用的Flash是最新的65nm工艺(相比之前的是180nm),其Flash运算速度和执行效率已经大幅提高,等待周期也可以减少,因此会非常接近RAM上的速度,根据不同的代码,你可以参考下面的相关数据(请注意,Flash wait states是根据工艺强制要求的,比如F28335运行150MHz主频时,必须至少要5个,而F2837x则只需要2个 ):
在这里插入图片描述
以下表格出自:
在这里插入图片描述

CMD文件结构与语法

建议首先阅读[2],这是一份写于2009年的文档,适合入门。
进一步的学习资料可以参考[3],本小节根据[3]的内容并结合280049C的实际进行总结。
280049C的片上存储器包含256KB (128KW)的ROM和100KB(50KW)的RAM。

MEMORY和SECTIONS指令

MEMORY和SECTIONS指令是CMD文件中的核心指令。
MEMORY指令用来指示存储空间,SECTIONS指令用来分配“段”到存储空间,即指定“段”的实际硬件空间。
本节的代码示例来自28004x_generic_ram_lnk.cmd

MEMORY指令

作用:指示存储空间

MEMORY
{
        PAGE 0 :
            name 0[(attr)]:orgin=constant , length=constant;
        PAGE n :
            name n[(attr)]:orgin=constant , length=constant;
}
MEMOR
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • PAGE n表示把可用的资源空间再划分成几个大块,最多允许分256块,从PAGE 0到 PAGE 255。通常习惯于把PAGE 0作为程序空间,把 PAGE 1作为数据空间。
  • name n为存储空间名;
  • orgin用来标明该段的起始地址;
  • length用来指示该段的长度。
MEMORY
{
PAGE 0 :
   /* BEGIN is used for the "boot to SARAM" bootloader mode   */

   BEGIN           	: origin = 0x000000, length = 0x000002
   RAMM0           	: origin = 0x0000F3, length = 0x00030D

   RAMLS0          	: origin = 0x008000, length = 0x000800
   RAMLS1          	: origin = 0x008800, length = 0x000800
   RAMLS2      		: origin = 0x009000, length = 0x000800
   RAMLS3      		: origin = 0x009800, length = 0x000800
   RAMLS4      		: origin = 0x00A000, length = 0x000800
   RESET           	: origin = 0x3FFFC0, length = 0x000002

 /* Flash sectors: you can use FLASH for program memory when the RAM is filled up*/
   /* BANK 0 */
   FLASH_BANK0_SEC0  : origin = 0x080000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC1  : origin = 0x081000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC2  : origin = 0x082000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC3  : origin = 0x083000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC4  : origin = 0x084000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC5  : origin = 0x085000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC6  : origin = 0x086000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC7  : origin = 0x087000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC8  : origin = 0x088000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC9  : origin = 0x089000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC10 : origin = 0x08A000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC11 : origin = 0x08B000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC12 : origin = 0x08C000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC13 : origin = 0x08D000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC14 : origin = 0x08E000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK0_SEC15 : origin = 0x08F000, length = 0x001000	/* on-chip Flash */

  /* BANK 1 */
   FLASH_BANK1_SEC0  : origin = 0x090000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC1  : origin = 0x091000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC2  : origin = 0x092000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC3  : origin = 0x093000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC4  : origin = 0x094000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC5  : origin = 0x095000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC6  : origin = 0x096000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC7  : origin = 0x097000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC8  : origin = 0x098000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC9  : origin = 0x099000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC10 : origin = 0x09A000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC11 : origin = 0x09B000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC12 : origin = 0x09C000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC13 : origin = 0x09D000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC14 : origin = 0x09E000, length = 0x001000	/* on-chip Flash */
   FLASH_BANK1_SEC15 : origin = 0x09F000, length = 0x001000	/* on-chip Flash */

PAGE 1 :

   BOOT_RSVD       : origin = 0x000002, length = 0x0000F1     /* Part of M0, BOOT rom will use this for stack */
   RAMM1           : origin = 0x000400, length = 0x0003F8     /* on-chip RAM block M1 */
//   RAMM1_RSVD      : origin = 0x0007F8, length = 0x000008     /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */

   RAMLS5      : origin = 0x00A800, length = 0x000800
   RAMLS6      : origin = 0x00B000, length = 0x000800
   RAMLS7      : origin = 0x00B800, length = 0x000800
   
   RAMGS0      : origin = 0x00C000, length = 0x002000
   RAMGS1      : origin = 0x00E000, length = 0x002000
   RAMGS2      : origin = 0x010000, length = 0x002000
   RAMGS3      : origin = 0x012000, length = 0x001FF8
//   RAMGS3_RSVD : origin = 0x013FF8, length = 0x000008     /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

SECTIONS指令

作用:分配段到存储空间,即指定段的实际硬件空间。
注意:SECTIONS字符是复数形式。

SECTIONS
{
        name 0 :> 存储空间名称 , PAGE = 页数;
        name n :> 存储空间名称 , PAGE = 页数;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • name n为段名;
  • “: >”为内存分配符,等效于load =,代表数段的存储位置,有时也会用到run关键字,代表段的运行位置;
  • ">>"表示多片空间串起来
  • “存储空间名称”为MEMORY中已经分配好的存储空间名称。
/*You can arrange the .text, .cinit, .const, .pinit, .switch and .econst to FLASH when RAM is filled up.*/
SECTIONS
{
   codestart        : > BEGIN,     PAGE = 0
   .TI.ramfunc      : > RAMM0,      PAGE = 0
   .text            : >> RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3 | RAMLS4,   PAGE = 0
   .cinit           : > RAMM0,     PAGE = 0
   .switch          : > RAMM0,     PAGE = 0
   .reset           : > RESET,     PAGE = 0, TYPE = DSECT /* not used, */

   .stack           : > RAMM1,     PAGE = 1

#if defined(__TI_EABI__)
   .bss             : > RAMLS5,     PAGE = 1
   .bss:output      : > RAMLS5,     PAGE = 1
   .init_array      : > RAMM0,      PAGE = 0
   .const           : > RAMLS5,     PAGE = 1
   .data            : > RAMLS5,     PAGE = 1
   .sysmem          : > RAMLS5,     PAGE = 1
   .bss:cio         : > RAMLS0,     PAGE = 0
#else
   .pinit           : > RAMM0,      PAGE = 0
   .ebss            : > RAMLS5,     PAGE = 1 
   .econst          : > RAMLS5,     PAGE = 1
   .esysmem         : > RAMLS5,     PAGE = 1
   .cio             : > RAMLS0,     PAGE = 0 
#endif

   ramgs0           : > RAMGS0,    PAGE = 1
   ramgs1           : > RAMGS1,    PAGE = 1  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

程序与数据段

程序中存在众多的段,这些段分为两种:已初始化段和未初始化段。
部分段存在64KB大小的限制,关于这点可以参考[4]。

已初始化段

  • .text C语言编译后生成的二进制指令代码段。我们编写的main主函数,子函数或子程序,中断服务程序,都会产生指令代码,都属于这个段;
  • .cinit 存放初始化的全局和静态变量;
  • .const 字符串常量和const定义的全局和静态变量;
  • .econst 字符串常量和far const定义的全局和静态变量;
  • .pinit 全局变量的构造函数(C++语言)程序列表,在新标准中有时用.init_array段表示;
  • .switch 存放switch语句产生的常数表格;
  • .vectors 中断向量段,也就是中断服务程序的入口地址段。

未初始化段

  • .bss 为全局变量和局部变量保留的空间,在程序上电时.cinit空间中的数据复制出来并存储到.bss空间中;
  • .ebss 为使用大寄存器模式时的全局变量和静态变量预留的空间,在程序上电时,cinit空间中的数据复制出来并存储在.ebss中;
  • .stack 堆栈空间,主要用于函数传递变量或为局部变量分配空间;
  • .sysmem 为动态存储分配保留的空间(malloc),如果有宏函数,此空间被占用;
  • .esysmen 为动态存储分配保留的空间(far malloc),如果有far函数,此空间会被占用。

其他指令

于2022年1月6日更新本小节,更全面的介绍可以参考TI官方的中文图书《TMS320C28X系列DSP指令和编程指南》

  • ALIGN 位对齐[13],常用于FFT。另外,TI推荐在第3代DSP中不再适用ALIGN(4),而是全部适用ALIGN(8) [14]

#pragma指令的使用

上一节讨论了CMD文件的结构,通常程序中的每一个变量和函数都会被编译器自动连接至指定的区域。但通过一些指令,也可以由用户自行指定某个函数或数据的存储位置。
实现方式参考文献[4],其中提到的手册为[5]。

  • 注意:
    不能在函数体内声明#pragma;
    必须在符号被定义和使用之前声明#pragma

程序从FLASH复制到RAM中运行

这个东西网上的教程大多讲的十分复杂,比较新的教程可以参考[6]。
但其实这个需求TI已经给出了解决方案[7],在传统教程中提到的包括段定义、延时函数修改等一系列内容,在新版的库函数都已经给出了定义,不再需要我们自己添加[8]。

方法

具体来说,只需要在函数声明前添加:

__attribute__((ramfunc))

举例:

__attribute__((ramfunc))  // 需要添加的代码
__interrupt void adcA1ISR(void) // 想要复制到ram的程序,以ADC中断程序为例
{
}
  • 1
  • 2
  • 3
  • 4

代码的效果很容易验证,只需要对比添加前后Debug文件夹下.map文件的内容即可。该文件描述了如何在ram和rom中分配代码中各个函数和变量的存储位置。

备份

TI的wiki页面上说将在今年底关闭网站,所以将[7]的内容截图备份如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

关于_BIOS.cmd 和 _nonBIOS.cmd文件

于2020年7月14日更新本小节。
在实际项目中偶然遇到编译器报如下警告:
#10247-D creating output section “AdcaRegsFile” without a SECTIONS specification

解决方案是根据芯片的不同,在工程中添加 F28xx_Headers_nonBIOS.cmd 即可[12]。
另外在[12]中有如下表述:

You can have two .cmd files in a project. The _BIOS or _nonBIOS cmd file defines the peripheral registers while the other .cmd file maps sections of memory and code.

The _BIOS cmd file is for DSP/BIOS and SYS/BIOS projects with an RTOS and does not have the PIE vector.
The _nonBIOS cmd file is for other projects and has the PIE vector table.

参考文献

  1. 28377D中代码在RAM和FLASH中执行时,效率差多远
  2. cmd文件原理——玄德
  3. CMD文件详解与DSP存储空间
  4. #pragma DATA_SECTION与#pragma CODE_SECTION的使用
  5. Programming TMS320x28xx and TMS320x28xxx Peripherals in CC++
  6. DSP28377S_程序从FLASH部分复制到RAM中运行详解
  7. Placing functions in RAM
  8. TMS320F28069: attribute((ramfunc)) this method does not require memcpy like older #pragma method nedded?
  9. Copying Compiler Sections From Flash to RAM on the TMS320F28xxx DSCs
  10. 把DSP TMS320F28XXX的程序段从flash复制到ram中运行
  11. C2000™ Key Technology Guide
  12. Compiler/TMS320F28075: [Warnings] #10247-D creating output section “xxxxx” without a SECTION specification
  13. 如何理解CMD文件中的ALIGN?
  14. TMS320F28388D: ALIGN(4) vs. ALIGN(8) in cmd files
  15. TMS320F280049C: 自问自答: 怎么在cmd文件中将.lib库中的部分文件链接至ram运行区?
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/697497
推荐阅读
相关标签
  

闽ICP备14008679号