如何用C語言開發DSP嵌入式系統
來源:互聯網
上載者:User
如何用C 語言開發DSP 嵌入式系統
肖宛昂 曾為民
Xiao,Wanang Ceng,Weimin
(華東交通大學) 肖宛昂曾為民
摘要目前很多嵌入式系統以 DSP 為核心構建,但是,採用組合語言開發DSP 系統存在開發
難度大、開發週期長、維護性差等缺點,應用C 語言開發DSP 系統是廣大嵌入式開發人員的
迫切要求。有關單片機的C 語言開發有相當多的資料可以參考,而DSP 系統的C 語言開發
卻很少見。本文以TI 公司的DSP 器件TMS320F24X 系列為例,講述怎樣用C 語言開發一
個完整的DSP 嵌入式系統。
關鍵詞:嵌入式系統; DSP 系統; C 語言開發; TMS320F24X 系列
引言
大家在開發嵌入式產品時首先會想到用控制器的組合語言編寫監控程式,主要原因是:①匯
編語言產生的程式對應的二進位代碼少,程式執行要比進階語言產生的程式快;②控制器剛
問世時,沒有相應的進階語言可供使用;③儲存空間的價格問題和定址空間的限制。
以上所述問題目前已基本解決,在這就不闡述了。實際情況是:在單片機的應用領域,開發
者已開始使用C 語言進行開發。大家發現用進階語言開發嵌入式產品是如此輕鬆,並且C
語言程式編譯後的二進位代碼也非常短小精練。
目前使用最多的數位訊號處理器(DSP)是美國TI 公司的TMS320 家族,而工業控制上用
得最多的又是TMS320F2XX 系列。TI 公司為每一個DSP 晶片提供了組合語言和C 語言供
開發人員選用。本人一直使用C 語言進行產品開發,而目前很少見到這方面的介紹、所以特
撰此文,以TMS320F240 為例,向各位同行推薦用C 語言開發DSP 嵌入式系統。
1 DSP 的C 語言的特殊性
大家在使用 51 系列C 語言時已經注意到,控制器的C 語言和PC 機上使用的C 有一個顯著
的特點:經常要對硬體操作,程式中有大量針對控制器內部資源進行操作的語句。所以,開
發者要明白怎樣用C 語言來操縱控制器的內部資源,即怎樣用C 語句操作寄存器和內部存
儲器等。
舉個例子:在 51 彙編中我們寫 MOV A,#20H;組譯工具能夠識別A 是指累加器;而在
51 的C 程式中我們寫ACC=32;,編譯器能夠識別ACC 是指累加器而不是一般的變數。即
每一個寄存器都有一個專有名字供開發人員使用,它們定義在一個標頭檔reg51.h 中,程式
員只需在程式的開始部分用#include“reg51.h”語句將該檔案包含進來即可。注意:這些
寄存器的名字不能用作變數名。
同樣,在TMS320F240 的C 語言中也有一個標頭檔C240.H 定義各個寄存器的名稱,這裡
摘錄幾條語句進行介紹。
比如:#define IMR((PORT)0x0004)
#define XINTI_CR((PORT) 0x07070)
IMR、XINT1_CR 就對應兩個寄存器,實際是寄存器的地址,用進階語言的說法是指標。我
們也在程式的開始部分用#include“c240.h”語句將該檔案包含進來。這樣,在DSP 的C
語言中使用它們只需在前面加一個星號(*),例如,
*IMR=0X1010;/*將十六進位數1010H 賦給IMR 寄存器*/
*XINT1_CR=0X0A0B0;/*將十六進位數A0B0H 賦給XINT1_CR 寄存器*/
開發人員最好將c240.h 這個檔案列印出來,弄清楚各個寄存器的定義名稱。至於不涉及硬體
的文法和ANSI 文法一樣。需要注意的是,有些ANSI 標準中的函數在DSP 的編譯器中不提
供,讀者可以參考DSP 編譯器的C 語言手冊。搞清楚了這些特殊性,由組合語言轉到C 語
言開發是很容易的事。當然,沒有組合語言編程基礎的人同樣可以用C 語言開發DSP 應用
系統。
有關嵌入式系統的 C 語言編程可參考《單片機與嵌入式系統應用》2001 年1~6 期《嵌入式
C 編程技術》,本文不作討論。下面只針對以TMS320F240 晶片為處理器的嵌入式C 語言編
程進行闡述,希望能夠指導讀者進行具體操作。
2 TMS320F240 晶片的C 語言開發過程
簡單地說,整個過程包括以下 5 個步驟:
①編輯 C 語言來源程式;
②編譯來源程式(注意編譯參數);
③連結目標檔案(注意用 CMD 檔案);
④線上模擬;
⑤固化程式。
2.1 來源程式的編輯
可以用任何一個編輯器書寫來源程式,如 EDIT。NOTEPAD 等,最後以.C 為尾碼存檔。源
代碼可以寫在一個C 檔案中,也可寫在多個C 檔案中;有些預定義變數和函數原型聲明可
以集中放在一個標頭檔中。
注意事項:不要忘記在 C 程式的前面用#in-clude “c240.h”將寄存器定義檔案包括進
來。
2.2 來源程式的編譯
來源程式編輯好後可以用 DSPCL 編譯器進行編譯,產生OBJ 檔案。
使用格式:DSPCL 源檔案名稱參數
例如: DSPCL EX1.C-V2XX-GK-MN
常用參數的意義:
V2XX——表示C 編譯器選擇處理器2XX 系列;
GK——保留編譯產生的彙編檔案(.ASM 檔案);
MN——進行正常最佳化。
其它參數請參考 DSP 編譯器的手冊。如果有多個源檔案分別編譯,每一個源檔案經編譯後
產生一個OBJ 檔案和ASM 檔案。
2.3 目標檔案的連結
2.3.1 TI 公司的COFF 檔案格式
TI 公司新的彙編器和編譯器建立的目標檔案採用COFF(Common Object File Format)的目
標檔案格式。採用COFF 格式有利於模組化編程,為管理程式碼片段和目標系統儲存空間提供更加
有力和靈活的方法。基於COFF 格式編寫組譯工具或C 語言程式時,不必為程式碼和變
量指定目標地址;為程式編寫和程式移植提供了極大的方便。
COFF 格式的基本思想是:鼓勵程式員在用組合語言或C 語言編程時運用代碼塊和資料區塊的
概念。這種塊稱為SECTION,是目標檔案中的最小單位。
所有的塊分為兩大類:已初始化塊和未初始化塊。已初始化塊包含程式碼和資料,未初始
化塊是為未初始化的資料在儲存空間中的保留塊。C 編譯器對C 程式編譯後產生已初始化塊
和未初始化塊,已初始化塊如.text 塊、.const 塊、.cinit 塊;未初始化塊如.bss 塊。
舉個例子,當程式員用 C 語句float data[100];定義一個數組時,不需要指定這100 個數
組元素的具體位置,編譯器會在資料區預留所需空間。到連結時連結器會具體定位。
2.3.2 連結器對塊的處理
連結器對塊的處理有兩個功能:其一,將 COFF 目標檔案中的塊用來建立程式塊和資料區塊,
並將這些塊組合成可以被DSP 晶片執行的COFF 輸出模組;其二,連結器為輸出塊指定存
儲位置。
連結器提供兩個命令實現上述功能:MEMORY 和SECTIONS。MEMORY 命令定義目標系
統的儲存空間,程式員可以定義每一Block Storage器並指定起始地址和長度;SECTIONS 命令用來定
義輸入塊的組合和輸出塊在儲存空間中的存放位置。若不用MEMORY 和SECTIONS 命令,
連結器採用預設的分配演算法。推薦使用這兩個命令,但要注意這兩個命令在CMD 檔案(鏈
接器命令檔案)中使用。
下面分析一個 TMS320F240 晶片的典型CMD 檔案。(假設檔案名稱 EX1.CMD。)
(1)CMD 檔案的構成及其詳細解釋
BOOT.OBJ /*F240 的中斷向量表,參見後面的說明*/
EX1.OBJ /*來源程式編譯後對應的目標檔案*/
/*若程式有多個目標檔案,一塊寫在這裡*/
-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 初始化表的存放位置*/
.text: load=ROM2 /*系統程式的存放位置*/
.bSS load=RAM_B0 /*未初始化資料的存放位置*/
.const load=RAM_B1 *已初始化資料的存放位置*/
}
(2)TMS320F240 連結時所需的中斷向量表檔案
TMS320F240 的目標檔案在連結時要用到中斷向量表。中斷向量表用組合語言編寫,和具體
的DSP 晶片有關。假設TMS320F240 的中斷向量表對應的組譯工具為BOOT.ASM,彙編
後的檔案名稱為BOOT.OBJ。
下面是一個典型的向量表檔案。(假設程式名為BOOT.ASM。)
.port /*定義中斷函數的名字*/
.globl_c_int0 /*中斷0 對應的函數名*/
.globl_c_int1 /*中斷1 對應的函數名,以下語句的意義相同*/
.globl_c_int2 /*可以將中斷函數名看作中斷入口地址*/
.globl_c_int3 /*向量表的存放不需程式員幹預*/
.globl_c_int4
.globl_c_int5
.globl_c_int6
.globl_c_int7
.globl_c_int8
·sect“.vectors”/*用.sect 命令自訂一個塊,用於存放中斷向量表*/
RSVECT B _c_int0 /*中斷0 發生後,程式的跳轉目的地址*/
INT1 B _c_int1 /*中斷1 發生後,則跳到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 來源程式中編寫中斷函數:
voidc_inx() /*x 為1~8 中之一*/
{
中斷程式的 C 語句系列;
}
注意事項:c_int0()是系統入口函數,使用者不能編寫。
經過上面對命令檔案(CMD 檔案)和中斷向量表的介紹,接下來可以連結命令檔案來產生
所需要的OUT 檔案供DSP 晶片執行或進行軟模擬。
命令形式:DSPLNK CMD 檔案名稱
例如:DSPLNK EX1.CMD
另一種情況是,不使用CMD 檔案,使用預設配置,簡單介紹如下:
命令形式:DSPLNK OBJ 檔案名稱參數
例如:DSPLNK EX1.OBJ BOOT.OBJ-O XX1.OUT-M XX1.MAP
以上三步可以用圖1 描述。
2.4 程式的模擬
用 EMURST 模擬器複位命令
EMU2XXW EX1.OUT
載入COFF 格式的二進位代碼模擬運行。有關調試器的使用略。
2.5 程式的固化
程式模擬運行正確後,需要固化到Flash ROM 中。TMS320F240 內部有16K 字的Flash ROM
可以用來固化程式,而不需要外擴EPROM(程式不大於16K 字的情況下)。
TI 公司提供有固化程式的軟體,可以通過模擬器經JTAG 口將程式寫入晶片內、目前發展
了一種新的固化技術,可以通過串口寫入DSP 晶片,特別適合於現場調試。下面介紹通過
JTAG 口的固化方法。
首先用 EMURST 命令複位調試器,然後執行下面三個批次檔。
第一步,執行 BCO.BAT 批次檔,將FlashROM 清除(CLEAR),使全為0。
第二步,執行 BE0.BAT 批次檔,將FlashROM 擦除(ERASE),使全為1。
(以上兩步不需要修改軟體包中內建的這兩個 BAT 檔案。)
第三步,執行BP16K.BAT 批次檔,將自己的OUT 檔案寫入到DSP 內部的Flash ROM
中。執行這一步之前,要先修改BP16K,BAT,將待寫入的OUT 檔案替換成自己的OUT
檔案。下面看一下這個批次檔。假設軟體包的安裝目錄為C:\DSP,該目錄下有一個子
目錄SRC。
prg2xx-p240-m0x0006-w6src\c2xx_bpx.out 要寫入的OUT 檔案
如果要將 EX1.OUT 寫入到DSP 的Flash 中,則執行下面的命令:
prg2xx-p240-m0x0006-w6src\c2xx_bpX.out c:\dsp\EX1.out
經過以上步驟即完成了程式固化,可以將系統放到現場實驗了。
注意:固化程式時,CPU 一定要工作在20MHz 的頻率下。在SRC 子目錄下有一個配置文
件C240_CFG.I,讀者可以根據程式說明並結合自己系統的外部晶振頻率將CPU 的工作
頻率設為20MHz(寫入時的頻率)。
本文以 TMS320F240 的開發為例,介紹了怎樣用C 語言開發DSP 系統的全過程。希望對讀
者會有所啟發和協助。
參考文獻
[1]Texas Instruments . TMS320F/C24XDSP Con-trollers Peripheral Library And Specific
Devive.1999
[2]Texas Instrument.TMS320C2X/C5X OptimizingC Compiler User’s Guide.1994
[3]張雄偉.DSP 晶片的原理與開發應用.北京:電子工業出版社, 2001
[4]章雲.DSP 控制器及其應用.北京:機械工業出版社, 2001
(華東交通大學) 肖宛昂曾為民