天天看點

在TMS320F2812上實作從flash拷貝整個程式到RAM上運作的方法探讨在TMS 320F 2812上實作從flash拷貝整個程式到RAM上運作的方法探讨

在TMS 320F 2812上實作從flash拷貝整個程式到RAM上運作的方法探讨

1.     前言

TMS 320F 2812 DSP 裡,代碼從内部flash裡運作,比從内部RAM裡運作要慢30%左右,是以對運作時間苛刻的程式直接在flash裡運作,往往不能滿足要求。故而,需要将代碼拷貝到RAM以提高運作速度。TI文檔隻提供了部分代碼從flash拷貝到RAM中的方法。然而,在一些應用中,需要将整個代碼段都拷貝到RAM中執行,以提高整體運作速度。本文通過對TMS 320F 2812 的啟動代碼研究,來探讨如何在從FLASH啟動後将整個代碼段拷貝到RAM中,然後在RAM中運作的方法。

2.     TMS 320F 2812 啟動過程

TMS 320F 2812的内部存儲器中,0x 3F F000  ----0x3FFFC0是4K*16的Boot ROM。

在TMS320F2812上實作從flash拷貝整個程式到RAM上運作的方法探讨在TMS 320F 2812上實作從flash拷貝整個程式到RAM上運作的方法探讨

  圖1  2812内部BootRom位址圖

CPU向量表位于北部ROM的底端(0x3FFFC0 ---- 0x3FFFF)。當VMAP=1,ENPIE=0 ,MPNMC=0時,該向量表被激活。複位向量出廠時被程式設計指向函數InitBoot。這個函數開始啟動過程。當然,啟動過程完成之後,我們需要初始化PIE中斷向量表,同時使能PIE block。初始化PIE中斷向量表之後,除了複位,所有中斷向量均從PIE獲得。

TMS 320F 2812啟動代碼固化在該内部ROM中。當TMS 320F 2812上電或者熱複位後,首先由晶片本身将一些寄存器初始化:

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(0x400 - 0x 44F 作為啟動過程中的堆棧);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 0x 3F 7FF6

下圖為BootROM 函數的流程圖

在TMS320F2812上實作從flash拷貝整個程式到RAM上運作的方法探讨在TMS 320F 2812上實作從flash拷貝整個程式到RAM上運作的方法探讨

圖2  BootROM 函數的流程圖

對于内部flash啟動,如圖

在TMS320F2812上實作從flash拷貝整個程式到RAM上運作的方法探讨在TMS 320F 2812上實作從flash拷貝整個程式到RAM上運作的方法探讨

圖3跳轉到Flash啟動的流程圖

在0x 3F 7FF6必須放置一個跳轉指令,該指令跳轉到你自己的啟動代碼或者應用程式。

3.     搬移思路

根據上節2的啟動過程,flash啟動過後,跳到0x 3F 7FF6,然後根據其内容再跳轉到應用程式。我們在這裡稍微修改一下,就可以将PC指針跳到RAM首位址,程式就能在RAM裡運作了。

将“搬移程式”燒在flash上,從flash啟動之後,“搬移程式”會被執行。“搬移程式”做的工作就是将“應用主程式”代碼拷貝到内部RAM,然後經過初始化環境(InitBoot,ExitBoot),将PC指針指向RAM裡代碼首位址。這樣,你的程式就在RAM中運作起來了。也就是說,我們需要一個“搬移程式”,啟動時運作,用來拷貝flash上的代碼到RAM中;當然,還需要一個你的“應用主程式”,該主程式被“搬移程式”從flash裡“挪”到RAM後在RAM中運作。我們還要做的工作就是,把“應用主程式”燒寫到flash裡的某一塊,這個塊又不會影響flash啟動時運作“搬移程式”。完成這個燒寫過程的程式,我們稱之為flash燒寫程式。

總結一下,完成整個搬移過程,一共需要三個程式。“搬移程式”和“應用主程式”被固化到flash裡“燒寫flash程式”将“應用主程式”燒入flash中指定的塊中。TI的燒寫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

}

      

從上面的CMD可知,主程式代碼均放在RAMH0中,長度為0x2000。

2)其次,将該工程編譯成功後,加載到内部ram,仿真器自動完成必要的初始化環境之後,pc指針應該指向_c_init00,記下現在PC指針的位置,在Boot.asm中會用到。

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();   //調用Boot.asm中程式         
      

繼續閱讀