嵌入式C語(yǔ)言開(kāi)發(fā)ADSP21XX系列DSP
關(guān)鍵詞:DSP VisualDSP 嵌入式C語(yǔ)言 匯編語(yǔ)言
引言
長(cháng)期以來(lái),在DSP系統開(kāi)發(fā)中,一直把匯編語(yǔ)言作為主要的開(kāi)發(fā)工具;但匯編語(yǔ)言與自然語(yǔ)言差距很大,不易常,而且匯編語(yǔ)言是依賴(lài)于處理器的,不利于軟件的可重復利用和系統的穩定性,程序不易移植,給開(kāi)發(fā)工作帶來(lái)了很大的困難。隨著(zhù)嵌入式系統復雜程度的不斷提高,用匯編語(yǔ)言編寫(xiě)一個(gè)巨大的程度將是困難,甚至是不可能的。為此,AD公司推出了針對ADSP21XX系列DSP的嵌入式C和C++語(yǔ)言集成開(kāi)發(fā)工具,分別是VisualDSP和VisualDSP++系列,這些開(kāi)發(fā)工具提供了C語(yǔ)言和C++語(yǔ)音的開(kāi)發(fā)功能。以下就以筆者在實(shí)際開(kāi)發(fā)中的一些經(jīng)驗,結合VisualDSP6.1版本,介紹用C語(yǔ)言開(kāi)發(fā)VisualDSP6.1版本,介紹用C語(yǔ)言開(kāi)發(fā)ADSP21XX的方法。VisualDSP提供了一個(gè)開(kāi)放源碼軟件組織GNU的C編譯器,和一套成熟穩定的C運行時(shí)間庫(C Run time Library)等。GNU的編譯器一向以編譯效率高著(zhù)稱(chēng),在編譯后的代碼長(cháng)度和運行速度方面非常優(yōu)秀;C運行時(shí)間庫則把很多重復性的工作,如浮點(diǎn)運行、三角函數、FFT等作為C語(yǔ)言的庫函數,提供給用戶(hù),大大提高了用戶(hù)的開(kāi)發(fā)效率和程序的穩定性,降低了開(kāi)發(fā)難度,另外,由于把這些庫函數的源代碼提供給了用戶(hù),還提高了C語(yǔ)言與匯編語(yǔ)言之間的透明性,使用戶(hù)開(kāi)發(fā)的程序兼具兩者的優(yōu)點(diǎn)。
1 Visual DSP簡(jiǎn)介
VisualDSP是AD公司的DSP開(kāi)發(fā)工具,主要由可執行文件、庫文件和各種幫助文檔組成。6.1版本還帶有一個(gè)基于圖形界面,針對21XX系列DSP的軟件仿真和調試工具。
VisualDSP的可執行文件包括匯編、編譯、鏈接工具以及可執行文件重新格式化工具等,見(jiàn)表1。
表1 VisualDSP的可執行文件及用途
可執行文件名 | 用 途 |
Asmpp.exe* | 匯編預處理程序 |
Asm2.exe* | 21XX系列匯編程序的匯編程序 |
Asm21.exe | 21XX系列命令行匯編程序 |
Ld21.exe | 21XX系列鏈接工具 |
G21.exe | 基于GNU的21XX系列C編譯器 |
Bld21.exe | 系統編譯工具,產(chǎn)生相應于不同硬件體系的.ACH文件 |
Lib21.exe | 21XX系列的庫管理工具 |
Hspl21.exe | 把21XX系列可執行文件變成HIP口可加載的格式 |
Spl21.exe | 把21XX系列可執行文件變成PROM可燒寫(xiě)的格式 |
注:“*”代表該程序一般不單獨使用,而昌由G21.exe或Asm21.exe調用。
VisualDSP套件中的軟件仿真調試工具DEBUGAPP,采用Windows圖形界面,使用方便。它的主要特點(diǎn)是:可以仿真調試從ADSP2101~2189全系列的DSP;支持斷點(diǎn)、單步、全速運行等各種常見(jiàn)調試方法;可以隨時(shí)查詢(xún)和修改DSP的程序RAM(PM)、數據RAM(DM)和各寄存器的內容;可以仿真中斷,進(jìn)行可執行程序性能評估(Profile),因此可以進(jìn)行時(shí)序仿真。DEBUGAPP是調試程序和驗證復雜算法的極好工具。
VisualDSP6.1還提供了豐富的幫助文檔,包括21XX系列的用戶(hù)手冊、匯編和C語(yǔ)言工具以及仿真調試程序的使用手冊;還有C運行庫的參考手冊,列出了所有可用的C庫函數。用C語(yǔ)言開(kāi)發(fā)DSP的典型流程如圖1所示。
2 C語(yǔ)言運行庫結構
C語(yǔ)言運行時(shí)間庫是位于LIB目錄下的*.a文件,是整個(gè)C開(kāi)發(fā)工具的核心之一,提供了大量的可以直接調用的庫函數。這些庫函數的函數原型包含在INCLUDE目錄下的頭文件中。這些頭文件有的還包含一些宏定義。另外,VisualDSP還把這些庫函數的匯編語(yǔ)言源代碼提供給出了用戶(hù),方便了用戶(hù)從中提取有用的代碼,甚至修改源代碼,生成新的庫,來(lái)適應自己的要求。利用LIB21程序,還可以把自己的常用匯編子程序做成庫,或是將實(shí)時(shí)性要求較高的代碼用匯編語(yǔ)言來(lái)寫(xiě),做成庫,供C語(yǔ)言程序調用。
VisualDSP的C語(yǔ)言運行庫由兩部分組成:應用程序框架和預定義的各種庫函數。
不同的DSP型號有不同的硬件結構、中斷向量表,所以對應的應用程序框架庫也不同,相應的文件是21*_HDR.DSP.其中*代表不同的DSP型號。應用程序框架的主體是中斷向量處理部分,把中斷向量引到合適的地址。其中最重要的是對系統復位(RESET_VECTOR)的中斷向量的處理:
_Reset_vector:CALL_lib_setup_everything;
CALL main_;
JUMP_lib_prog_term;
NOP;
第一條指令是調用C庫函數中的_ _lib_setup_everything函數作程序啟動(dòng)時(shí)的初始化工作。接下來(lái),調用C語(yǔ)言程序中的main_函數,進(jìn)入C程序的主體,也就是進(jìn)入用戶(hù)自己程序,開(kāi)始正常工作。主程序結束后,再調用_lib_prog_term函數,作程序退出時(shí)的結尾工作。由于嵌入式系統的特性,系統絕大多數都在主程序運行時(shí)被繼電了,所以_lib_prog_term得到執行的機會(huì )很小。
其它的中斷向量由C運行庫來(lái)管理,匯編指令如下:
_Interrupt2:JUMP_lib_int2_ctrl;NOP;NOP;NOP;
其中的_lib_int2_crtl就是C語(yǔ)言庫中控制INT2的函數。如果用戶(hù)要使用該中斷,應先把中斷服務(wù)程序用一個(gè)C庫函數Interrupt()把服務(wù)函數指針設定好,并打開(kāi)相應的中斷允許位,當該中斷發(fā)生時(shí),_lib_int2_ctr1函數就會(huì )控制DSP跳轉到相應的指針位置。
VisualDSP預定義的C語(yǔ)言庫函數包括數學(xué)函數、FFT函數、ANSI標準內存管理和字符串管理函數的一個(gè)子集。所有的函數列表可參考VisualDSP的聯(lián)機文檔。這些庫函數以二進(jìn)制代碼的形式,打包集合在lib*.a文件中,用戶(hù)的C語(yǔ)言程序可以像使用自己的子程序一樣方便地調用這些庫函數。下面是調用庫函數的一個(gè)例子。
#includemath.h> //包含所需的頭文件
……
float a,b,c; //定義所需的變量
……
c=a*sin(b); //數學(xué)運算
編譯后產(chǎn)生的匯編源代碼中有call sin_指令,就是調用sin庫函數的匯編語(yǔ)言指令語(yǔ)句。
從嵌入式開(kāi)發(fā)的角度講,VisualDSP的C語(yǔ)言工具已經(jīng)提供了一個(gè)操作系統雛形的功能。在A(yíng)D公司的ADMC系列DSP中,已經(jīng)把這些庫函數和一些電機控制專(zhuān)用的函數,以及程序加載功能,集成在了DSP的片內ROM中。
3 C語(yǔ)言與匯編語(yǔ)言混合編程方法
用C語(yǔ)言開(kāi)發(fā)的缺點(diǎn)是不能精確控制程序運行的時(shí)間,對于實(shí)時(shí)性要求較高的應用,必須用匯編語(yǔ)言。VisualDSP為用戶(hù)提供了兩種與匯編語(yǔ)言的接口方法:用ASM()方法,直接嵌入匯編語(yǔ)言語(yǔ)句;用匯編語(yǔ)言編寫(xiě)子程序,供C語(yǔ)言程序調用。為了支持C語(yǔ)言與匯編程序程序的接口,VisualDSP預定義了諸如FUNCTION_ENTRY、EXIT、SAVE_REG、RESTORE_REG等13個(gè)宏。限于篇幅,不詳細介紹其功能。使用這些宏以前,要包含asm_sprt.h頭文件。
3.1 使用ASM()嵌入行的方法
使用這一方法時(shí),一定要注意各寄存器和堆棧當前的狀態(tài),以免破壞程序運行的環(huán)境,產(chǎn)生錯誤的結果。VisualDSP保留了一些內部寄存器供用戶(hù)的匯編代碼使用。用戶(hù)可以自由地修改其內容,而不會(huì )對程序造成破壞。這些寄存器包括AR、AF、AY1、M5、11、16、MF、MR0等18個(gè)。如果不夠用,可以用系統定義的宏save_reg和restore_reg保護現場(chǎng),得到另外11個(gè)可用寄存器。另外要注意的是,在匯編語(yǔ)言中操作C語(yǔ)言中定義的變量時(shí),要在變量名后加下劃線(xiàn)。下面是一個(gè)嵌套匯編語(yǔ)言的例子:
int img228; //定義C語(yǔ)言變量
asm("ax0=0x5c;")
asm("dm(ing228_)=ax0"); //用匯編語(yǔ)言賦值要將Img228變成Img228_
img228=0x5c; //直接用C語(yǔ)言賦值
編譯后的匯編語(yǔ)言代碼是
ax0=0x5c;
dm(img228_)=ax0
my1=92;
dm(img228_)=my1;
注意前者可能會(huì )破壞程序結構,因為它使用了未經(jīng)保護的寄存器AX0;而由C語(yǔ)言產(chǎn)生的匯編代碼,則會(huì )自動(dòng)選擇合適的臨時(shí)寄存器MY1。
3.2 使用匯編子程序的方法
使用匯編子程序是C語(yǔ)言程序與匯編語(yǔ)言接口的另一種方法。用戶(hù)定義的子程序放在單獨的匯編文件中,或是做成二進(jìn)制的庫文件,并將子程序的定義用GLOBEL輸出,匯編后就可以供C語(yǔ)言程序調用。下面是一個(gè)不需要參數的子程序的例子:
.MODULE/RAM_delay_;
.external del_cycle; //聲明del_cycle是外部變量
.global delay; //聲明delay為全局函數
delay_:
runction_entry; //子程序開(kāi)始標志,必須要的
ar=dm(del_cycle_);
cntr=ar;
do d_loop until ce;
d_loop:nop;
exit; //子程序結束標志,必須要的
.ENDMOD;
如果匯編語(yǔ)言子程序中用到了參數,情況就復雜些。子程序中的入口參數前兩個(gè)一定要保存在A(yíng)R、AY1中。如果參數多于兩個(gè)就要把其余的放在堆棧中。所有子程序的第一個(gè)返回值放在A(yíng)R中。如果返回值不止一個(gè),就要用到變量型參數或者指針來(lái)獲得取所有的返回值了。下面是一個(gè)有5個(gè)輸入參數、1個(gè)返回值的子程序例子。
add5_:
function_entry;
ar=ar+ay1; //前面的兩個(gè)變量放在A(yíng)R、AY1中
readsfirst(ay1); //從程序堆棧中讀取第三個(gè)變量
ar=ar+ay1;
ay1=readsnext; //從程序堆棧中讀取第四個(gè)變量
ar=ar+ay1;
ay1=readsnext; //從程序堆棧中讀取第五個(gè)變量
ar=ar+ay1; //返回值放在A(yíng)R中
exit;
注意其中的readsfirst和readsnext都是匯編語(yǔ)言接口宏。其功能是從堆棧中讀取所有的參數。
4 C運行庫的匯編源代碼
如果只用C語(yǔ)言來(lái)開(kāi)發(fā)21XX程序,只要有C運行庫的二進(jìn)制版就夠了。幸運的是,AD公司把所有C運行庫的匯編源代碼隨VisualDSP提供給了用戶(hù),所以對那些用匯編語(yǔ)言開(kāi)發(fā)的工程師來(lái)說(shuō),這些源代碼也提供了很大的幫助。因此這代表很多功能的子程序不需要自己去編碼、調試,用到某功能時(shí)只要把相應的匯編代碼鏈接進(jìn)自己的程序就可以。C運行庫的源代碼是擴展名為DSP的文本文件?;旧弦粋€(gè)庫函數對應一個(gè)文件,文件名就是函數名。比如說(shuō)sin.dsp是正弦、余弦查找、使用都很方便,但是對于其中的交叉調用要注意。
反過(guò)來(lái),用戶(hù)也可以把自己已經(jīng)調試、驗證過(guò)的匯編子程序,做成二進(jìn)制庫文件,供C程序調用,這樣可以大大提高軟件的可重復利用率。要制作二進(jìn)制庫文件,只要用lib21.exe工具處理就行了。注意,生成的二制庫文件的名字必須以.a作為文件擴展名。
筆者在實(shí)際的開(kāi)發(fā)中,遇到這樣的情況,自制的2181目標板上有一個(gè)自己開(kāi)忍氣吞聲駐留程序,通過(guò)軟件模擬的異步串口與PC通信,加載程序。但是這個(gè)駐留程序占據了0~0x500的空間,用戶(hù)開(kāi)發(fā)的程序只能加載到從0x500開(kāi)始的空間內,而用C語(yǔ)言開(kāi)發(fā)的程序起始地址都是從0開(kāi)始的。為了解決這個(gè)問(wèn)題,只能自己修改2181_hdr.dsp源文件。首先把第一行的.MODULE/ABS=0改成.MODULE/ABS=0x500,然后匯編成obj文件,代替原來(lái)的文件。另外,在自己的程序中定義一個(gè)從0開(kāi)始0x500大小的PM區域,并初始化成0,就可以防止編譯器在該區域內分配別的變量或程序代碼,這樣編譯后的可執行文件的0~0x500空間都是0,加載時(shí)把它剔除,而其它有用的指令代碼都在0x500之后,解決了這一個(gè)問(wèn)題。
5 總結
從實(shí)際開(kāi)發(fā)的經(jīng)驗來(lái)看,VisualDSP的C語(yǔ)言開(kāi)發(fā)功能十分豐富。雖然提供的庫函數只是ANSI的一個(gè)不完備子集,但是對于一般的工程開(kāi)發(fā)來(lái)說(shuō)已經(jīng)足夠用了,而且VisualDSP還提供了C運行庫的源代碼,這對于解決函數不完備的問(wèn)題也好處。用C語(yǔ)言開(kāi)發(fā)的好處還包括開(kāi)發(fā)時(shí)間大大減少,程序的穩定性大大提高,這對于面對激烈的市場(chǎng)競爭,對于減輕設計工程師的工作量都很有好處。最后,用C語(yǔ)言開(kāi)發(fā)是趨勢,必將更加流行。
linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)c語(yǔ)言相關(guān)文章:c語(yǔ)言教程
c++相關(guān)文章:c++教程
評論