如何用C語(yǔ)言開(kāi)發(fā)DSP嵌入式系統
引言
以上所述問(wèn)題目前已基本解決,在這就不闡述了。實(shí)際情況是:在單片機的應用領(lǐng)域,開(kāi)發(fā)者已開(kāi)始使用C語(yǔ)言進(jìn)行開(kāi)發(fā)。大家發(fā)現用高級語(yǔ)言開(kāi)發(fā)嵌入式產(chǎn)品是如此輕松,并且C語(yǔ)言程序編譯后的二進(jìn)制代碼也非常短小精練。
目前使用最多的數字信號處理器(DSP)是美國TI公司的TMS320家族,而工業(yè)控制上用得最多的又是TMS320F2XX系列。TI公司為每一個(gè)DSP芯片提供了匯編語(yǔ)言和C語(yǔ)言供開(kāi)發(fā)者選用。本人一直使用C語(yǔ)言進(jìn)行產(chǎn)品開(kāi)發(fā),而目前很少見(jiàn)到這方面的介紹、所以特撰此文,以TMS320F240為例,向各位同行推薦用C語(yǔ)言開(kāi)發(fā)DSP嵌入式系統。
1 DSP的C語(yǔ)言的特殊性
大家在使用51系列C語(yǔ)言時(shí)已經(jīng)注意到,控制器的C語(yǔ)言和PC機上使用的C有一個(gè)顯著(zhù)的特點(diǎn):經(jīng)常要對硬件操作,程序中有大量針對控制器內部資源進(jìn)行操作的語(yǔ)句。所以,開(kāi)發(fā)者要明白怎樣用C語(yǔ)言來(lái)操縱控制器的內部資源,即怎樣用C語(yǔ)句操作寄存器和內部存儲器等。
舉個(gè)例子:在51匯編中我們寫(xiě) MOV A,#20H;匯編程序能夠識別A是指累加器;而在51的C程序中我們寫(xiě)ACC=32;,編譯器能夠識別ACC是指累加器而不是一般的變量。即每一個(gè)寄存器都有一個(gè)專(zhuān)有名字供開(kāi)發(fā)者使用,它們定義在一個(gè)頭文件reg51.h中,程序員只需在程序的開(kāi)始部分用#include“reg51.h”語(yǔ)句將該文件包含進(jìn)來(lái)即可。注意:這些寄存器的名字不能用作變量名。
同樣,在TMS320F240的C語(yǔ)言中也有一個(gè)頭文件C240.H定義各個(gè)寄存器的名稱(chēng),這里摘錄幾條語(yǔ)句進(jìn)行介紹。
比如:#define IMR((PORT)0x0004)
?。efine XINTI_CR((PORT) 0x07070)
IMR、XINT1_CR就對應兩個(gè)寄存器,實(shí)際是寄存器的地址,用高級語(yǔ)言的說(shuō)法是指針。我們也在程序的開(kāi)始部分用#include“c240.h”語(yǔ)句將該文件包含進(jìn)來(lái)。這樣,在DSP的C語(yǔ)言中使用它們只需在前面加一個(gè)星號(*),例如,
*IMR=0X1010;/*將十六進(jìn)制數1010H賦給IMR寄存器*/
*XINT1_CR=0X0A0B0;/*將十六進(jìn)制數A0B0H賦給XINT1_CR寄存器*/
開(kāi)發(fā)者最好將c240.h這個(gè)文件打印出來(lái),弄清楚各個(gè)寄存器的定義名稱(chēng)。至于不涉及硬件的語(yǔ)法和ANSI語(yǔ)法一樣。需要注意的是,有些ANSI標準中的函數在DSP的編譯器中不提供,讀者可以參考DSP編譯器的C語(yǔ)言手冊。搞清楚了這些特殊性,由匯編語(yǔ)言轉到C語(yǔ)言開(kāi)發(fā)是很容易的事。當然,沒(méi)有匯編語(yǔ)言編程基礎的人同樣可以用C語(yǔ)言開(kāi)發(fā)DSP應用系統。
有關(guān)嵌入式系統的C語(yǔ)言編程可參考《單片機與嵌入式系統應用》2001年1~6期《嵌入式C編程技術(shù)》,本文不作討論。下面只針對以TMS320F240芯片為處理器的嵌入式C語(yǔ)言編程進(jìn)行闡述,希望能夠指導讀者進(jìn)行具體操作。
2 TMS320F240芯片的C語(yǔ)言開(kāi)發(fā)過(guò)程
簡(jiǎn)單地說(shuō),整個(gè)過(guò)程包括以下5個(gè)步驟:
?、倬庉婥語(yǔ)言源程序;
?、诰幾g源程序(注意編譯參數);
?、坻溄幽繕宋募ㄗ⒁庥肅MD文件);
?、茉诰€(xiàn)仿真;
?、莨袒绦?。
2.1源程序的編輯
可以用任何一個(gè)編輯器書(shū)寫(xiě)源程序,如EDIT。NOTEPAD等,最后以.C為后綴存盤(pán)。源代碼可以寫(xiě)在一個(gè)C文件中,也可寫(xiě)在多個(gè)C文件中;有些預定義變量和函數原型聲明可以集中放在一個(gè)頭文件中。
注意事項:不要忘記在C程序的前面用 #in-clude “c240.h”將寄存器定義文件包括進(jìn)來(lái)。
2.2源程序的編譯
源程序編輯好后可以用DSPCL編譯程序進(jìn)行編譯,生成OBJ文件。
使用格式:DSPCL源文件名 參數
例如: DSPCL EX1.C-V2XX-GK-MN
常用參數的意義:
V2XX——表示C編譯器選擇處理器2XX系列;
GK——保留編譯生成的匯編文件(.ASM文件);
MN——進(jìn)行正常優(yōu)化。
其它參數請參考DSP編譯器的手冊。如果有多個(gè)源文件分別編譯,每一個(gè)源文件經(jīng)編譯后產(chǎn)生一個(gè)OBJ文件和ASM文件。
2.3 目標文件的鏈接
2.3.1 TI公司的COFF文件格式
TI公司新的匯編器和編譯器創(chuàng )建的目標文件采用COFF(Common Object File Format)的目標文件格式。采用COFF格式有利于模塊化編程,為管理代碼段和目標系統存儲器提供更加有力和靈活的方法?;贑OFF格式編寫(xiě)匯編程序或C語(yǔ)言程序時(shí),不必為程序代碼和變量指定目標地址;為程序編寫(xiě)和程序移植提供了極大的方便。
COFF格式的基本思想是:鼓勵程序員在用匯編語(yǔ)言或C語(yǔ)言編程時(shí)運用代碼塊和數據塊的概念。這種塊稱(chēng)為SECTION,是目標文件中的最小單位。
所有的塊分為兩大類(lèi):已初始化塊和未初始化塊。已初始化塊包含程序代碼和數據,未初始化塊是為未初始化的數據在存儲器中的保留塊。C編譯器對C程序編譯后產(chǎn)生已初始化塊和未初始化塊,已初始化塊如.text塊、.const塊、.cinit塊;未初始化塊如.bss塊。
舉個(gè)例子,當程序員用C語(yǔ)句float data[100];定義一個(gè)數組時(shí),不需要指定這100個(gè)數組元素的具體位置,編譯器會(huì )在數據區預留所需空間。到鏈接時(shí)鏈接器會(huì )具體定位。
2.3.2 鏈接器對塊的處理
下面分析一個(gè)TMS320F240芯片的典型CMD文件。(假設文件名 EX1.CMD。)
?。?)CMD文件的構成及其詳細解釋
BOOT.OBJ /*F240的中斷矢量表,參見(jiàn)后面的說(shuō)明*/
EX1.OBJ /*源程序編譯后對應的目標文件*/
/*若程序有多個(gè)目標文件,一塊寫(xiě)在這里*/
-STACK 0X400 /*設定系統堆棧*/
-C /*ROM初始化*/
-O EX1.OUT /*輸出的文件名*/
-M EX1.MAP /*輸出映像文件名*/
-L RTS2XX.LIB /*漣接RTS2XX.LIB庫*/
MEMORY /*MEMORY命令規定系統的存儲器配置*/
{
PAGEO:ROM0:origin=0000h,length=003fh
/*FLASH ROM*/
PAGE0:ROM1:origin=0040h,length=0200h
/*FLASH ROM*/
PAGEO:ROM2:origin=0240h,length=3000h
/*FLASH ROM*/
PAGE1:RAM_B2:origin=0060h,length=0020h
/*內部RAMB2*/
PAGE1:RAM_B1:origin=0300h,length=0100h
/*內部RAM B1*/
PAGE1:RAM_B0:origin=0100h,length=0100h
/*內部RAM B0*/
PAGE1:RAM_EX:origin=0d000h,length=2800h
/*外部擴展RAM*/
}
SECTIONS /*SECTIONS命令規定了程序中塊的具體分配方法*/
{
.vectors:load=ROM0 /*規定矢量表的存放位置*/
.cinit:load=rom1 /*C初始化表的存放位置*/
?。畉ext: load=ROM2 /*系統程序的存放位置*/
.bSS load=RAM_B0 /*未初始化數據的存放位置*/
.const load=RAM_B1 *已初始化數據的存放位置*/
}
?。?)TMS320F240鏈接時(shí)所需的中斷矢量表文件
TMS320F240的目標文件在鏈接時(shí)要用到中斷矢量表。中斷矢量表用匯編語(yǔ)言編寫(xiě),和具體的DSP芯片有關(guān)。假設TMS320F240的中斷矢量表對應的匯編程序為BOOT.ASM,匯編后的文件名為BOOT.OBJ。
下面是一個(gè)典型的矢量表文件。(假設程序名為BOOT.ASM。)
.port /*定義中斷函數的名字*/
.globl_c_int0 /*中斷0對應的函數名*/
.globl_c_int1 /*中斷1對應的函數名,以下語(yǔ)句的意義相同*/
.globl_c_int2 /*可以將中斷函數名看作中斷入口地址*/
.globl_c_int3 /*矢量表的存放不需程序員干預*/
.globl_c_int4
.globl_c_int5
.globl_c_int6
.globl_c_int7
.globl_c_int8
·sect“.vectors”/*用.sect命令自定義一個(gè)塊,用于存放中斷矢量表*/
RSVECT B _c_int0 /*中斷0發(fā)生后,程序的跳轉目的地址*/
INT1 B _c_int1 /*中斷1發(fā)生后,則跳到c_int1()函數處*/
INT2 B _c_int2 /*意義同上,下同*/
INT3 B _c_int3
INT4 B _c_int4
INT5 B _c_int5
INT6 B _c_int6
用匯編器匯編該程序,命令形式:DSPABOOT.ASM-V2XX生成BOOT.OBJ文件供鏈接器使用。這樣,就可以按如下形式在C源程序中編寫(xiě)中斷函數:
voidc_inx() /*x為1~8中之一*/
?。?/P>
中斷程序的C語(yǔ)句系列;
?。?/P>
注意事項:c_int0()是系統入口函數,用戶(hù)不能編寫(xiě)。
經(jīng)過(guò)上面對命令文件(CMD文件)和中斷矢量表的介紹,接下來(lái)可以鏈接命令文件來(lái)生成所需要的OUT文件供DSP芯片執行或進(jìn)行軟仿真。
命令形式:DSPLNK CMD文件名
例如:DSPLNK EX1.CMD
另一種情況是,不使用CMD文件,使用缺省配置,簡(jiǎn)單介紹如下:
命令形式:DSPLNK OBJ文件名參數
例如:DSPLNK EX1.OBJ BOOT.OBJ-O XX1.OUT-M XX1.MAP
以上三步可以用圖1描述。
2.4程序的仿真
用EMURST仿真器復位命令
EMU2XXW EX1.OUT
載入COFF格式的二進(jìn)制代碼仿真運行。有關(guān)調試器的使用略。
2.5程序的固化
程序仿真運行正確后,需要固化到Flash ROM中。TMS320F240內部有16K字的Flash ROM可以用來(lái)固化程序,而不需要外擴EPROM(程序不大于16K字的情況下)。
TI公司提供有固化程序的軟件,可以通過(guò)仿真器經(jīng)JTAG口將程序寫(xiě)入芯片內、目前發(fā)展了一種新的固化技術(shù),可以通過(guò)串口寫(xiě)入DSP芯片,特別適合于現場(chǎng)調試。下面介紹通過(guò)JTAG口的固化方法。
首先用EMURST命令復位調試器,然后執行下面三個(gè)批處理文件。
第一步,執行BCO.BAT批處理文件,將FlashROM清除(CLEAR),使全為0。
第二步,執行BE0.BAT批處理文件,將FlashROM擦除(ERASE),使全為1。
?。ㄒ陨蟽刹讲恍枰薷能浖凶詭У倪@兩個(gè)BAT文件。)
第三步,執行BP16K.BAT批處理文件,將自己的OUT文件寫(xiě)入到DSP內部的Flash ROM中。執行這一步之前,要先修改BP16K,BAT,將待寫(xiě)入的OUT文件替換成自己的OUT文件。下面看一下這個(gè)批處理文件。假設軟件包的安裝目錄為C:DSP,該目錄下有一個(gè)子目錄SRC。
prg2xx-p240-m0x0006-w6srcc2xx_bpx.out要寫(xiě)入的OUT文件
如果要將EX1.OUT寫(xiě)入到DSP的Flash中,則執行下面的命令:
prg2xx-p240-m0x0006-w6srcc2xx_bpX.out c:dspEX1.out
經(jīng)過(guò)以上步驟即完成了程序固化,可以將系統放到現場(chǎng)實(shí)驗了。
注意:固化程序時(shí),CPU一定要工作在20MHz的頻率下。在SRC子目錄下有一個(gè)配置文件C240_CFG.I,讀者可以根據程序說(shuō)明并結合自己系統的外部晶振頻率將CPU的工作頻率設為20MHz(寫(xiě)入時(shí)的頻率)。
本文以TMS320F240的開(kāi)發(fā)為例,介紹了怎樣用C語(yǔ)言開(kāi)發(fā)DSP系統的全過(guò)程。希望對讀者會(huì )有所啟發(fā)和幫助。
c語(yǔ)言相關(guān)文章:c語(yǔ)言教程
評論