TMS320F28335在實際的應用比較廣泛。在具體應用過程中,往往有優先級比較高的定時需求。實現次功能的方式有數種,例如使用PWM中斷,定時器中斷等。這裏介紹使用定時器0作爲觸發源進行中斷,實現定時中斷的功能。
1 定時中斷的意義
在F28335的使用過程中,使用定時器進行定時中斷,可以執行定時任務。該任務的執行的時間誤差相比特別小。
2 原理介紹
2.1 中斷介紹
CPU在執行任務時,遇到優先級更高的任務,CPU將會先去執行優先級更高的任務,執行完畢後繼續執行當前任務,這就是中斷。
F28335的具有諸多資源,許多資源均可以觸發中斷。將可以觸發中斷的資源稱爲中斷源。下圖位F28335的中斷源及連接關係。
由於F28335的 中斷源很多,因此F28335採用三級中斷機制,分爲外設級、PIE級和CPU級。原理圖如下所示:
而定時器0就是採用這種三級中斷機制。
爲了便於管理諸多中斷源,TI按照優先級進行了諸多中斷源的分組。其中,定時器0在PIE的第一組第七個,在CPU級的第一組。
2.2 定時器介紹
F28335具有三個定時器,分別爲Timer0、Timer1和Timer2。
定時器的具體功能框圖如下所示:
定時器有一個預分頻模塊和一個定時/計數模塊,其中預分頻模塊有一個16位的定時器分頻寄存器(TDDRH:TDDR)和。一個16位的預定標計數器(PSCH:PSC);定時/計數模塊包括一個32位的週期寄存器(PRDH:PRD)和一個32位的計數寄存器(TIMH:TIM)。
由下圖F28335系統時鐘圖可知,定時器是由系統時鐘來提供時鐘的。
當系統時鐘(SYSCLKOUT)來一個脈衝,PSCH:PSC預定標計數器減1,當PSCH:PSC預定標計數器減到0的時候,預定標計數器產生下溢後向計數寄存器TIMH:TIM借位,也即計數寄存器TIMH:TIM減1,同時PSCH:PSC在一個系統時鐘脈衝之後重載定時器分頻寄存器TDDRH:TDDR的值,當計數寄存器TIMH:TIM減到0產生下溢的時候,計數寄存器TIMH:TIM會重載週期寄存器TIMH:TIM的值。此時,如果TIMERxTCR.TIF位使能了,那麼同時定時器會產生一箇中斷信號給CPU。
2.3 定時器0觸發中斷過程
定時器0觸發中斷的結構圖如下所示:
當TIMER0TCR.TIF位使能了,那麼在定時器重載計數寄存器TIMH:TIM時會產生一箇中斷信號。該中斷信號就是TINT0(定時器0在中斷向量表的位置和命名)。定時器0中斷信號在PIE第一組中的第七個中斷,因此PIE的第一組會產生中斷信號(需要使能PIE第一組中斷)到CPU級,然後到CPU內核,CPU如果判定此時響應該中斷,那麼就會找到中斷向量表中的TINT0所指向的中斷服務子函數,並執行。
根據上述定時器原理,可得定時時間T公式爲:
其中: 爲周器寄存器的值;爲定時器預分頻寄存器的值;爲系統時鐘頻率。
3 實現過程
DSP的運行過程如下:
- 關所有中斷,禁止CPU中斷,清除所有CPU中斷標誌;
- 初始化系統時鐘;
- 中斷設置始化;
- 定時器初始化;
- 使能中斷,開中斷;
- 進入主循環;
- 等待中斷;
- 中斷到時,執行中斷任務;
- 結束中斷任務後,執行中斷應答,清除定時器標誌;
- 重複7~9
具體代碼如下:
3.1 關所有中斷,禁止CPU中斷,清除所有CPU中斷標誌
//Clear all interrupts and initialize PIE vector table: Disable CPU interrupts
DINT;
//Disable CPU interrupts and clear all CPU interrupt flags;
IER = 0x0000;
IFR = 0x0000;
3.2 初始化系統時鐘
// Disable the watchdog
EALLOW;
SysCtrlRegs.WDCR= 0x0068;
EDIS;
// Initialize the PLL control: PLLCR and DIVSEL
// DSP28_PLLCR and DSP28_DIVSEL are defined in DSP2833x_Examples.h
InitPll(DSP28_PLLCR,DSP28_DIVSEL);
// Initialize the peripheral clocks
InitPeripheralClocks();
3.3 中斷設置始化
//Initialize PIE control registers;detail info in the DSP2802x_PieCtrl.c file.
InitPieCtrl();
//Initialize PIE vector table with pointers to the shell ISR
InitPieVectTable();
//Add adress of ISRTask to PIEVectTable
EALLOW;
PieVectTable.TINT0 = &ISRTimer0;
EDIS;
//Enable INT1 & INT1.7
IER |= M_INT1;
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
3.4 定時器初始化
// CPU Timer 0
//初始化計數值
//Counter = 1500*(1/150MHz)=10us
CpuTimer0Regs.PRD.all = 1500;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
CpuTimer0Regs.TIM.all = 0;
//自動重新裝載計數值
CpuTimer0Regs.TCR.bit.TRB = 1;
//啓動定時器0
CpuTimer0Regs.TCR.bit.TSS = 0;
//定時器0中斷使能
CpuTimer0Regs.TCR.bit.TIE = 1;
3.5 使能中斷,開中斷
//Enable global Interrupts and higher priarity real-tme debug events;
EINT;
ERTM;
3.6 進入主循環
for(;;)
{
}
3.7 等待中斷
3.8 中斷到時,執行中斷任務
interrupt void ISRTimer0(void)
{
//Task
//Interrupt ACK & Clear Timer0
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
TIMER0_OUT_CLEAR();
CpuTimer0Regs.TCR.bit.TRB = 1;
}
3.9 執行中斷應答,清除定時器標誌
//Interrupt ACK & Clear Timer0
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
TIMER0_OUT_CLEAR();
CpuTimer0Regs.TCR.bit.TRB = 1;
4 實驗驗證
爲了驗證基於定時器是否能夠實現定時任務,設計GPIO輸出電平1s定時翻轉任務。
代碼的具體實現方式是在上述中斷函數中加入翻轉邏輯,代碼如下:
interrupt void ISRTimer0(void)
{
static int s_iGPIOCnt = 0;
//Task
if(++s_iGPIOCnt >= 100000 ) //10us * 100000 = 1s
{
GpioDataRegs.GPATOGGLE.bit.GPIO0 = 1;
s_iGPIOCnt = 0;
}
//Interrupt ACK & Clear Timer0
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
TIMER0_OUT_CLEAR();
CpuTimer0Regs.TCR.bit.TRB = 1;
}
通過觀測,發現GPIO口對應的LED進行1s的亮滅閃爍。
5 結論
通過觀測到LED的閃爍,證明了中斷函數因爲定時器而響應,時間上大概爲10us。