DSP

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了,这就解释了中断发生后,程序怎么能够执行到用户所注册的函数的,技术路线有点绕。