天天看點

TI DSP外設寄存器和CPU控制寄存器、資料類型、中斷的使用

題目:有關TI DSP的一些東西(整理一些網絡資源及手冊資料)--外設寄存器和CPU控制寄存器、資料類型、中斷的使用

原文:http://blog.csdn.net/jbb0523/article/details/7799919

===================================================================

IER 和 IFR 你知道如何去定義嗎?

IER和IFR在并沒有定義位址,因為它是CPU是CPU寄存器,隻有存儲器才會有明确的位址。

隻需如此在頭檔案中如此定義:

extern cregister volatile unsigned int IFR;

extern  cregister volatile unsigned int IER

在使用時要注意IER 可采用直接付值的方式,而IFR為隻讀如果要改變值 隻可用&= 和|=

轉自:http://bbs.eeworld.com.cn/thread-111092-1-9.html

===================================================================

[原創]  CPU寄存器IER&IFR

     看顧老師的手把手教你學DSP,每個例程裡面main()中有下面幾行代碼:DINT; IER = 0x0000; IFR = 0x0000;......IER |= M_INT1 ; 剛開始不知道其中的原理是什麼,為什麼可以直接使用IER和IFR這兩個寄存器,因為頭檔案并沒有給出IER,IFR兩個CPU寄存器的位址,不像其它寄存器那樣,通過#define 寄存器名字  位址定義之後,我們便可以直接操作寄存器了。 看了TMS320C28x Optimizing CC++ Compiler.pdf P130 之後才明白其中的原因。

      The compiler extends the C language by adding the cregister keyword to allow high level language access to control registers.

      When you use the cregister keyword on an object, the compiler compares the  name of the object to a subset of standard control registers for the TMS320C28x . If the name matches, the compiler generates the code to reference the control register. If the name does not match, the compiler issues an error.

      The cregister keyword can only be used in file scope. The cregister keyword is not allowed on any declaration within the boundaries of a function. It can only be used on objects of type integer or pointer. The cregister keyword is not allowed on objects of any floating-point type or on any structure or union objects.

       Once you have declared the register, you can use the register name directly. Note that IFR is read only and can only be set using the| (or) operation with an immediate.

For example: IFR | = 0x4;  The IFR can only be cleared using the& (AND) operation with an immediate. Any other use of the IFR register will result in an error.  疑問:那上面的IFR = 0x0000 直接指派清除中斷标志時怎麼回事?

轉自:http://www.hellodsp.com/bbs/forum.php?mod=viewthread&tid=183888

====================================================================

厘清楚外設寄存器(peripheral register)和CPU控制寄存器(CPU Control Registers),外設寄存器是有位址的,通過位址直接仿問,而CPU控制寄存器沒有位址,通路時直接extern cregister volatile unsigned int聲明即可,詳細可參見以上兩段轉載内容。

針對TMS320C6416T的外設寄存器可參見文檔《[sprs226m]TMS320C6414T, TMS320C6415T, TMS320C6416T FIXED-POINT DIGITAL SIGNAL PROCESSORS》的Table4~Table22,針對CPU控制寄存器詳見文檔《[spru186v]TMS320C6000 Assembly Language Tools v7p3 User's Guide》的Table3-2 ,有關CPU控制寄存器的較長的描述詳見文檔《[spru732j]TMS320C64x_C64x+ DSP CPU and Instruction Reference Guide》的2.8節,另外該文檔的第5章較大篇幅的講述了DSP的中斷。

有關中斷的三個外設寄存器MUXH、MUXL、EXTPOL說明詳見文檔《[spru646a]TMS320C6000 DSP Interrupt Selector Reference Guide》 。

使用中斷時經常要調用intr.h檔案,但内部的以下三個函數是沒有源代碼的,它們屬于外設支援庫中的函數,詳細說明可以參考文檔《[spru273b]TMS320C6x Peripheral Support Library Programmer’s Reference》。

void intr_reset(void);

void intr_init(void);

void intr_hook(void (*fp)(void),int cpu_intr);

DSP的資料類型說明如下,來自文檔《[spru198k]TMS320C6000 Programmer’s Guide》 :

  char 8 bits 

  short 16 bits 

  int 32 bits 

  float 32 bits

  long 40 bits

  long long 64 bits

  double 64 bits

以上主要說了一些内容對應哪個文檔,也可以在CCS下help---contents,搜尋相應的關鍵字,比如要檢視IER這個寄存器,直接index IER即可。

=========================================================

DSP中斷使用:(摘自http://embed.chinaitlab.com/DF/750409_2.html)

下面以響應外部中斷4為例,給出具體的中斷處理流程:(1)初始化中斷intr_init(),初始化ISTP,其值為中斷服務表的首位址;(2)将外部中斷源4映射到CPU中斷4上:intr map(CPU INT4,ISN EXT INT4),置中斷選擇寄存器相應位置處值為中斷服務号4;(3)裝載中斷服務子程式:intr_hook(fp,CPU_INT4),函數指針指向中斷處理表中的相應表項;(4)手動清除中斷标志寄存器IFR中的中斷标志位:INT_CLR_FLAG(CPU_INT4),保證IFR任何比特域中沒有不必要的值;(5)使能非屏蔽中斷NMI,否則其餘中斷皆不能處理,中斷使能寄存器IER中的NMI E位置1:INTR_ENABLE(CPU INT NMI);(6)使能CPU中斷4,中斷使能寄存器IER中的相應位置1:INTR_ENABLE(CPU INT4);(7)通過設定控制狀态寄存器CSR中的GIE位,全局使能所有可屏蔽中斷:INTR_GL OBAL_ENABLE()。

=========================================================

DSP中斷設定簡明教程 (轉自:http://blog.21ic.com/user1/3128/archives/2009/60506.html)

一、 簡述

本文介紹TMS320C6000系列中斷設定的簡明方法。通過示例定時器中斷,MCBSP序列槽接收中斷及外部中斷這三種中斷實作過程,介紹如何實作中斷各個寄存器的配置,中斷向量表書寫以及中斷服務函數。最後提供一個簡要的示例程式可供大家下載下傳使用。此示例在DSK6416的TI官方實驗闆上通過測試。由于定時器和序列槽工作模式較繁,是以對中斷無關部分不做介紹。

二、 實作DSP中斷需要做哪些通用工作

設定允許哪些非屏蔽中斷

設定各個允許的非屏蔽中斷的中斷來源

設定開啟總中斷

設計中斷向量表

将中斷向量表通過cmd檔案挂載到指令記憶體

提供中斷處理函數

如果中斷向量表首位址挂載的不是0位址,那麼需要設定中斷向量表位址寄存器

對于不同的中斷源,需要做各個自己的工作,比如如果是外部中斷,那麼需要設定管腳極性,即由高->低産生中斷抑或反之。

為了照顧知識較少的讀者,下面将從一個新工程出發,引導大家建立一個中斷示例程式。

如果您對建立工程很熟悉,可以跳過此步。

三、 建立新工程

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[email protected]"Debug.lkf" "main.c"

[Linking...] "D:\CCStudio_v3.1\C6000\cgtools\bin\cl6x" [email protected]"Debug.lkf"

<Linking>

Build Complete,

  0 Errors, 0 Warnings, 0 Remarks.

四、 定時器中斷設計

首先,我們先實作一個定時器中斷,因為它不受外部影響,容易測試。

在global.h檔案中,加入控制寄存器和中斷寄存器别名定義,另外為了使用定時器1,也應對其别名進行定義:

extern cregister volatile unsigned int AMR;    

extern cregister volatile unsigned int CSR;    

extern cregister volatile unsigned int IFR;    

extern cregister volatile unsigned int ISR;    

extern cregister volatile unsigned int ICR;    

extern cregister volatile unsigned int IER;    

extern cregister volatile unsigned int ISTP;   

extern cregister volatile unsigned int IRP;    

extern cregister volatile unsigned int NRP;    

extern cregister volatile unsigned int IN;     

extern cregister volatile unsigned int OUT;    

#define MUXH 0x019C0000

#define MUXL 0x019C0004

#define EXTPOL 0x019C0008

#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;  //計數器清零,啟動

}

并在主函數中調用它。

随後我們設定中斷寄存器參數。

DSP支援1個RESET中斷,1個NMI(不可屏蔽中斷),12個可屏蔽中斷(INT4-15),它們具有優先級順序,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位保留,填0

MUXL

位  中斷來源

30-26 INTSEL9

25-21 INTSEL8

20-16 INTSEL7

14-10 INTSEL6

9-5  INTSEL5

4-0  INTSEL4

31,15位保留,填0

是以,我們設定MUXH的第4-0位為定時器1的中斷選擇碼00010,其餘位可以任意設定(在此可以填1)。轉換為16進制後,設定如下:

 *( volatile unsigned int* )MUXH=0x7fff7fe2;

MUXL可以不設定。

開啟中斷到IE10,使能全局中斷:

 IER |= 0x00000402;   // 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 nrp

  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區域,起點為0位址。其大小為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,對于每個位有:

0:低->高産生中斷

1:高->低産生中斷

是以設定它即可完成極性變化。

下面,以設定外部端口INT7中斷,并将其挂載到12号中斷為例,簡述實作過程:

将12号中斷設定為外部中斷7,即MUXH(4:0)=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.設定中斷向量表起始位置

上文讨論的都是将中斷向量表放置在0位址,如果需要放置到任意位址(以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,搜尋關鍵字的方法得到。也可以參考官方文檔。

八、 附帶程式

本教程以附件提供三個示例:

1. onlytimerint——僅包含了定時器的示例

2. int——包含了完整的3種中斷

3. intbios——提供了DSP/BIOS下的此3種中斷。

九、 參考文檔

《TMS320C64x/C64x+ DSP CPU and Instruction Set Reference Guide》Chapter5 interrupts