一、主函数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)