C6748EDMA_GPIO_中断学习笔记
2019-07-13 13:01发布
生成海报
// 申请 EDMA3 通道
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, chType, chNum, tccNum, evtQ);
这句函数中,chNum指的是所申请的通道的number,cc0和cc1各有32个DMA通道,每个通道对应一个特定的事件(event),如cc0的channel6对应GPIObank0的中断

(指南P439)

(手册P102)
evtQ是事件队列,chNum对应的事件发生后,会将该事件缓存入事件队列中,等待处理,cc0有2个队列,每个队列最大深度为16,即最多只能存放16个事件,队列0的优先级比队列1的优先级高,如果Q1和Q2同时有至少1个事件,则Q1的事件会先出队,提交TR(transfer request)给TR0,然后Q2的事件才出队,给TR1。当数据转移完成后,TC(transfer
controller)会返回TCC(transfer completion code)给CC(channel controller),TCC在与channel关联的Param Set中设置。TCC决定了IPR(interrupt pending register)中的那位被置位,如果在IER(interrupt enable register)中相应的位也为1,使能了该中断,就会产生相应的中断给CPU。
(指南P522)
转移(transfer)完成所产生具体的中断事件以下公式决定。

(指南P523)
/** rief Base address of GPIO memory mapped registers */
#define SOC_GPIO_0_REGS (0x01E26000)
voidGPIOBankIntDisable(unsignedint
baseAdd, unsignedint bankNumber)
GPIOBankIntDisable(SOC_GPIO_0_REGS, 0);
该句清除BINTEN中相应位,禁止GPIObank0中断。
(手册P254)
#define
SYS_INT_GPIO_B0INT 65
IntEventClear(SYS_INT_GPIO_B0INT);
该句清除DSP中断控制器中的系统中断状态位,系统中断状态位在中断控制器的事件标志寄存器EVTFLAGn中(n=1~4),每个EVTFLAG寄存器存放32个系统中断状态,每一位对应一个中断事件,如EVTFLAG3的1位对应的是标号为65的中断事件,即GPIObank0中断,当GPIObank0中断事件发生时,该位就会置为1。
(手册P22)
(手册P96)
(mega手册P170)
在中断处理程序(interrupt service routine)中,需要清除事件标志寄存器中断事件标志位,则需要往事件清除寄存器相应的位写1。如GPIObank0中断事件发生时,因为该中断事件的标号为65,所以EVTFLAG2寄存器的1位会置1,要清除该位,需要往EVTCLR3寄存器的1位写1.
(mega手册P169)
(mega手册P173)
voidGPIOPinIntClear(unsignedint
baseAdd, unsignedint pinNumber)
GPIOPinIntClear(SOC_GPIO_0_REGS, 7);
该句清除GPIObank0pin6所对应的GPIO中断状态位。GPIO中断状态寄存器INTSTAT为标志GPIO引脚发生中断的寄存器,当某个GPIO引脚发生中断时,相应的INTSTATn寄存器中的位会被置1。如GPIObank0的pin6发生下降沿触发中断时,INTSTAT01寄存器的6位会被置1.软件需要往INTSTAT01寄存器的6位写1才能将其清除。
(指南P867)
// 注册中断服务函数
IntRegister(C674X_MASK_INT6, USER0KEYIsr);
voidIntRegister (unsignedint
cpuINT, void (*userISR)(void))
{
/* Check the CPU
maskable interrupt number */
ASSERT(((cpuINT >= 1) && (cpuINT <= 15)));
/* Assign the user's ISR to the CPU
maskable interrupt */
c674xISRtbl[cpuINT] = userISR;
}
staticc674xISR c674xISRtbl[C674X_INT_COUNT];
typedefvoid (*c674xISR)(void);
c674xISRtbl为定义的一个函数指针数组,存放的函数指针指向参数列表为void,返回值为void的函数。其实c674xISRtbl就是存放中断服务程序地址的指针数组,各指针分别指向对应INT4到INT15的中断服务程序(interrupt service routine)。IntRegister(C674X_MASK_INT6,
USER0KEYIsr);这句函数将该c674xISRtbl函数指针数组的第6个指针指向了USER0KEYIsr函数。
// 映射中断到 DSP 可屏蔽中断
IntEventMap(C674X_MASK_INT6, SYS_INT_GPIO_B0INT);
该句函数将中断复用器INTMUX1的INTSEL6字段设为GPIObank0中断事件号65,即将标号为65的中断源映射到标号为6的CPU中断。INTMUXn寄存器地址及字段如下图所示:
(手册P96)
(mega手册P178)
那么,当发生65号中断(GPIObank0中断时),CPU又为什么能够执行c674xISRtbl[C674X_MASK_INT6]函数指针所指向的函数呢?这个问题背后的实现机制有点绕,我也是想了很久才明白。
首先,在DSP中断控制器初始化的时候,IntDSPINTCInit();函数将中断服务表指针ISTP(Interrupt Service Table Pointer)指向了中断向量表_intcVectorTable,函数部分如下:
/* Set interrupt service table pointer to the vector table */
#ifdef__TI_EABI__
ISTP = (unsignedint)_intcVectorTable;
#else
ISTP = (unsignedint)intcVectorTable;
#endif
intcVectorTable中断向量表在starterware的systerm_config工程的intvecs.asm文件中定义了,代码如下:
1. ;
2. ; File: intvecs.asm
3. ;
4. ; Brief: Contains interrupt vector table and fetch packets
5. ;
6. ; Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
7. ; ALL RIGHTS RESERVED
8.
9. ;**********************************************************
10. ; Global Symbols
11. ;**********************************************************
12. .global _intcVectorTable
13. .global _c_int00
14. .global _c674x_nmi_isr
15. .global _c674x_rsvd_int2_isr
16. .global _c674x_rsvd_int3_isr
17. .global _c674x_mask_int4_isr
18. .global _c674x_mask_int5_isr
19. .global _c674x_mask_int6_isr
20. .global _c674x_mask_int7_isr
21. .global _c674x_mask_int8_isr
22. .global _c674x_mask_int9_isr
23. .global _c674x_mask_int10_isr
24. .global _c674x_mask_int11_isr
25. .global _c674x_mask_int12_isr
26. .global _c674x_mask_int13_isr
27. .global _c674x_mask_int14_isr
28. .global _c674x_mask_int15_isr
29.
30. ;**********************************************************
31. ; Interrupt Fetch Packet
32. ;**********************************************************
33. VEC_ENTRY .macro addr
34. STW B0,*--B15
35. MVKL addr,B0
36. MVKH addr,B0
37. B B0
38. LDW *B15++,B0
39. NOP 2
40. NOP
41. NOP
42. .endm
43.
44. ;**********************************************************
45. ; Interrupt Vector Table
46. ;**********************************************************
47. .align 1024
48. _intcVectorTable:
49. VEC_ENTRY _c_int00
50. VEC_ENTRY _c674x_nmi_isr
51. VEC_ENTRY _c674x_rsvd_int2_isr
52. VEC_ENTRY _c674x_rsvd_int3_isr
53. VEC_ENTRY _c674x_mask_int4_isr
54. VEC_ENTRY _c674x_mask_int5_isr
55. VEC_ENTRY _c674x_mask_int6_isr
56. VEC_ENTRY _c674x_mask_int7_isr
57. VEC_ENTRY _c674x_mask_int8_isr
58. VEC_ENTRY _c674x_mask_int9_isr
59. VEC_ENTRY _c674x_mask_int10_isr
60. VEC_ENTRY _c674x_mask_int11_isr
61. VEC_ENTRY _c674x_mask_int12_isr
62. VEC_ENTRY _c674x_mask_int13_isr
63. VEC_ENTRY _c674x_mask_int14_isr
64. VEC_ENTRY _c674x_mask_int15_isr
但是intvecs.asm文件中,中断向量的名字是c674x_rsvd_intn_isr(n=2~15),与c674xISRtbl函数指针数组并没有直观的联系,这两者是如何对应上的呢?比如,当发生65号中断时,根据上面的映射,CPU会执行6号可屏蔽CPU中断服务程序_c674x_mask_int6_isr,但是c674x_mask_int6_isr程序的入口又在哪里?这里我找了很久,终于在interrupt.c文件中找到了该函数的定义,如下:
#ifdef __TI_EABI__
interruptvoid _c674x_mask_int6_isr
(void)
#else
interruptvoidc674x_mask_int6_isr (void)
#endif
{
c674xISRtbl[6]();
}
注意这句话c674xISRtbl[6]();,原来在中断服务程序c674x_mask_int6_isr中,程序直接跳转到了c674xISRtbl[6]函数指针所指的函数了,即上面所注册的用户函数userISR了,这就解释了中断发生后,程序怎么能够执行到用户所注册的函数的,技术路线有点绕。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮