本文只要是關于TMS320C6000和DSP的相關介紹,并著重對TMS320C6000系列中斷設置問題進行了詳盡的闡述。
DSP
隨著DSP(數字信號處理器)系統的廣泛應用,其程序規模也隨之不斷擴大,使用芯片本身自帶的Boot-loader通過Flash存儲器來引導DSP程序,往往受到程序大小和結構的制約,比如程序很大超過廠商固化boot的范圍,再如中斷向量表的不同位置對程序boot跳轉的影響,等等,因此越來越需要更加靈活的引導方式。
系統上電后,由引導程序將DSP的應用程序從該存儲器引導到DSP應用板上的高速存儲器(如內部SRAM、SDRAM等)中。由于Flash存儲器具有電信號刪除功能,且刪除速度快,集成度高,因此已成為此種存儲器的首選。由于Flash存儲器的存取速度較慢,寫入Flash存儲器的程序將在系統上電時被DSP裝載到快速的存儲器中運行,這個過程稱為Boot loader。不同的DSP有不同的引導方式。
DSP編程
DSP系統的引導裝載是指在系統加電后,系統自行將一段存儲在外部非易失性存儲器中的代碼移植到內部DSP的高速RAM中并執行的過程。
因此,在引導裝載系統中,外部非易失性存儲器和DSP的性能顯得尤為重要。
FLASH存儲器是一種高密度、非易失性的電可擦寫存儲器。
而且單位存儲比特的價格比傳統的EPROM要低,所以十分適合于作為外擴存儲器。
在系統加電之前,必須先將引導程序和用戶程序寫入FLASH中。
編程時,除了可以利用專用的硬件編程器實現對FLASH的編程之外,FLASH通常還支持DSP軟件編程以實現同樣的功能。
當系統加電之后,一般首先在FLASH中運行引導程序,并由其自行完成對用戶程序的移植操作,然后再由DSP高速運行移人到DSP片內的用戶程序。
DSP編程技巧
mposerStudio)是TI公司開發的一個完整的DSP集成開發環境。由于TI的DSP使用非常廣泛,使得CCS也就成為使用最為廣泛的DSP開發軟件之一。現在,所有TI公司的DSP都可以在該環境里進行開發,可實現全空間透明仿真,不占用用戶任何資源,軟件配有匯編/鏈接、C編譯器、C源碼調試器等。不同的系統有不同版本的CCS開發環境,TMS320F28l2的集成開發環境是CCS2000。在購買開發板時都會免費贈送CCS開發軟件,另外也可以在TI的網站上免費下載該軟件,開發環境的安裝使用一般在DSP開發板的使用說明書中有詳盡的敘述,在此不做贊述。
2.編程語言CCS開發環境支持兩種語言:匯編語言和C語言。TI的每個DSP系列都有對應的一套匯編指令,如果采用匯編語言編程,需要熟悉這些指令,難度和效率可想而知。現在TI的工程師在不斷改進CCS的C程序優化編譯器,目前C優化的效率可達到手工匯編的90%甚至更高。當然有的時候如果計算能力和內存資源是瓶頸,ASM還是有優勢,比如G.729編解碼。但是針對一般的應用開發,C語言是最好的選擇,只要有一定的C語言的基礎,就完全可以進行DSP的開發編程。
應用實例及開發流程
1.實例介紹400Hz的逆變電源的控制部分實現的主要功能有:(1)AD轉換,(2)SPWM生成,(3)與顯示單片機的串口通信,(4)與其他并聯電源的CAN總線通信;(5)捕捉同步信號。妥實現以上這些功能,顯然普通的單片機是無法完成的,因此我們選擇了專門用作控制的數字信號處理器TMS320F2812。在此儀對TMS320F28l2生成SPWM波的開發過程作詳細介紹。
PWM(PulseWidthModulation)控制就是對脈沖的寬度進行調制的技術,即通過對一系列脈沖的寬度進行調制,來等效地獲得所需要波形。
SPWM波形(SinuSOIdalPWM)就是脈沖的寬度按正弦規律變化而和正弦波等效的PWM波形,在逆變電路中的應用最為廣泛。在此例中SPWM的功能是給三相逆變電路的6個IGBT(絕緣柵雙極晶體管)提供觸發脈沖,從而使直流電逆變為400Hz的正弦交流電。
2.開發流程(1)編寫軟件SPWM的生成主要是應用TMS320F28l2的事件管理器模塊(EVA/B),所以編寫程序前要做的主要工作就是了解熟悉這一模塊的結構和工作原理,至于其他用不到的模塊可暫時不作了解。程序編寫的第一步就是要對用到的模塊的各種寄存器進行設置,第二步就是算法的設計編寫。
(2)調試程序編寫完程序后,就要在仿真環境下進行調試,先編譯再運行,通過示波器可以直接觀察DSP引腳上輸出的SPWM波形,直到與要求的波形相符為止。
(3)燒寫程序在仿真環境下調試好程序后,需要把程序燒寫到DSP的片上FLASH存儲器中。燒寫時必須先安裝專門的燒寫軟件,安裝后就可以直接在CCS環境下操作燒寫。燒寫完成后就可以脫離仿真器,開發板就可以上電獨立運行,并和其他的外圍電路相連而實現它的功能。
習方法知參考資源一、習方法初學DSP常常會感覺到技術文檔太多,無從下手。根據我的自學經歷,這時最應該弄明白的就是DSP芯片的內部硬件工作原理,如果有微機原理和單片機基礎的話,這應該是很容易掌握的,如果沒有這方面的基礎,建議先去找一本微機原理的書看,看明白后再來看DSP的原理。另外,DSP的外設模塊有很多,這時沒有必要都去了解,只是了解你所用到的模塊就可以了。
了解了DSP的工作原理之后,就要去看關于軟件開發環境的書,包括軟件的安裝和使用。然后就找幾個完整的工程(購買開發板時都會贈送各模塊的完整工程)來看,在似懂非懂的大體了解了一個完整工程的創建及結構后,就可以開始分析和你所用到的模塊相關的程序。現在有大量現成的例程和算法可以參考,切忌自己悶頭摸索,一定要去找相關的程序來參考,這會起到事半功倍的效果。
淺談TMS320C6000系列中斷設置問題
實現DSP中斷需要做哪些通用工作
設置允許哪些非屏蔽中斷
設置各個允許的非屏蔽中斷的中斷來源
設置開啟總中斷
設計中斷向量表
將中斷向量表通過cmd文件掛載到指令內存
提供中斷處理函數
如果中斷向量表首地址掛載的不是地址,那么需要設置中斷向量表地址寄存器
對于不同的中斷源,需要做各個自己的工作,比如如果是外部中斷,那么需要設置管腳極性,即由高-》低產生中斷抑或反之。
為了照顧知識較少的讀者,下面將從一個新工程出發,引導大家建立一個中斷示例程序。
如果您對建立工程很熟悉,可以跳過此步。
三、 建立新工程
1.點擊Project-》New,設置Project Name為intexample,Project Type為Executable,Target選擇您需要的器件,在此由于本人使用的是DSK6416評估板。因此選擇TMS320C64XX。
2.添加標準庫rts6400.lib,以便自動產生c_int00等函數。右擊當前工程,選擇“Add Files to Project”,選擇庫所在路徑,一般為CCS安裝自帶,可參考本CCS3.1版本的路徑地址:\CCStudio_v3.1\C6000\cgtools\lib\rts6400.lib
如果您使用的是其他器件類型,請在lib文件夾內選擇其他器件庫。
添加源文件,選擇File-》New-》Source File,保存為main.c到工程路徑下。
在此文件內書寫主函數。
void main(void)
{
while(1);
}
最后通過如2步驟添加此文件到工程。
3.添加寄存器別名定義頭文件。在本示例中,對需要用到的寄存器定義別名后,構成global.h文件,內容在后文逐步介紹。在此可以建立一個空文件,并在main.c中包括它。
#i nclude “global.h”
到此,一個DSP的新工程框架制作完畢。
4.添加cmd鏈接文件
為了實現鏈接時內存配置,我們需要提供一個cmd文件,為了方便,可以從官方的示例程序中拷貝一份,再加以修改。
在安裝目錄下D:\CCStudio_v3.1\tutorial\器件類型\hello1示例下,會找到一個hello1.cmd,
將其拷貝到本工程目錄下,并將其改名為link.cmd,最后將其添加到工程中。
由于此文件沒有聲明stack和heap,會產生警告,如果動態數據較多也容易溢出。因此我們最好在此文件提供stack和heap的大小,其值可根據實際情況調整,修改后,此文件內容類似為:
-stack 0x1000
-heap 0x1000
MEMORY
{
ISRAM : origin = 0x0, len = 0x1000000
}
SECTIONS
{
.vectors 》 ISRAM
.text 》 ISRAM
.bss 》 ISRAM
.cinit 》 ISRAM
.const 》 ISRAM
.far 》 ISRAM
.stack 》 ISRAM
.cio 》 ISRAM
.sysmem 》 ISRAM
}
至此,工程建立完畢,可以編譯一遍,觀察是否正常。
--------------------------- intexample.pjt - Debug ---------------------------
[main.c] “D:\CCStudio_v3.1\C6000\cgtools\bin\cl6x” -g -fr“D:/intexample/Debug” -d“_DEBUG” -mv6400 -@“Debug.lkf” “main.c”
[Linking.。。] “D:\CCStudio_v3.1\C6000\cgtools\bin\cl6x” -@“Debug.lkf”
《Linking》
Build Complete,
0 Errors, 0 Warnings, 0 Remarks.
四、 定時器中斷設計
首先,我們先實現一個定時器中斷,因為它不受外部影響,容易測試。
在global.h文件中,加入控制寄存器和中斷寄存器別名定義,另外為了使用定時器1,也應對其別名進行定義:
/*定義控制寄存器*/
extern cregister volatile unsigned int AMR; /* Address Mode Register */
extern cregister volatile unsigned int CSR; /* Control Status Register */
extern cregister volatile unsigned int IFR; /* Interrupt Flag Register */
extern cregister volatile unsigned int ISR; /* Interrupt Set Register */
extern cregister volatile unsigned int ICR; /* Interrupt Clear Register */
extern cregister volatile unsigned int IER; /* Interrupt Enable Register */
extern cregister volatile unsigned int ISTP; /* Interrupt Service Tbl Ptr */
extern cregister volatile unsigned int IRP; /* Interrupt Return Pointer */
extern cregister volatile unsigned int NRP; /* Non-maskable Int Return Ptr*/
extern cregister volatile unsigned int IN; /* General Purpose Input Reg */
extern cregister volatile unsigned int OUT; /* General Purpose Output Reg */
/* 定義中斷選擇寄存器*/
#define MUXH 0x019C0000
#define MUXL 0x019C0004
#define EXTPOL 0x019C0008
/*定義定時器1寄存器*/
#define CTL1 0x01980000 //Timer1 control register
#define PRD1 0x01980004 //Timer1 period register
#define CNT1 0x01980008 //Timer1 counter register
之后,在main函數中對定時器進行初始化,在此我們使用Timer1,參數初始化函數如下:
void Timer1_Init(void)
{
*( volatile unsigned int* )CTL1= 0x00000201; //計數器功能設置
*( volatile unsigned int* )PRD1= 0x1000; //計數器周期值
*( volatile unsigned int* )CTL1|= 0x000000C0; //計數器清零,啟動
上句的注釋:*( volatile unsigned int* )CTL1=CTL1|0x000000C0
}
并在主函數中調用它。
隨后我們設置中斷寄存器參數。
DSP支持1個RESET中斷,1個NMI(不可屏蔽中斷),12個可屏蔽中斷(INT4-15),它們具有優先級順序,INT4最高,INT15最低。每個中斷號(INT4-INT15)都可以設置任何中斷來源。在此我們選擇中斷INT10,即開啟中斷10,并設置其中斷來源為定時器1,即在MUXH或MUXL中指定位上填寫中斷來源選擇碼:
中斷來源選擇碼定義如下:(此內容可以通過幫助中搜索INTSEL得到)
INTSEL(Interrupt Selection Number Deion)
00000b DSPINT Host port host to DSP interrupt
00001b TINT0 Timer 0 interrupt
00010b TINT1 Timer 1 interrupt
00011b SD_INT EMIF SDRAM timer interrupt
00100b EXT_INT4 External interrupt 4
00101b EXT_INT5 External interrupt 5
00110b EXT_INT6 External interrupt 6
00111b EXT_INT7 External interrupt 7
01000b EDMA_INT EDMA channel (0-15) interrupt
01001-01011b Reserved
01100b XINT0 McBSP0 transmit interrupt
01101b RINT0 McBSP0 receive interrupt
01110b XINT1 McBSP1 transmit interrupt
01111b RINT1 McBSP1 receive interrupt
10000-11111b Reserved
從中得到定時器1的中斷選擇碼為00010。
MUXH和MUXL的寄存器定義如下:(也可以通過幫助得到)
MUXH
位 中斷來源
30-26 INTSEL15
25-21 INTSEL14
20-16 INTSEL13
14-10 INTSEL12
9-5 INTSEL11
4-0 INTSEL10
31,15 保留,填
MUXL
位 中斷來源
30-26 INTSEL9
25-21 INTSEL8
20-16 INTSEL7
14-10 INTSEL6
9-5 INTSEL5
4-0 INTSEL4 //中斷INT4的中斷來源,選擇定時器中斷
31,15 保留,填
因此,我們設置MUXH的第4-0位為定時器1的中斷選擇碼00010,其余位可以任意設置(在此可以填1)。轉換為16進制后,設置如下:
*( volatile unsigned int* )MUXH=0x7fff7fe2;
MUXL可以不設置。
開啟中斷到IE10,使能全局中斷:
IER |= 0x0000 0402; // IE10=1
CSR |= 0x00000001; // 全局中斷使能
以上就完成了中斷參數的配置,中斷啟動并且可以進入了。下面是中斷的處理過程。主要分為設計中斷向量表和中斷處理函數。
我們可以從DSP CCS的示例中復制一份向量表的雛形。例如\CCStudio_v3.1\tutorial\dsk6416\hello1\vectors.asm
將其拷貝到本工程目錄下并加入工程中。
中斷向量表包含了16個中斷處理單元,每個單元限制必須是8條指令。如果不夠8條,可以用nop填充,(但nop 4算1條語句),如果服務程序過多,那么可以制作專門的中斷服務程序,此時此表只起到跳轉作用,這樣CPU就可以正確尋址找到正確的中斷服務入口。
首先分析一下此文件。
文件開始定義了一個宏,用于處理未用到的中斷。
unused .macro id
.global unused:id:
unused:id:
b unused:id: ; nested branches to block interrupts
nop 4
b unused:id:
nop
nop
nop
nop
nop
它的做法是讓程序進入死循環,我認為這種做法未必最優,因此我建議使用直接返回的方式。返回到被中斷地址,對于可屏蔽中斷為b irp,因此將此宏部分替換成,注意一定要湊夠8條。
unused .macro id
.global unused:id:
unused:id:
b irp
nop
nop
nop
nop
nop
nop
nop
.endm
這樣,即使我們誤開啟了此中斷,也會順利返回。當然,如果我們確信的確沒有開啟,那么其內容是無意義的。
代碼的正文部分用了一系列unused n來插入此宏,起到占地的作用。
由于NMI的返回與可屏蔽中斷不同,它在向量表中位于RESET之下,即unused 1,我們將其刪除,替換為
NMI: b irp
nop
nop
nop
nop
nop
nop
nop
為了實現定時器1中斷的處理,我們將unused 10刪除,替換為我們自己的中斷跳轉程序,如下:
INT10:
stw b0,*--b15
mvkl _xint0_isr,b0
mvkh _xint0_isr,b0
b b0
ldw *b15++,b0
nop 3
nop
nop
另外,需要和語句:
.ref _c_int00 ; C entry point
類似,添加處理程序的引用
.ref _xint0_isr ; timer 1 interrupt handler
由于中斷向量表的位置需要特定指明,且應對齊到400H,在此文件中,已經定義了段名:
.sect “.vectors”
因此我們需要將此.vector代碼段掛載到專門的一段指定內存區域。
修改link.cmd 鏈接文件,加入INT區域,起點為地址。其大小為400H,將原先的ISRAM起始點修改。并將SECTIONS中的.vector指向自己定義的內存區域。
MEMORY
{
INT : origin = 0x00000000, len = 0x0000400
ISRAM : origin = 0x00000400, len = 0x1000000
}
SECTIONS
{
.vectors 》 INT
…
}
中斷向量表設置、安裝完畢。
最后,設計中斷服務函數,在main.c中添加:
interrupt void xint0_isr(void)
{
}
注意,一定要標識interrupt關鍵字,用于產生中斷返回語句b irp,同時,此函數的入口參數和出口參數應為void。如果需要更新變量,可以通過全局變量的方式。
另外,C語言函數名稱與匯編相差一個“_”,請在設計中斷向量表時注意添加。
經過上述步驟,整個定時器中斷的制作過程就完成了。此時可以在interrupt void xint0_isr(void)上添加一個斷點,運行后應該停在此處。如果進入失敗,可以先在vector.asm的INT10:stw b0,*--b15一句上設置斷點,如果沒有進入此處,證明中斷沒有進來,可以檢查是否在參數設置上出現了問題。
五、 外部中斷設計
DSP6000系列提供了INT4-7四個中斷輸入管腳,因此可以通過此四個管腳的輸入電平變化實現外部中斷。對于電平變化的極性,分為高到低,低到高兩種,因此,DSP采用寄存器EXTPOL來設置。EXTPOL只有低4位有效,分別代表INT4-7,對于每個位有:
:低-》高產生中斷
1:高-》低產生中斷
因此設置它即可完成極性變化。
下面,以設置外部端口INT7中斷,并將其掛載到12號中斷為例,簡述實現過程:
將12號中斷設置為外部中斷7,即MUXH(14:10)=00111,此時MUXH設置為:
*( volatile unsigned int* )MUXH=0x7fff7ce2;//0111 1100 1110 0010
將IER的第12位開啟。
IER |= 0x00001402; // IE10=1 IE12=1
對vectors.asm的unused 12替換為:
INT12:
stw b0,*--b15
mvkl _extint7_isr,b0
mvkh _extint7_isr,b0
b b0
ldw *b15++,b0
nop 3
nop
nop
并添加引用
.ref _extint7_isr
在main.c中加入服務函數:
interrupt void extint7_isr(void)
{
}
在硬件上,對INT7/GPIO7管腳產生一個低-》高的信號,則可以觸發出中斷。
若改變此極性,可以設置EXTPOL第四位為1:
*( volatile unsigned int* )EXTPOL|= 0x00000008;
此時,一個高-》低的信號可以產生中斷。
需要注意的是,如果你對GPIO進行過初始化,一定要保證GPEN的中斷引腳相應位為1。如全部使能:
*(volatile unsigned int* )GPEN = 0x000000F0;
六、 MCBSP串口接收中斷設計
在實際應用過程中,經常需要通過中斷接收串口數據。在此假設添加MCBSP0接收中斷到11號。
首先,將MCBSP0別名添加到global.h文件。
設置MCBSP0參數并啟用,其初始化函數為:
void MCBSP0_Init(void)
{
*( volatile unsigned int* )McBSP0_SPCR = 0x00000000;
*( volatile unsigned int* )McBSP0_SRGR = 0x200000FF;
*( volatile unsigned int* )McBSP0_PCR = 0x00000800;
*( volatile unsigned int* )McBSP0_XCR = 0x000100A0;
*( volatile unsigned int* )McBSP0_RCR = 0x000100A0;
*( volatile unsigned int* )McBSP0_MCR = 0x00000000;
*( volatile unsigned int* )McBSP0_SPCR |= 0x00C10001;
}
并在main函數中調用。
開啟中斷11:
IER |= 0x00001C02; // IE10=1 IE11=1 IE12=1
并將MUXH(9:5)=01101,綜合以上三個中斷,
此時MUXH為: *( volatile unsigned int* )MUXH=0x7fff1da2;//0001 1101 1010 0010
當然,如果只考慮現在的中斷,MUXH可以設置為:
*( volatile unsigned int* )MUXH=0x7fff7dbf;//0111 1101 1011 1111
制作中斷服務程序,將數據取出:
interrupt void rint0_isr(void)
{
int DotRev;
DotRev=*( volatile unsigned int *)McBSP0_DRR;
}
修改vectors.asm,替換unused 11為:
INT11:
stw b0,*--b15
mvkl _rint0_isr,b0
mvkh _rint0_isr,b0
b b0
ldw *b15++,b0
nop 3
nop
nop
添加引用:
.ref _rint0_isr ; mcbsp 0 receive interrupt handler
這時,所有的任務完成了,可以通過設置斷點觀察一下接收的數值。
另外需要注意一定要在服務程序中將數據取出,否則會停止接到新的數據。
七、 其他話題
1.設置中斷向量表起始位置
上文討論的都是將中斷向量表放置在地址,如果需要放置到任意地址(以400H對齊),那么就需要提供向量表起始地址。
比如我們的終端向量位置:INT設置為:
MEMORY
{
INT : origin = 0x00000400, len = 0x0000400
ISRAM : origin = 0x00000800, len = 0x1000000
}
那么我們在初始化中斷時,應設置:
ISTP=0x00000400;
2.查看現在的中斷位圖
可以查看中斷標志寄存器IFR相應位(15:0)看是否有中斷到達。
3.清除/設置原先的中斷
如果需要清除原先的中斷,可以通過對ICR寄存器相應位置位。如果希望人工觸發中斷,可以設置ISR寄存器相應位置位,它們將更新IFR位圖。
比如,我們在定時器中斷服務程序中,通過設置ISR的第12位,人工觸發外部INT7的12號中斷。
interrupt void xint0_isr(void)
{
ISR=0x00001000;
}
那么CPU將執行extint7_isr(void)處理此中斷。
又比如,在上例的外部中斷中,有時會出現剛一開機,沒有發送信號就有中斷進來的情況,那么怎樣克服呢?可以通過ICR克服。對ICR置位可以清除可屏蔽中斷。對應位有效。比如在設置中斷初始化時清除所有原先的中斷。那么可以加入語句:
ICR =0xffffffff;
4.DSP/BIOS下的中斷設置
在DSP/BIOS管理下,我們不需要自己設定中斷向量表,以及中斷初始化等等,一切通過BIOS的圖形化設置即可完成。
添加一個DSP/BIOS
選擇File-》New,在本測試下選擇DSK6416,讀者可根據自己實際需要選取。保存為Configuration1.cdb。
將其添加到工程。
如上例需求,選擇HWI的10,11,12號中斷,右鍵選擇Properties分別填寫如下參數:
HWI_INT10 interrupt source=Timer_1 =_xint0_isr(注意下劃線!)
HWI_INT11 interrupt source=MCSP_0_Receive =_rint0_isr
HWI_INT11 interrupt source=External_Pin_7 =_extint7_isr
在main函數中可以通過同樣的方法啟動中斷。
IER |= 0x00001C02; // IE10=1 IE11=1 IE12=1
CSR |= 0x00000001; //全局中斷使能
至此配置完畢。
5.中斷進不來怎樣檢查?
首先檢查是否設置IER相應位開啟,CSR最低位置位,其次看看中斷向量表地址是否設置正確。如果確認無誤。在向量表中斷應當進入的位置設定斷點。運行看是否執行到斷點。如果有,那么看看中斷服務程序有沒有執行到。如果中斷只進來一次后就再也無法進入了,可以查看中斷向量表是否能返回到原程序,如果不能返回,查看是否是8條語句。另外可以通過跟蹤查看b irp語句是否被執行。如果可以正常返回到原程序,例如串口接收,看看是否沒有取值導致阻塞。如果是這樣需要將原先值取出才有新的中斷。
6.中斷若干寄存器的說明到哪里去找?
可以通過Help-》Contents,搜索關鍵字的方法得到。也可以參考官方文檔。
結語
關于TMS320C6000的相關介紹就到這了,如有不足之處歡迎指正。
-
dsp
+關注
關注
553文章
7987瀏覽量
348743 -
TMS320C6000
+關注
關注
0文章
96瀏覽量
15749
發布評論請先 登錄
相關推薦
評論