DSP編程技巧---在main函數運行之前,你需要知道的
注:小型內存模型含義是已初始化的段被鏈接至低 64Kw(字)可尋址空間內的非易失性?xún)却?,它使用rts2800.lib。對于定點(diǎn)器件,如果使用大內存模型(超過(guò)64K字),則需要使用庫 rts2800_ml.lib;對于含有FPU的器件,用于標準 C 語(yǔ)言代碼的為 rts2800_fpu32.lib,或者用于 C++ 代碼的 rts2800_fpu32_eh.lib(沒(méi)有針對浮點(diǎn)器件的較小內存模型庫)。在 CCS v5/v6 中,有一個(gè)針對庫的“自動(dòng)”設置,此設置可據項目的設置(例如,浮點(diǎn)支持和內存模型選擇)讓 CCS 自動(dòng)選擇正確的庫來(lái)使用。對于DSP/BIOS 項目,DSP/BIOS 將負責將所需的庫包括在內,我們用戶(hù)不需要在項目中包含任何運行支持庫。
本文引用地址:http://dyxdggzs.com/article/201612/332395.htm如果在鏈接器選項中我們使用了--ram_model或者--rom_mode(具體含義請參考http://dyxdggzs.com/article/249328.htm),則_c_int00函數自動(dòng)被配置為整個(gè)程序執行的入口點(diǎn)。此外,在CPU復位之后(相當于一個(gè)軟件或者硬件的復位中斷),我們也可以把整個(gè)程序的入口點(diǎn)指向_c_int00,例如:
.def _Reset
.ref _c_int00
_Reset: .vec _c_int00, USE_RETA
則在執行CPU復位操作之后,系統自動(dòng)跳轉到_c_int00函數。
在c_int00函數中完成的功能主要有:
1. 設置/初始化CPU的狀態(tài)和配置寄存器。
2. 為系統的棧定義一個(gè).stack段(關(guān)于各個(gè)段的含義,請參考http://dyxdggzs.com/article/256732.htm),然后建立并初始化棧的指針。其中,棧需要被分配在單一的、連續的一段地址中,起始點(diǎn)為低地址,終點(diǎn)為高地址,棧指針SP的初始化值指向棧的頂端。
3. 從初始化表中,把數據復制到.bss段中,從而初始化全局變量。如果使用了—ram_model選項在加載程序時(shí)就初始化變量,則在程序運行前,會(huì )首先運行一個(gè)加載程序來(lái)完成變量的初始化。如果使用了--rom_model選項,則使用.cinit中的運行時(shí)初始化表來(lái)完成變量的初始化。
默認情況下,鏈接器使用--rom_model選項,在程序運行時(shí)完成變量的自動(dòng)初始化。在程序運行時(shí),.cinit段和其它初始化的段會(huì )被一起加載到內存中,從而使得C/C++的啟動(dòng)程序可以自動(dòng)把.cinit中的初始化表格復制到.bss段中,完成全局變量的自動(dòng)初始化。這種方法的特點(diǎn)在于,初始化的表格可以被存放在更加便宜且大容量的ROM或者FLASH,而不是RAM中,并且可以在程序啟動(dòng)時(shí)再自動(dòng)加載到RAM中,這種方法在我們把程序燒寫(xiě)到FLASH中再運行的時(shí)候是經(jīng)常使用的。關(guān)于Flash運行的更多信息,可以參考TI的的一個(gè)應用報告:http://www.ti.com.cn/cn/lit/an/zhca550l/zhca550l.pdf,從 TMS320F28xxx 數字信號處理器 (DSP) 上的內部閃存存儲器上運行一個(gè)應用。
如果使用—ram_model的鏈接器選項,則鏈接器會(huì )在.cinit段的開(kāi)頭中配置STYP_COPY位(0010h),告訴加載器不要把.cinit段自動(dòng)加載到內存中,并且把cinit這個(gè)符號設置為-1(默認情況下符號cinit指向初始化表格),從而向啟動(dòng)程序表明,內存中沒(méi)有初始化表格,在啟動(dòng)時(shí)不需要執行運行時(shí)的初始化工作。在這種情況下,需要我們自定義一個(gè)加載程序,從而在加載程序時(shí)就完成初始化,它的主要內容包括:
ü 在目標文件中檢測.cinit段的存在;
ü 在.cinit段的開(kāi)頭配置STYP_COPY位,使得該段不會(huì )被自動(dòng)復制到內存中;
ü 需要我們理解并正確遵循初始化表格的格式。
這三個(gè)注意點(diǎn)貌似比較復雜,不過(guò)有讀者可能會(huì )問(wèn),我們在直接把程序通過(guò)JTAG下載到DSP的RAM中并運行的時(shí)候,貌似并沒(méi)有配置這么麻煩的步驟啊?那是因為CCS編程環(huán)境已經(jīng)幫我們承擔了這一重要任務(wù),在我們用仿真器來(lái)調試、運行的時(shí)候經(jīng)常會(huì )使用到這個(gè)方式。
注意:在C/C++程序運行之前,一些全局變量必須被賦予初始值。在A(yíng)NSI/ISO C中,未明確初始化的全局和靜態(tài)變量在程序執行前都需要被初始化為0,C/C++的編譯器并不會(huì )對它們進(jìn)行自動(dòng)初始化。在把程序加載到RAM而不是ROM中的情況下,比較方便的方法是直接把.bss段初始化為0。
而在C28x DSP的編程中,如果一個(gè)全局變量的初值并不會(huì )對程序的運行結果產(chǎn)生任何影響,則我們一般不用考慮給它們賦初值,因為編譯器會(huì )使用.cinit段中的初始化表格來(lái)初始化變量,叫做自動(dòng)初始化autoinitialization,其示意圖為:
在使用了--ram_model或者--rom_mode選項的情況下,鏈接器在把所有C/C++模塊中的相關(guān)變量初始化的內容鏈接入.cinit段之后,會(huì )自動(dòng)在其末尾加入null關(guān)鍵字,來(lái)標明初始化表格的末尾。
4.調用.pinit中的所有的全局構造函數。
.pinit段中的內容相對簡(jiǎn)單,它主要包含了構造的地址列表。在.cinit初始化完成之后,構造函數的地址就出現在構造函數地址列表中了。
在使用了--ram_model或者--rom_mode選項的情況下,鏈接器在把所有C/C++模塊中的構造函數的地址鏈接入.pinit段之后,會(huì )自動(dòng)在其末尾加入null關(guān)鍵字,來(lái)標明構造函數地址的結束。
與.cinit段不同的時(shí),不管使用--ram_model還是--rom_mode選項,.pinit段都會(huì )在運行時(shí)被加載和處理。
5.調用main()函數,執行我們的程序。
6.在main()函數返回時(shí),調用exit函數。
根據需要,我們可以自定義啟動(dòng)函數,但是一定要保證我們的自定義函數能夠正確完成以上的步驟以建立C/C++的實(shí)時(shí)運行庫環(huán)境,否則我們的程序將無(wú)法正常運行,甚至根本無(wú)法運行。
評論