總結——在CCS5.5.0中如何將程式碼燒寫到DSP28335的Flash中
/******************************************************17.6.10更新*************************************************************/
發現之前想的有點小問題,現在想的是,在燒寫程式前不必將Boot mode選擇為1111,只需要將cmd檔案替換為F28335.cmd,然後load程式,之後再將Boot mode選為1111,即FLASH啟動,個人猜測,未驗證。
/********************************************************************************************************************************/
把一個原來是燒寫到DSP的片內RAM的程式修改成是燒寫到DSP片內FLASH的程式,需要以下幾個步驟:
1.新增DSP2833x_CodeStartBranch.asm檔案
新增D:\tidcs\c28\DSP2833x\v131\DSP2833x_common\source\DSP2833x_CodeStartBranch.asm檔案,此檔案負責上電後程序執行順序跳轉的;
2.新增DSP281x_Headers_nonBIOS.cmd檔案
新增D:\tidcs\c28\DSP2833x\v131\DSP2833x_headers\cmd\DSP2833x_Headers_nonBIOS.cmd檔案,用於將DSP28標頭檔案中的外設結構與儲存器地址對應起來;
3.刪除28335_RAM_lnk.cmd檔案
把28335_RAM_lnk.cmd檔案從project中移除,用右鍵選擇28335_RAM_lnk.cmd然後選delete;
4.新增F28335.cmd檔案
右鍵選擇project名稱,然後選add file to project,然後出現瀏覽框,在D:\tidcs\c28\DSP2833x\v131\DSP2833x_common\cmd這個子資料夾下,選擇F28335.cmd,點OK,至此可以在project的檔案列表內看到F28335.cmd被新增到project中;
5.新增兩行程式碼
在main()函式中新增如下語句:
上述兩句話新增在InitPieVectTable();這句的下面的一行,新增語句的時候,注意不要新增錯了,每一個字母都要正確,括號也要用英文括號;MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart); InitFlash();
6.新增DSP2833x_MemCopy.c檔案
右鍵選擇project名稱,然後選add file to project,然後出現瀏覽框,找到D:\tidcs\c28\DSP2833x\v131\DSP2833x_common\source資料夾中的DSP2833x_MemCopy.c檔案,然後點OK;
7.選擇Boot mode
DSP開發板上的撥碼開關都撥到ON,本質含義是:將F28335的GPIO84、GPIO85、GPIO86、GPIO87這四個引腳用1k到10k之間電阻上拉到3.3V,這樣就把Boot mode選為從DSP內部FLASH處boot程式的模式;
8.編譯後進行Debug
編譯沒有錯誤後即可進行Debug,此時將程式碼燒寫到FLASH中,而不是RAM中,如下圖所示:
9.注意事項
(1)下載完如果想要脫離模擬器重新上電執行,必須斷掉模擬器與板子的JTAG連線,否則執行程式會出錯,之前我只把模擬器上的USB和電腦斷開,而JTAG介面未斷開,所以出現執行不正常的現象,這一點很重要!(2)不是RAM中執行正確的程式,就在FLASH中執行也一定正確。
這是因為同樣的程式在DSP的RAM中執行消耗的時間要遠遠短於在FLASH中執行的時間。假如,有一箇中斷函式cpu_timer_isr10ms(),這個函式每隔10ms由CPU定時器1產生中斷觸發,自動跳轉進入執行一次。這個cpu_timer_isr1ms()內部包括三個子函式依次是adc_sanple(),pwm_update(),gpio_toggle():
cpu_timer_isr1ms()
{
adc_sanple();
pwm_update();
gpio_toggle();
}
其中假設adc_sanple()這個子函式在RAM中的執行時間是1ms,pwm_update()這個子函式在RAM中的執行時間是2ms,gpio_toggle()這個子函式在RAM中的執行時間是3ms,那麼1+2+3=6<10,所以完全沒有問題,在RAM中上面這些程式都可以執行很好。但是,如果把上面這些程式放到FLASH中執行,很有可能adc_sanple()這個子函式在FLASH中的執行時間是3ms,pwm_update()這個子函式在FLASH中的執行時間是7ms,這是因為同樣的程式在DSP的RAM中執行消耗的時間要遠遠短於在FLASH中執行的時間。這樣前兩個函式就把10ms都用掉了,根本輪不上gpio_toggle()這個子函式被執行,就被DSP強制終止了,所以看不到gpio_toggle()的現象;
(3)可以Load program到RAM的Out檔案和可以固化(燒寫)到FLASH的out檔案內容是不同的;
(4)一般使用CCS模擬器時,我們把程式燒進RAM中執行,這樣執行速度快,方便實際專案的開發與除錯,此時用的是28335_RAM_lnk.cmd檔案;當專案完成時,我們會選擇將程式燒進Flash中,以擺脫仿對真器的依賴,當我們用f28335.cmd連線檔案時,會把程式燒進28335內部的Flash中,此時,就可以脫離模擬器運行了,從Flash啟動。
(5)DSP的Flash啟動過程是什麼?
首先硬體配置GPIO84~87上拉為1,即處於Flash啟動過程。當DSP復位後,會從復位向量0x3FFFC0處取得復位向量,並跳轉到InitBoot處開始執行,InitBoot會讀GPIO84~87的值發現全為1判斷為Flash啟動方式。然後會跳到0x33FFF6處執行。在CCS5.2工程的cmd檔案中有如下程式碼:
MEMORY
{
PAGE 0 :
BEGIN : origin = 0x33FFF6, length = 0x000002
...
}
SECTIONS
{...
codestart : > BEGIN PAGE = 0
...}
即表示把codestart段放到0x33FFF6位置處,檔案“DSP2833x_CodeStartBranch.asm”中有codestart段的定義,實際上codestart段只是包含了一個跳轉指令,是程式跳轉到_c_int00處,_c_int00在boot.asm in RTS library中有定義,_c_int00的程式碼最終會呼叫c的main函式,之後就是main函式的執行。
(6)cmd中以下程式碼如何解釋?
ramfuncs : LOAD = FLASHD,
RUN = RAML0,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0
第1行表示該段的裝載在PAGA0的FLASHD中
第2行表示該段的執行地址在PAGE0的RAML0中
LOAD_ START(_RamfuncsLoadStart)令編譯器建立了一個變數RamfuncsLoadStart,該變數指向段ramfuncs的裝載地址的首地址(LOAD_ START為編譯偽指令,請見CCS的幫助文件);
LOAD_ START(_RamfuncsLoadEnd)令編譯器建立了一個變數RamfuncsLoadEnd,該變數指向段ramfuncs的裝載地址的末地址(LOAD_ END為編譯偽指令,請見CCS的幫助文件);
RUN_ START(_RamfuncsRunStart)令編譯器建立了一個變數RamfuncsRunStart,該變數指向段ramfuncs的執行地址的首地址(LOAD_ START為編譯偽指令,請見CCS的幫助文件);
從第1和2行可以看出,段ramfuncs中的函式DSP28x_usDelay()的裝載地址和執行地址是不同的,本程式中裝載在Flash的塊FLASHD中,而在SARAM L0中執行,這只是目標,實際執行時DSP並不會自動將Flash中的程式碼拷貝到SARAM中,因此需要手動新增程式碼來完成。
在C函式中,為了使用變數RamfuncsLoadStart、RamfuncsLoadEnd和RamfuncsRunStart,必須先宣告,本工程在檔案DSP2833x_GlobalPrototypes.h中做了如下宣告:
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
然後就可以使用了。在Main.c中,使用MemCopy()函式將段ramfuncs中的函式DSP28x_usDelay()的程式碼從裝載地址RamfuncsLoadStart—RamfuncsLoadEnd拷貝到RamfuncsRunStart開始的SARAM空間中。之後在程式執行時,只要呼叫DSP28x_usDelay()函式,都會自動地指向SARAM中相應的函式入口地址,這一點是自動完成的。MemCopy()函式原型在MemCopy.c中,DSP2833x_GlobalPrototypes.h宣告。