如何用C語言開發DSP嵌入式系統

如何用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 命令定義目標系
統的存儲器,程序員可以定義每一塊存儲器並指定起始地址和長度;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
(華東交通大學) 肖宛昂曾爲民
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章