一、主函數man.c
UART的中斷部分函數內容在C6748_UART輪詢模式中已經介紹,這里不再贅述。這里主要介紹關於中斷部分的函數。UART中斷的主函數如下:
int main(void) { // 外設使能配置 PSCInit(); // GPIO 管腳復用配置 GPIOBankPinMuxSet(); // DSP 中斷初始化 InterruptInit(); // UART 初始化 UARTInit(); // UART 中斷初始化 UARTInterruptInit(); // 主循環 for(;;) { } }
二、DSP中斷初始化函數InterruptInit()
前部分的內容參見C6748_UART輪詢模式,首先進行的是DSP中斷初始化,該函數主要包含了IntDSPINTCInit()和IntGlobalEnable()兩個函數。其中,IntDSPINTCInit()函數是初始化DSP的中斷控制器,包括初始化所有可屏蔽中斷標志位及使能不可屏蔽中斷;IntGlobalEnable()函數是使能DSP全局中斷,具體的介紹如下:

1 void IntDSPINTCInit (void) 2 { 3 unsigned int step = 0; 4 5 /* Set ISRs to default "do-nothing" routine */ 6 while(step != C674X_INT_COUNT) 7 c674xISRtbl[step++] = IntDefaultHandler; 8 9 /* Set interrupt service table pointer to the vector table */ 10 #ifdef __TI_EABI__ 11 ISTP = (unsigned int)_intcVectorTable; 12 #else 13 ISTP = (unsigned int)intcVectorTable; 14 #endif 15 16 /* Clear pending CPU maskable interrupts (if any) */ 17 ICR = 0xFFF0; 18 19 /* Enable NMIE bit to allow CPU maskable interrupts */ 20 IER = (1 << C674X_NMI); 21 }
其中,IntDefaultHandler是While(1)的空函數,c674xISRtbl為定義的一個函數指針數組,存放的函數指針指向參數列表為void,返回值為void的函數。其實c674xISRtbl就是存放中斷服務程序地址的指針數組,各指針分別指向對應INT4到INT15的中斷服務程序(interrupt service routine,而該函數的意思是先將16個c674xISRtbl[step++]函數指針均初始化為默認While(1)程序。ICR = 0xFFF0即將可屏蔽中斷INT15-INT4的所有中斷標志位IFR清除,IER = (1 << C674X_NMI)使能不可屏蔽中斷。
(CPU and Instruction手冊--P41)
(CPU and Instruction手冊--P42)
而其中的c674xISRtbl[step++]函數指針所指向的函數如下所示,位於interrupt.c文件中。

1 #ifdef __TI_EABI__ 2 interrupt void _c674x_nmi_isr (void) 3 #else 4 interrupt void c674x_nmi_isr (void) 5 #endif 6 { 7 c674xISRtbl[1](); 8 } 9 10 #ifdef __TI_EABI__ 11 interrupt void _c674x_rsvd_int2_isr (void) 12 #else 13 interrupt void c674x_rsvd_int2_isr (void) 14 #endif 15 { 16 c674xISRtbl[2](); 17 } 18 19 #ifdef __TI_EABI__ 20 interrupt void _c674x_rsvd_int3_isr (void) 21 #else 22 interrupt void c674x_rsvd_int3_isr (void) 23 #endif 24 { 25 c674xISRtbl[3](); 26 } 27 28 #ifdef __TI_EABI__ 29 interrupt void _c674x_mask_int4_isr (void) 30 #else 31 interrupt void c674x_mask_int4_isr (void) 32 #endif 33 { 34 c674xISRtbl[4](); 35 } 36 37 #ifdef __TI_EABI__ 38 interrupt void _c674x_mask_int5_isr (void) 39 #else 40 interrupt void c674x_mask_int5_isr (void) 41 #endif 42 { 43 c674xISRtbl[5](); 44 } 45 46 #ifdef __TI_EABI__ 47 interrupt void _c674x_mask_int6_isr (void) 48 #else 49 interrupt void c674x_mask_int6_isr (void) 50 #endif 51 { 52 c674xISRtbl[6](); 53 } 54 55 #ifdef __TI_EABI__ 56 interrupt void _c674x_mask_int7_isr (void) 57 #else 58 interrupt void c674x_mask_int7_isr (void) 59 #endif 60 { 61 c674xISRtbl[7](); 62 } 63 64 #ifdef __TI_EABI__ 65 interrupt void _c674x_mask_int8_isr (void) 66 #else 67 interrupt void c674x_mask_int8_isr (void) 68 #endif 69 { 70 c674xISRtbl[8](); 71 } 72 73 #ifdef __TI_EABI__ 74 interrupt void _c674x_mask_int9_isr (void) 75 #else 76 interrupt void c674x_mask_int9_isr (void) 77 #endif 78 { 79 c674xISRtbl[9](); 80 } 81 82 #ifdef __TI_EABI__ 83 interrupt void _c674x_mask_int10_isr (void) 84 #else 85 interrupt void c674x_mask_int10_isr (void) 86 #endif 87 { 88 c674xISRtbl[10](); 89 } 90 91 #ifdef __TI_EABI__ 92 interrupt void _c674x_mask_int11_isr (void) 93 #else 94 interrupt void c674x_mask_int11_isr (void) 95 #endif 96 { 97 c674xISRtbl[11](); 98 } 99 100 #ifdef __TI_EABI__ 101 interrupt void _c674x_mask_int12_isr (void) 102 #else 103 interrupt void c674x_mask_int12_isr (void) 104 #endif 105 { 106 c674xISRtbl[12](); 107 } 108 109 #ifdef __TI_EABI__ 110 interrupt void _c674x_mask_int13_isr (void) 111 #else 112 interrupt void c674x_mask_int13_isr (void) 113 #endif 114 { 115 c674xISRtbl[13](); 116 } 117 118 #ifdef __TI_EABI__ 119 interrupt void _c674x_mask_int14_isr (void) 120 #else 121 interrupt void c674x_mask_int14_isr (void) 122 #endif 123 { 124 c674xISRtbl[14](); 125 } 126 127 #ifdef __TI_EABI__ 128 interrupt void _c674x_mask_int15_isr (void) 129 #else 130 interrupt void c674x_mask_int15_isr (void) 131 #endif 132 { 133 c674xISRtbl[15](); 134 }
函數將ISTP(Interrupt Service Table Pointer)指向intcVectorTable,intcVectorTable是一張向量表,記錄了CPU中斷服務程序的入口地址,各向量對應一個CPU中斷。該向量表在intvecs.asm文件中,路徑同interrupt.c文件一樣(\demo\StarterWare\Source\StarterWare\SystemConfig),內容如下,而intcVectorTable表所有向量的入口函數在interrupt.c文件中,

1 .global _intcVectorTable 2 3 .global _c_int00 4 5 .global _c674x_nmi_isr 6 7 .global _c674x_rsvd_int2_isr 8 9 .global _c674x_rsvd_int3_isr 10 11 .global _c674x_mask_int4_isr 12 13 .global _c674x_mask_int5_isr 14 15 .global _c674x_mask_int6_isr 16 17 .global _c674x_mask_int7_isr 18 19 .global _c674x_mask_int8_isr 20 21 .global _c674x_mask_int9_isr 22 23 .global _c674x_mask_int10_isr 24 25 .global _c674x_mask_int11_isr 26 27 .global _c674x_mask_int12_isr 28 29 .global _c674x_mask_int13_isr 30 31 .global _c674x_mask_int14_isr 32 33 .global _c674x_mask_int15_isr 34 35 36 37 ;********************************************************** 38 39 ; Interrupt Fetch Packet 40 41 ;********************************************************** 42 43 VEC_ENTRY .macro addr 44 45 STW B0,*--B15 46 47 MVKL addr,B0 48 49 MVKH addr,B0 50 51 B B0 52 53 LDW *B15++,B0 54 55 NOP 2 56 57 NOP 58 59 NOP 60 61 .endm 62 63 64 65 ;********************************************************** 66 67 ; Interrupt Vector Table 68 69 ;********************************************************** 70 71 .align 1024 72 73 _intcVectorTable: 74 75 VEC_ENTRY _c_int00 76 77 VEC_ENTRY _c674x_nmi_isr 78 79 VEC_ENTRY _c674x_rsvd_int2_isr 80 81 VEC_ENTRY _c674x_rsvd_int3_isr 82 83 VEC_ENTRY _c674x_mask_int4_isr 84 85 VEC_ENTRY _c674x_mask_int5_isr 86 87 VEC_ENTRY _c674x_mask_int6_isr 88 89 VEC_ENTRY _c674x_mask_int7_isr 90 91 VEC_ENTRY _c674x_mask_int8_isr 92 93 VEC_ENTRY _c674x_mask_int9_isr 94 95 VEC_ENTRY _c674x_mask_int10_isr 96 97 VEC_ENTRY _c674x_mask_int11_isr 98 99 VEC_ENTRY _c674x_mask_int12_isr 100 101 VEC_ENTRY _c674x_mask_int13_isr 102 103 VEC_ENTRY _c674x_mask_int14_isr 104 105 VEC_ENTRY _c674x_mask_int15_isr
在intvecs.asm文件如“_c_int00”代表中斷函數名,C語言中的函數在匯編中使用需要在前面加“_”,而這些中斷向量表是根據中斷優先級順序排列的。
_enable_interrupts函數為Intrinsic函數,函數使能全局中斷。Intrinsic函數為C/C++語言提供了一個調用匯編語言的接口機制,通過Intrinsic函數,C/C++函數中可以調用匯編函數。
三、UART 中斷初始化 UARTInterruptInit()
1 void UARTInterruptInit(void) 2 { 3 IntRegister(C674X_MASK_INT4, UARTIsr); 4 IntEventMap(C674X_MASK_INT4, SYS_INT_UART0_INT); 5 IntEnable(C674X_MASK_INT4); 6 7 // 使能中斷 8 unsigned int intFlags = 0; 9 intFlags |= (UART_INT_LINE_STAT | \ 10 UART_INT_TX_EMPTY | \ 11 UART_INT_RXDATA_CTI); 12 UARTIntEnable(SOC_UART_0_REGS, intFlags); 13 }
先是注冊4號CPU可屏蔽中斷的中斷服務函數(這里的可屏蔽中斷可在INT4到INT15中任意選擇,如下圖所示),IntRegister(C674X_MASK_INT4, UARTIsr)函數如下所示。
1 void IntRegister (unsigned int cpuINT, void (*userISR)(void)) 2 { 3 /* Check the CPU maskable interrupt number */ 4 ASSERT(((cpuINT >= 1) && (cpuINT <= 15))); 5 6 /* Assign the user's ISR to the CPU maskable interrupt */ 7 c674xISRtbl[cpuINT] = userISR; 8 }
該函數首先核對可屏蔽中斷序號是否錯誤,接着由“c674xISRtbl[cpuINT] = userISR”函數將該c674xISRtbl函數指針數組的第4個指針指向了userISR(UARTIsr)程序。則當C674X_MASK_INT4中斷發生時,執行UARTIsr函數。
(見Magamodule手冊P161)
其次,由IntEventMap(C674X_MASK_INT4, SYS_INT_UART0_INT)將128個系統中斷事件EVT中的UART0_INT事件與12個可屏蔽中斷INT中的INT4之間建立映射關系。由IntEnable使能可屏蔽中斷INT4。
1 unsigned int intFlags = 0; 2 intFlags |= (UART_INT_LINE_STAT | \ 3 UART_INT_TX_EMPTY | \ 4 UART_INT_RXDATA_CTI); 5 UARTIntEnable(SOC_UART_0_REGS, intFlags);
通過intFlags的值表示三種中斷觸發事件,任意一種發生則執行中斷INT4,UARTIntEnable(SOC_UART_0_REGS, intFlags)對UART的中斷使能寄存器IER(Interrupt Enable Register)寄存器進行設置。
(見指南P1448)
四、UART中斷服務函數UARTIsr()

1 void UARTIsr() 2 { 3 static unsigned int length = sizeof(txArray); 4 static unsigned int count = 0; 5 unsigned char rxData = 0; 6 unsigned int int_id = 0; 7 8 // 確定中斷源 9 int_id = UARTIntStatus(SOC_UART_0_REGS); 10 11 // 清除 UART2 系統中斷 12 IntEventClear(SYS_INT_UART0_INT); 13 14 // 發送中斷 15 if(UART_INTID_TX_EMPTY == int_id) 16 { 17 if(0 < length) 18 { 19 // 寫一個字節到 THR 20 UARTCharPutNonBlocking(SOC_UART_0_REGS, txArray[count]); 21 length--; 22 count++; 23 } 24 if(0 == length) 25 { 26 // 禁用發送中斷 27 UARTIntDisable(SOC_UART_0_REGS, UART_INT_TX_EMPTY); 28 } 29 } 30 31 // 接收中斷 32 if(UART_INTID_RX_DATA == int_id) 33 { 34 rxData = UARTCharGetNonBlocking(SOC_UART_0_REGS); 35 UARTCharPutNonBlocking(SOC_UART_0_REGS, rxData); 36 } 37 38 // 接收錯誤 39 if(UART_INTID_RX_LINE_STAT == int_id) 40 { 41 while(UARTRxErrorGet(SOC_UART_0_REGS)) 42 { 43 // 從 RBR 讀一個字節 44 UARTCharGetNonBlocking(SOC_UART_0_REGS); 45 } 46 } 47 48 return; 49 }
當中斷發生了,在IER中相應的中斷位也使能了,此時在IIR的IPEND位就會清零,代表UART中斷發生了,此時就會執行UART中斷服務程序UARTIsr()。首先通過“int_id = UARTIntStatus(SOC_UART_0_REGS)”清除中斷鑒別寄存器IIR的IPEND位,即清除IIR中的UART的中斷標志位,其次讀取IIR的INTID的值,得到中斷類型,其值的定義如下圖所示。按照UART中斷優先級的順序(發送中斷1>接收中斷2>接受錯誤3),依此判定“int_id”的值,執行相應的程序。
(見指南P1449)
- 如果UART中斷是由發送中斷引起的,說明發送FIFO為空,就往THR寄存器(transmitter holding register)寫1字節。注意,在FIFO模式下,THR寄存器變成了1個16字節的FIFO。
- 如果UART中斷是由接收中斷引起的,則檢查LSR寄存器(Line Status Register)的DR(Data-ready)字段,確定數據是否已經准備好,即接收器FIFO中是否有數據,如果有,則從RBR寄存器(Receiver Buffer Register)中讀取該數據。當UART處於FIFO模式時,RBR為16字節的FIFO。注意,RBR和THR,DLL共享同一地址,要讀RBR,需要確保LCR寄存器的DLAB位為0.
- 若UART中斷是由接收錯誤引起的,則從RBR中把錯誤的字節都讀出來,並不斷檢測LSR的錯誤標志位,直到所有的錯誤字節都讀走了。
(指南P1432)
(指南P1431)
(指南P1442)
五、關於C6748的UART中斷說明
(見指南P1442)