文章来自:http://www.61ic.com/Article/C2000/Delfino/201303/47552.html

翻译自TI应用手册SPRAAU8

很详细,对编写CMD文件很有帮助!

摘要

这个应用报告和相关的代码提供了一种把编译后的程序段从TMS320F28xxx的flash复制到ram的功能,这样可以提高代码的运行速度。这个解决方案在直接启动之后,进入c_int00 ——C语言代码运行之前实现此功能。

本应用报告中所讨论的项目内容和源代码可以从以下网址下载:http://www-s.ti.com/sc/techlit/spraau8.zip

1.引言:

在许多应用中,代码的执行速度是至关重要的。例如在医疗,监控,电机控制等等一些对时间有严格要求的终端设备。许多应用使用TMS320F28xxx DSCs是因为它的内置flash储存器。内置flash是TMS320F28xxx的一个优势,因为它使得设计者不需要外接flash来储存代码。使用内部flash缺点是访问Flash需要等待状态,这使得程序的运行变慢。在大多数应用中,这不是一个问题。其他一些应用中可能会为了获得最高的运行速度要求无等待状态。内部RAM存储器具有零等待状态,它是易失性存储器。所以,引导的初始化代码段不可以存储在此存储器中。

现在提供的解决方案,使得设计者能够在运行时把被编译器初始化的代码段从flash复制到ram里,获得最大的运行速度。这使代码执行从多达15个等待状态的提升到0等待状态。另一种解决方案是只将某些函数从Flash复制到RAM。详见:《Running an Application from Internal Flash Memory on the TMS320F28xx DSP》
(SPRA958)。这种方法应该使用在大多数使用C2000™ DSC的应用上,其他要求严格的时序和连续的零等待状态的应用程序应采用这里提出的解决方案。

编写汇编程序来完成代码从Flash到RAM的复制。该汇编代码在复位向量后调用c_int00之前执行。这保证了在c_int00调用mian()之前完成复制。

有一些工程比较小,可以把所有初始化了的段都复制到ram。然而,其他一些工程的初始化了的段比所有的内部ram还要大。这些工程可能不可以把所有的初始化了的段都复制到ram,但是用这种方法复制其中一部分段。

2.编译的代码段:

编译器生成的包含代码和数据的多个部分,称为段。这下段被分为两个不同的组:初始化了的和没被初始化的,初始化的部分是由所有的代码,常量和初始化表组成的。下表列出了由编译器产生的初始化段。

初始化段
段名 内容 限制
.cinit 显式初始化的全局变量和静态变量表 代码
.const 显式初始化的全局和静态的const变量和字符串常量 不超过64K长度
.econst 长调用的常量 数据中的任何地方
.pinit 全局对象的构造函数表 代码
.switch switch语句产生的表 代码或者数据
.text 可执行代码和常数 代码

没初始化的段是由未初始化的变量,堆栈和malloc产生的内存。下表列出了由编译器产生的没初始化段。

没初始化段
段名 内容 限制
.bss 全局和静态变量 不超过64K长度
.ebss 长调用的全局或静态变量 数据中的任何地方
.stack 堆栈空间 不超过64K长度
.sysmem malloc函数产生的内存 不超过64K长度
.esysmem far_malloc函数产生的内存 数据中的任何地方

一旦编译器生成的这些段,连接器会从各个源文件中取出这些段,并结合它们来创建一个输出文件。连接器命令文件(.cmd)就是用来告诉连接器去哪里找这些段的。初始化段必须分配到非易失性存储器,如flash/ ROM,当电源被撤除时,程序不会消失。未初始化的段可以被分配到RAM中,因为它们是在代码执行期间被初始化的。

关于更多编译段和连接的信息,请参见:《TMS320C28x Assembly Language
Tools User’s Guide 》(SPRU513) 和《 the TMS320C28x Optimizing C/C++ Compiler User’s Guide》(SPRU514)。

德州仪器(TI)提供了多个例子显示如何使用链接器命令文件分配编译段。其中一个就是《Running an Application from Internal Flash Memory on the TMS320F28xx DSP 》(SPRA958)。此应用文档提供的例子,演示了使用基于RAM和Flash的项目的链接器命令文件。

3.软件:

本应用文档相关的代码文件,包括修改后的版本的CodeStartBranch.asm文件和非DSP/BIOS™项目用的文件DSP28xxx_SectionCopy_nonBIOS.asm,由the C/C++ Header Files and Peripheral Examples提供。每个TMS320F28xxx处理器都提供了现成的连接器命令文件。提供的示例项目演示了如何使用这些文件。本应用文档以TMS320F2808为例。

该软件独立存放于F28xxx_Flash_to_Ram文件夹中。代码使用的来自the C/C++ Header Files and Peripheral Examples的几个文件,经过了Code Composer Studio™ 3.3和F28xxx代码生成工具5.0.0B3版本的测试。

3.描述:

一般的程序流程是这样子的:code_start->wd_disable->copy_sections->c_int00->mian()

。这个软件流程比标准的软件流程仅仅多了调用复制代码段函数。标准的软件流程:code_start->wd_disable->c_int00->mian()。

程序开始和关闭看门狗:

code_start 和wd_disable 的运行代码由DSP28xxx_CodeStartBranch.asm文件提供。上电后,code_start正常执行,因为它被分配给Flash的引导地址的0x3F7FF6。详见:《Running an Application from Internal Flash Memory on the TMS320F28xx DSP
》(SPRA958)

  1. WD_DISABLE .set 1 ;set to 1 to disable WD, else set to 0
  2. .ref copy_sections
  3. .global code_start
  4. ***********************************************************************
  5. * Function: codestart section
  6. *
  7. * Description: Branch to code starting point
  8. ***********************************************************************
  9. .sect "codestart"
  10. code_start:
  11. .if WD_DISABLE == 1
  12. LB wd_disable ;Branch to watchdog disable code
  13. .else
  14. LB copy_sections ;Branch to copy_sections
  15. .endif

这个函数从the C/C++ Header Files and Peripheral Examples提供的CodeStartBranch.asm文件修改而来,只是第二个调用用copy_sections代替了_c_int00。这个调用仅仅在WD_DISABLE为0时执行。上面的代码,WD_DISABLE 被设置为1。这使得wd_disable运行。wd_disable的代码如下:

  1. ***********************************************************************
  2. * Function: wd_disable
  3. *
  4. * Description: Disables the watchdog timer
  5. ***********************************************************************
  6. .if WD_DISABLE == 1
  7. .sect "wddisable"
  8. wd_disable:
  9. SETC OBJMODE ;Set OBJMODE for 28x object code
  10. EALLOW ;Enable EALLOW protected register access
  11. MOVZ DP, #7029h>>6 ;Set data page for WDCR register
  12. MOV @7029h, #0068h ;Set WDDIS bit in WDCR to disable WD
  13. EDIS ;Disable EALLOW protected register access
  14. LB copy_sections ;Branch to copy_sections
  15. .endif

这要求看门狗在_sections和c_int00函数运行期间被除能,否则,看门狗可能会在进入main()之前超时。这个函数也是从the C/C++ Header Files and Peripheral Examples提供的CodeStartBranch.asm文件修改而来,只是用copy_sections代替了_c_int00。

Copy_sections:

DSP28xxx_SectionCopy_nonBIOS.asm文件提供了copy_sections的代码,第一次运行到这里,看门狗是关闭的,段已经准备好被复制,段大小被存放在累加器,装载地址放在XAR6中,执行地址放在XAR7中,这个功能例子如下:

  1. MOVL XAR5,#_text_size ; Store Section Size in XAR5
  2. MOVL ACC,@XAR5 ; Move Section Size to ACC
  3. MOVL XAR6,#_text_loadstart ; Store Load Starting Address in XAR6
  4. MOVL XAR7,#_text_runstart ; Store Run Address in XAR7
  5. LCR copy ; Branch to Copy

段的大小,装载开始标志,执行开始标志都由连接器产生,这是在内存分配 -链接器命令文件一节讨论。

在地址和段长度都被存放好之后,copy程序被调用来确定段是否被编译器产生,这由检测累加器是否为0来确定。

  1. copy:
  2. B return,EQ ; Return if ACC is Zero (No section to copy)
  3. RPT AL ; Copy Section From Load Address to
  4. || PWRITE *XAR7, *XAR6++ ; Run Address
  5. return:
  6. LRETR ; Return

如果累加器为0,程序会返回到调用前的地址,如果累加器不为0,有段需要被复制。这用上面所示的PWRITE指令来实现,PWRITE复制XAR6指向的存储器的内容到XAR7指向的内容。在这里,就是复制装载代码的地址的内容到运行代码的地址。这样,一直到累加器为0,完成整个段的复制,当所有段都被复制完,程序就会跳到c_int00,如下:

  1. LB _c_int00 ; Branch to start of boot.asm in RTS library

到这里,C语言环境被建立,main()是可进去的。

完整的copy_sections程序请参见相关文件夹中的DSP28xxx_SectionCopy_nonBIOS.asm。

内存分配 - 连接命令文件(.cmd):

如第二节所述,连接命令文件(.cmd)是用来告诉连接器怎么分配编译器产生的段的。The C/C++ Header Files and Peripheral Examples提供了标准的连接命令文件(.cmd)。

相关代码文件中提供了三个链接器命令文件用于配置内存分配。

· F280xx_nonBIOS_flash.cmd
· F281x_nonBIOS_flash.cmd
· F2833x_nonBIOS_flash.cmd

每个文件一般都用相同的方法编写,只是在存储器方面有很小的一些差异(特殊设备)。连接命令文件(.cmd)的Memory部分是根据设备的内存空间来连接编译好的段的。详情参见具体控制器的数据手册。

下表展示TMS320F2808的存储器映射:

TMS320F28xxx系列控制器内置RAM,可以被分配为一个单独的段,或者更多的段,因为它是连续的存储器映射。如上图所示,F2808有映射到存储器空间的L0,L1和H0 SARAMs,允许生成一个大的内存块,这个块可以被CMD文件的MEMORY部分如下定义:

  1. RAM_H0L0L1 : origin = 0x008000, length = 0x004000

其余的也可以定义在MEMORY部分,完整的内存分配,请参见相关文件中的CMD文件。

链接器命令文件的第二部分是SECTIONS。这是实际编译器把段连接到的存储区。所有DSP28xxx_CodeStartBranch.asm 和 DSP28xxx_SectionCopy_nonBIOS.asm的段都被装载到flash中运行,这部分如下所示分配:

  1. codestart : > BEGIN_FLASH, PAGE = 0
  2. wddisable : > FLASH_AB, PAGE = 0
  3. copysections : > FLASH_AB, PAGE = 0

其他被初始化的段被下载到flash,但是在ram中运行。这是通过load和run指令来实现。下面展示一个例子:

  1. .text : LOAD = FLASH_AB, PAGE = 0
  2. RUN = RAM_H0L0L1,PAGE = 0
  3. LOAD_START(_text_loadstart),
  4. RUN_START(_text_runstart),
  5. SIZE(_text_size)

为了获得与一个段相关联的特定地址,如上所示,使用了LOAD_START, RUN_START, 和SIZE指令。这些指令的地址和大小在DSP28xxx_SectionCopy_nonBIOS.asm文件使用到,用以在复制过程中指向正确的地址。DSP28xxx_SectionCopy_nonBIOS.asm把这些值创建为全局变量,如下图所示

  1. .global _cinit_loadstart, _cinit_runstart, _cinit_size
  2. .global _const_loadstart, _const_runstart, _const_size
  3. .global _econst_loadstart, _econst_runstart, _econst_size
  4. .global _pinit_loadstart, _pinit_runstart, _pinit_size
  5. .global _switch_loadstart, _switch_runstart, _switch_size
  6. .global _text_loadstart, _text_runstart, _text_size

测试例子:

提供的示例在TMS320F2812,TMS320F2808,TMS320F28335eZdsp开发板上进行了测试。板子上LED的闪烁可以从视觉上证实程序是否正确运行。下面的程序是基于F2808eZdsp评估板设计和测试的。同样的,这种方法可以用于其他eZdsp开发板。

Code Composer Studio环境:

1.使用USB线连接F2808eZdsp开发板到PC,接上电源线给板子供电。

2.打开Code Composer Studio,设置F2808 eZdsp 仿真器。

3.打开和编译Example_280xx_Flash_to_RAM_nonBIOS.pjt。

4.下载.out文件到芯片的flash中。

5.调试程序(debug)。

6.运行程序(run)。

在eZdsp电路板上的LED应闪烁,表示程序正在运行。

应用:

现有的Flash应用程序可以很容易地通过移植相关代码文件来实现此功能。基本的移植步骤如下:

1.用DSP28xxx_CodeStartBranch.asm替换CodeStartBranch.asm。

2.在工程中添加DSP28xxx_SectionCopy_nonBIOS.asm文件。

3.用特殊生成的CMD文件代替现有的CMD文件。

这个基本步骤不适用于一些特殊情况,比如用户自己定义的段,等

应用例子:

为了演示的应用程序集成的过程,在C280x,C2801x
C / C ++头文件和外设示例的Example_2808_Flash.pjt中使用下列步骤移植。

1.下载安装C280x, C2801x C/C++ Header Files and Peripheral Examples。

2.如上所述连接板,打开项目文件。

3.删除项目中的DSP280x_CodeStartBranch.asm文件,在项目中添加DSP28xxx_CodeStartBranch.asm文件。

4.在项目中添加DSP28xxx_SectionCopy_nonBIOS.asm文件。

5.删除项目中的cmd文件,在项目中添加F280xx_nonBIOS_flash.cmd文件。

6.把DSP280x_usDelay.asm中的.sect “ramfuncs”改为.text,使DSP28x_usDelay在被分配在.text段中。

7.删除DSP280x_SysCtrl.c文件中的#pragma CODE_SECTION(InitFlash, “ramfuncs”);。使得InitFlash( )函数被分配到.text而不是ramfuncs。

8.删除Example_280xFlash.c文件中的#pragma CODE_SECTION(epwm1_timer_isr, “ramfuncs”);和#pragma CODE_SECTION(epwm2_timer_isr, “ramfuncs”);。使得中断服务函数被分配到.text而不是ramfuncs。

9.删除Example_280xFlash.c文件中的MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart)注意:这个已经不需要和
InitFlash( )。由于代码已经被复制到RAM,这些是不需要的了。

10.如上所述,编译连接程序,把程序下到芯片里运行。

在eZdsp电路板上的LED应闪烁,表示程序正在运行。

存储空间占用:

因为仅仅在DSP28xxx_SectionCopy_nonBIOS.asm文件中增加了copy_sections的代码。增加的占用的片内flash为0x3C。code_start 和wd_disable函数没有增加额外的代码,他们本来就在C/C++ Header Files and Peripheral Examples的所用项目中被使用。

测试:

因为这个功能开机后直接实现,闪存等待状态,锁相环(PLL)都没有配置,因此,它们都运行在默认值。Flash等待状态为15个周期,对于F280xx/F281x设备SYSCLKOUT为OSCCLK/2,对于F2833x设备SYSCLKOUT为OSCCLK/ 4。使用Code Composer Studio的分析功能可以测量运行时间。下表给出了每个F28xxx控制器从启动到main()函数的第一个指令所用的时间,如下所示,由于个平台的代码长度和系统时钟不一样,他们的运行时间也不一样。

限制:

此实现的限制因素为使用的TMS320F28xxx控制器内部RAM的大小。这限制了那些工程可以使用这种方法,如果工程太大,以至于没法放进RAM里,这种方法是不能用的。(除非外扩RAM)

建议:

有一些项目需要这种功能,但不是所有被初始化段都要复制到RAM或者没有足够的RAM放下所有的段。仅仅需要复制应用代码本身。这种情况下,仅仅需要复制.text段到RAM。这样子,可以把DSP28xxx_SectionCopy_nonBIOS.asm文件和cmd文件中复制其他段的代码删掉,把其他段放在flash中运行。减少flash的占用空间和缩短了运行到main()的时间。

应该确定应用程序可以处理复制代码执行时间的一点滞后。如果应用程序不能处理这段时间,可以使用Running an Application from Internal Flash Memory on the TMS320F28xx DSP (SPRA958)中的方法复制一部分主要的代码到ram。

如果使用DSP的引导,建议使用Running an Application from Internal Flash Memory on the TMS320F28xx DSP (SPRA958)中的方法复制一部分主要的代码到ram。一个使用DSP / BIOS的项目,通常是一个较大的项目,不建议使用此方案。

结语:

这份应用文档展示,在建立C语言环境之前,通过把flash的代码复制到ram,可以使TMS320F28xxx的控制器实现零等待状态运行。这方案给出了代码和存储空间的限制,为设计者提供了实现了这种功能的相关文件。

DSP28335—把TMS320F28XXX的程序段从flash复制到ram中运行相关推荐

  1. 把DSP TMS320F28XXX的程序段从flash复制到ram中运行

    翻译自TI应用手册SPRAAU8(http://www.ti.com.cn/cn/lit/an/spraau8/spraau8.pdf) 摘要 这个应用报告和相关的代码提供了一种把编译后的程序段从TM ...

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

    文章目录 动机 CMD文件结构与语法 MEMORY和SECTIONS指令 MEMORY指令 SECTIONS指令 程序与数据段 已初始化段 未初始化段 其他指令 #pragma指令的使用 程序从FLA ...

  3. DSP28377S_程序从FLASH部分复制到RAM中运行详解

    程序从FLASH部分复制到RAM中运行详解 为什么要复制到RAM中运行 CMD文件中对存储空间的分配 CMD文件中对段的定义 CMD文件中FLASH部分复制到RAM中的定义 main中的操作 编译后如 ...

  4. 将flash中的代码复制到RAM中运行的方法

    在MCU的使用过程中,偶尔会遇到将flash中的代码复制到RAM中运行的情况,下面就来说一下具体的方法,以28335的flash初始化为例: 1,编写函数,该函数处于flash中,就是我们即将要复制的 ...

  5. [第一讲]DSP28335将Flash中的代码拷贝到RAM中运行

    背景: 近期需要使用28335完成一个简单的逆变器设计,由于开关频率为81kHz,每个开关周期只有12.34us,担心在每个开关期间无法完成相应的计算工作,因此想到了将代码烧写时放在Flash中,初始 ...

  6. STM32中断向量表复制到SRAM中运行

    1.生成Map文件 复制中断向量表前需要知道中断向量表的大小,可以通过编译生成的Map文件查看. 2.查看中断向量表大小 中断向量表的大小是固定的,与程序代码量无关,打开Map文件,直接搜索0x080 ...

  7. 为什么单片机的代码在Flash中运行,单片机的代码运行位置跟电脑有什么不同?

    1. 单片机与电脑,在代码运行空间的区别 单片机与 电脑/Linux嵌入式 在代码运行的空间上不同.大多数单片机,代码都是在Flash中运行的.而电脑/linux嵌入式,是将代码从存储介质(可能是硬盘 ...

  8. TMS28335下载到片内Flash中并全部搬运到RAM中进行运行

    目录 前言 一.将部分函数搬运到RAM运行. 二.将所有函数全部搬运到RAM中运行. 1.从RAM调试模式到Flash模式 2.从Flash模式到RAM调试模式 总结 文件上传 前言 本人最近调试好代 ...

  9. 程序是运行在flash中还是RAM中?

    前言 最近在做项目中遇到一些疑虑,包括OTA升级时会不会阻塞到其他工作线程.select原理和正确用法.如何快速正确理解产品到软件框架构建.嵌入式应用的代码优化方法.本篇文章主要针对第一个问题,请教外 ...

最新文章

  1. java关键字--static--应用场景、特点和注意事项
  2. TCP连接之未连接队列的理解[转]
  3. 员外陪你读论文:DeepWalk: Online learning of Social Representations
  4. Linux系统开机启动过程分析
  5. mysql 为数据表添加字段_MySQL数据表添加字段实例
  6. 脚本修改IIS连接数
  7. 明年的现在我也想去“双选会”应聘!
  8. 使用fetch函数发送ajax
  9. c51语言自定义头文件,C51语言头文件包括的内容有
  10. linux mint17kde 安装教程,Kubuntu 14.04 /Linux Mint 17 怎样安装 KDE 4.14.1
  11. php脚本是什么,PHP脚本的编写
  12. params.c:Parameter() - Ignoring badly formed line in configuration file: ignore errors 解决方法
  13. 电脑开机加速,一下子就提升了20几秒
  14. 什么是大型机和小型机
  15. 微信JSAPI之V3版本支付踩坑
  16. 七夕给男朋友送什么礼物好、七夕男朋友礼物清单
  17. ES6转码器Babel
  18. android app 重启消失了,android平板重启apk消失不见
  19. 孙飞脸色一变,惊讶道:“修者,你也是修者?”
  20. 42岁,王兴的兄弟退休了

热门文章

  1. 别人的 App 不好用?自己改了便是。嘿嘿嘿 篇
  2. 怎么抓取网上的音频呢?我来操作下嘿嘿...
  3. MySQL+JDBC--狂神视频学习笔记
  4. 解析旅游网驴妈妈的大数据用户推荐系统(3月11日实时分享)
  5. Matlab:仿真正弦光栅的衍射传输特性
  6. 用UPUPW配置服务器环境竟然这么简单
  7. DTK的历史起源、发展,和简单入门
  8. C# 打印Word文档
  9. 深拷贝与浅拷贝的实现方案与应用场景
  10. tp5网站 服务器部署,tp5云服务器部署