在TMS320F28XXX DSP上实现从flash拷贝整个程序到ram运行的方法探讨

1.     前言

TMS320F28XXX DSP 里,代码从内部flash里运行,比从内部RAM里运行要慢30%左右,所以对运行时间苛刻的程序直接在flash里运行,往往不能满足要求。故而,需要将代码拷贝到RAM以提高运行速度。TI文档只提供了部分代码从flash拷贝到RAM中的方法。然而,在一些应用中,需要将整个代码段都拷贝到RAM中执行,以提高整体运行速度。本文通过对TMS320F28XXX 的启动代码研究,来探讨如何在从FLASH启动后将整个代码段拷贝到RAM中,然后在RAM中运行的方法。

2.     F28XXX 启动过程

F28XXX启动代码固化在内部ROM中。当F28XXX上电或者热复位后,首先由芯片本身将一些寄存器初始化:

PIE disabled(ENPIE=0,VMAP=1,OBJMDE=0,AMODE=0,MOM1MAP=1),

然后dsp会对XMPNMC管脚采样,根据采样值的高低,来决定启动模式是“微处理器模式”还是“微计算机模式”。当XMPNMC=0时,为“微计算机模式”,此时,启动ROM存储器被使能而XINTF Zone 7被禁止。复位向量从内部启动ROM获取,启动ROM在复位期间一直被使能。

       启动ROM里的复位向量(位于0x3FFFC0)指向InitBoot函数(位于0x3FFC00)。在完成器件初始化(InitBoot)之后,Boot loader将检查GPIO管脚的状态,然后再决定选用的启动模式。启动模式有4种:跳转到flash,跳转到H0 SARAM,跳转到OTP或者调用片上启动程序。

       InitBoot Function 所做工作有:

1.初始化状态寄存器;

2.将堆栈指针设为0x400;

3.读CSM密码保护部分;

4.调用SelectBootMode;

5.调用ExitBoot

       在完成选择启动模式过程之后,根据选择的启动模式,dsp会跳到相应的启动入口。也可以自己选择启动入口。这些入口地址都在这之前已经被dsp定义好的。

       如果从flash启动,那么我们的管脚状态应该是

GPIOF4

GPIOF12

GPIOF3

GPIOF2

 

(SCITXDA)

(MDXA)

(SPISTEA)

(SPICLK)

 

内部上拉

无内部上拉

无内部上拉

无内部上拉

Mode Selected

1

x

x

x

Jump to Flash address 0x3F 7FF6

 

3.     搬移思路

将搬移代码烧在flash上,从flash启动之后,搬移代码会被执行。搬移代码做的工作就是将烧在flash其他区的代码拷贝到内部RAM,然后经过初始化环境,PC指针指向RAM里代码部分首地址,开始执行程序。这样,你的程序就在 RAM中运行起来了。也就是说,我们需要两个程序,一个是搬移程序,启动时运行,用来拷贝代码到RAM中;一个就是主程序,从flash里被搬移到RAM 后在RAM中运行。这样flash里应该存有两个程序的代码。我们还要做的工作就是,把主程序烧写到flash里的某一块,这个块又不会影响flash启动时运行搬移程序。完成这个烧写过程的程序,我们称之为flash烧写程序。

这样,完成整个搬移过程,一共需要三个程序。两个程序被固化到flash里,一个程序在仿真器里运行完成烧写任务即可。

4.     搬移方法

1)首先你要用的主程序必须编译通过,并且通过仿真器在RAM里运行无问题。将主程序的CMD文件进行改写,保证程序段(.text段)分配在连续的存储空间。程序从flash启动,所有初始化段链接在非易失存储器里,而非初始化段必须链接在易失存储器。我们可以把初始化段都放在一个连续的内部RAM空间,而非初始化段放在另一个内部RAM空间。如果你的代码不是很大,也可以都放在连续的RAM空间。但在实际项目中,通常你会遇到存储空间不够的问题。这时就要考虑将无关紧要的段放在另外的非程序空间了。

.cinit

Flash

.cio

RAM

.const

Flash

.econst

Flash

.pinit

Flash

.switch

Flash

.text

Flash

.bss

RAM

.ebss

RAM

.stack

Lower 64Kw RAM

.sysmem

RAM

.esysmem

RAM

.reset

RAM1

例如:

MEMORY

{

PAGE 0 :

   RAMH0      : origin = 0x3F8000, length = 0x002000

        

PAGE 1 :

   /* SARAM                     */    

   RAMM0M1    : origin = 0x000000, length = 0x000800

   RAML0L1    : origin = 0x008000, length = 0x002000

}

 

 

SECTIONS

{

   /* Allocate program areas: */

   .reset              : > RAMH0     PAGE = 0

   vectors             : > RAMH0     PAGE = 0

   .cinit              : > RAMH0     PAGE = 0

   .text               : > RAMH0     PAGE = 0

   .const              : > RAMH0     PAGE = 0

   .econst             : > RAMH0     PAGE = 0

   .switch                      : > RAMH0     PAGE = 0

  

   /* Allocate data areas: */

   .stack              : > RAMM0M1     PAGE = 1

   .bss                : > RAML0L1     PAGE = 1

   .ebss               : > RAML0L1     PAGE = 1

   .sysmem             : > RAML0L1     PAGE = 1

}

 

2)其次,将该工程编译成功后,加载到内部ram,仿真器自动完成必要的初始化环境之后,pc指针应该指向_c_init00。

3)自制一个flash烧写程序,或者从网上下载其他网友的flash烧写程序,将目标地址放在除flashJ块以外的块中。烧写的长度不能小于被烧写的主程序长度。该烧写程序在RAM中运行。,其代码段不能和被烧写的主程序用的代码段存储区域相同,否则会破坏主程序在ram中的代码。

       烧写之后,可以用CCS的Save data功能,来查看flash中的数值是否和ram里主程序空间数值一致。

4) 用TI的烧写插件烧写搬移程序。注意,该搬移程序要能在dsp启动后执行。并且,烧写的时候,不能将上一步烧到flash上的主程序代码擦除。搬移程序具体见下节。

 

 

5.     搬移程序具体实现方法

Boot.asm文件内容:

 

    .def _InitBoot

    .ref _EntryAddr_H

    .ref _EntryAddr_L

 

    .sect ".InitBoot"

;

; _InitBoot

;

; 1) Initalizes the stack pointer

; 2) Sets the device for C28x operating mode

; 3) Calls the main boot functions

; 4) Calls an exit routine

;

_InitBoot:

; Initalize the stack pointer.

  MOV SP, #0 ; Initalize the stack pointer

; Initalize the device for running in C28x mode.

  C28OBJ ; Select C28x object mode

  C28ADDR ; Select C27x/C28x addressing

  C28MAP ; Set blocks M0/M1 for C28x mode

  CLRC PAGE0 ; Always use stack addressing mode

  MOVW DP,#0 ; Initialize DP to point to the low 64 K

  CLRC OVM

; Set PM shift of 0

  SPM 0

; Read the password locations – this will unlock the

; CSM only if the passwords are erased. Otherwise it

; will not have an effect.

  MOVL XAR1,#0x3F7FF8;

  MOVL XAR0,*XAR1++

  MOVL XAR0,*XAR1++

  MOVL XAR0,*XAR1++

  MOVL XAR0,*XAR1

; Cleanup and exit. At this point the EntryAddr

; is located in the ACC register

  BF _ExitBoot,UNC

;

; _ExitBoot

;

;

;This module cleans up after the boot loader

;

; 1) Make sure the stack is deallocated.

; SP = 0x400 after exiting the boot

; loader

; 2) Push 0 onto the stack so RPC will be

; 0 after using LRETR to jump to the

; entry point

; 2) Load RPC with the entry point

; 3) Clear all XARn registers

; 4) Clear ACC, P and XT registers

; 5) LRETR – this will also clear the RPC

; register since 0 was on the stack

;

_ExitBoot:

;

; Insure that the stack is deallocated

;

  MOV SP,#0

;

; Clear the bottom of the stack. This will endup

; in RPC when we are finished

;

  MOV *SP++,#0

  MOV *SP++,#0

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP 

;

; Load RPC with the entry point as determined

; by the boot mode. This address will be returned

; in the ACC register.

;向堆栈中压入0x3f8000,该地址即为主程序在ram中运行的首地址。

  MOV *SP++, #0x8000

  MOV *SP++, #0x3F

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

 

  POP RPC

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP 

;

; Put registers back in their reset state.

;

; Clear all the XARn, ACC, XT, and P and DP

; registers

;

; NOTE: Leave the device in C28x operating mode

; (OBJMODE = 1, AMODE = 0)

;

  ZAPA

  MOVL XT,ACC

  MOVZ AR0,AL

  MOVZ AR1,AL

  MOVZ AR2,AL

  MOVZ AR3,AL

  MOVZ AR4,AL

  MOVZ AR5,AL

  MOVZ AR6,AL

  MOVZ AR7,AL

  MOVW DP, #0

;

; Restore ST0 and ST1. Note OBJMODE is

; the only bit not restored to its reset state.

; OBJMODE is left set for C28x object operating

; mode.

;

; ST0 = 0x0000 ST1 = 0x0A0B

; 15:10 OVC = 0 15:13 ARP = 0

; 9: 7 PM = 0 12 XF = 0

; 6 V = 0 11 M0M1MAP = 1

; 5 N = 0 10 reserved

; 4 Z = 0 9 OBJMODE = 1

; 3 C = 0 8 AMODE = 0

; 2 TC = 0 7 IDLESTAT = 0

; 1 OVM = 0 6 EALLOW = 0

; 0 SXM = 0 5 LOOP = 0

; 4 SPA = 0

; 3 VMAP = 1

; 2 PAGE0 = 0

; 1 DBGM = 1

; 0 INTM = 1

;

  MOV *SP++,#0

  MOV *SP++,#0x0A0B

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  POP ST1

  POP ST0

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

  NOP

;

; Jump to the EntryAddr as defined by the

; boot mode selected and continue execution

;

  LRETR

;

    .end

 

主程序调用

 unsigned long *srcAddr = (unsigned long *)0x3D8000;

unsigned long *desAddr = (unsigned long *)0x3F8000;

       InitSysCtrl();

 

       // Disable and clear all CPU interrupts:

       DINT;

       IER = 0x0000;

       IFR = 0x0000;

 

       // Initialize Pie Control Registers To Default State:

       InitPieCtrl();

 

       InitPieVectTable(); 

      

       //以下即将flash上的代码拷贝到ram中,根据自己需要,更改源地址和目标地址

    for(i = 0; i < 0x2000; i++)

    {

        *(desAddr + i) = *(srcAddr + i);

    }

   

    InitBoot();       

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在将STM32代码Flash搬移到RAM的过程,我们首先需要确保芯片的RAM容量足够存储代码。然后,我们需要将代码的链接脚本进行修改,以便将代码Flash的地址重新定位到RAM的地址。接下来,我们需要进行代码的复制操作,将Flash代码复制到RAM。 为了完成这个过程,我们可以使用如下的步骤: 1. 修改链接脚本:打开链接脚本文件并进行修改,将代码的起始地址和大小重新定义为RAM的地址和大小。 2. 修改代码运行起始位置:检查代码的启动函数,确保它指向RAM的起始位置,而不是Flash的起始位置。 3. 复制代码RAM:在代码的启动函数,我们需要添加复制代码RAM的操作。可以使用内置的复制函数(如`memcpy()`)或者手动复制方式进行。将Flash代码复制到RAM后,确保更新相关变量的地址。 4. 设置向量表位置:在引导代码的开头,我们需要设置向量表的位置为RAM。这需要根据具体的芯片进行设置,可以通过修改SCB的VTOR寄存器来实现。 5. 更新断向量表地址:在启动文件,确保断向量表的地址已经更新为RAM的地址。这样做可以确保芯片在断发生时正确地跳转到RAM断处理函数。 6. 验证代码正常运行:重新编译和烧写代码,并确保所有代码正常运行,没有出现异常或错误。 总结起来,将STM32代码Flash搬移到RAM需要修改链接脚本和代码运行起始位置,并进行代码的复制操作。同时,还需要设置向量表的位置,更新断向量表地址,并验证代码的正常运行。这样做可以提高代码的执行速度,尤其适用于性能要求较高的应用。 ### 回答2: 将STM32代码Flash搬移到RAM的主要目的是为了提高代码的执行效率和响应速度。在Flash存储的代码是只读的,因此每次执行代码时,MCU都需要从Flash读取指令,这会导致一定的读取延迟和访问速度下降。而将代码搬移到RAM后,可以直接从RAM读取指令,以极大地减少读取延迟和提高执行效率。 搬移代码的操作一般分为两步:将代码Flash复制到RAM,并将复制后的代码重新定位到RAM的起始地址。这样,当代码执行时,MCU会首先从RAM读取指令,而不需要再每次都从Flash读取。 搬移代码的过程可以通过使用相关函数或指令来完成。在STM32,可以使用HAL库的相应函数,如HAL_FLASHEx_DATAEEPROM_Copy()函数来实现Flash代码复制到RAM。在复制完成后,还需要根据具体的MCU型号和使用的开发工具,设置复制后代码的起始地址,以便MCU能够正确地访问RAM代码。 需要注意的是,将代码搬移到RAM后,需要合理利用RAM的容量和管理RAM的使用,因为RAM的容量一般比Flash有限。在复制代码之前,应该先估计代码的大小,并确保RAM有足够的空间来存储代码。此外,还可以考虑将一些频繁执行的代码块搬移到RAM,以进一步提高执行效率。 总结来说,将STM32代码Flash搬移到RAM是为了提高代码的执行效率和响应速度。通过复制代码RAM并设置正确的起始地址,可以减少访问延迟,提高读取速度和执行效率。然而,在搬移代码时需要注意RAM的容量限制,并合理管理RAM的使用。 ### 回答3: 将STM32的代码Flash搬移到RAM可以提高代码执行效率和速度。通常情况下,STM32的代码存储在Flash,当在运行时需要执行部分代码时,会从Flash读取指令并执行。搬移到RAM后,所有代码都存储在RAM运行时不再需要从Flash读取指令,而是直接在RAM执行指令,从而减少了访问存储器的时间。 实现将STM32代码Flash搬移到RAM的步骤如下: 1. 在代码工程Flash部分的代码复制到RAM区域的一部分以确保代码可用。可以在代码声明一个特殊的RAM段,将相关函数和变量放入其。 2. 通过编译器和链接器设置,将这部分特殊RAM段的起始地址和大小与MCU的RAM进行关联。这样,编译器在生成可执行文件时会将相应的代码放到RAM区域。 3. 在代码修改启动向量,使得MCU重启后直接从RAM启动,而不是从Flash启动。这可以通过设置复位向量表的复位向量地址为RAM的起始地址来实现。 4. 对于涉及到断向量表的代码,还需要修改断向量表,使得断服务程序能够从RAM正确地执行。 通过将代码搬移到RAM,可以减少Flash访问的延迟和读取时间,提高代码执行速度和效率。这在对实时性要求较高的应用特别有用,例如控制任务响应、数据处理和实时通信等。然而,需要注意的是,将大量代码Flash搬移到RAM可能会导致RAM资源紧张,因此需要仔细评估代码规模和RAM容量,以确保RAM能够容纳所需的代码和数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值