DSP

C6748_GPIO_KEY_TIMER_EventCombine

2019-07-13 20:30发布

组合事件中断初始化EventCombineInterruptInit();函数完成组合事件中断初始化,其中 // 使能定时器 /计数器中断TimerIntEnable(SOC_TMR_1_REGS,TMR_INT_TMR34_NON_CAPT_MODE);该函数使能了定时器中断。 SOC_TMR_1_REGS(0x01C21000),即timer1的地址,如图所示: (手册P22 偏移44h,为定时器中断控制和状态寄存器INTCTLSTATTimer Interrupt Control and Status Register (指南P1401 (指南P1414 TMR_INT_TMR34_NON_CAPT_MODE((0x00010000u)),将PRDINTEN34位置1,使能了定时器中断。 #define C674X_MASK_INT4 4 #define ECM0_UNUSED -1 #define ECM1_UNUSED -1 #define ECM2_UNUSED -1 #define ECM3_UNUSED -1

    IntEventCombineInit(ECM0_UNUSED, C674X_MASK_INT4, ECM2_UNUSED, ECM3_UNUSED);函数将event combiner1的输出EVT1事件映射到了CPU可屏蔽中断4,因为所用到的事件中断GPIObank6中断和定时器1中断的中断号分别为6248,都在3263的范围,所以组合事件为EVT1IntEventCombineInit函数中的这句语句 IntRegister(ecmINT1, IntEventCombineIsr1);ECM1的中断服务函数IntEventCombineIsr1注册为了CPU可屏蔽中断4ecmINT1传参为4)的中断服务函数(c674xISRtbl[cpuINT] = userISR;)则当CPU可屏蔽中断4发生时,CPU将会执行函数指针c674xISRtbl[4]所指向的中断服务函数,这里是注册的函数IntEventCombineIsr1IntEventMap(ecmINT1, SYS_INT_EVT1);这句语句将事件中断1EVT1映射到CPU可屏蔽中断,中断号为参数ecmINT1. mega手册P166 IntEventMap函数如下: voidIntEventMap (unsignedint cpuINT, unsignedint sysINT) { unsignedint dspintcREG, restoreVal; /* Check the CPU maskable interrupt number */ ASSERT(((cpuINT >= 4) && (cpuINT <= 15))); /* Check the system event number */ ASSERT((sysINT <= 127)); /* Get the address of the correct interrupt mux register */ dspintcREG = SOC_INTC_0_REGS + DSPINTC_INTMUX((cpuINT >> 2)); /* Disable interrupts */ restoreVal = IntGlobalDisable(); /* Clear and set INTSELx with system event number */ HWREG(dspintcREG) = (HWREG(dspintcREG) & ~DSPINTC_INTMUX_INTSEL(cpuINT)) | (sysINT << DSPINTC_INTMUX_INTSEL_SHIFT(cpuINT)); /* Clear any residual interrupt */ ICR = (1 << cpuINT); /* Restore interrupts */ IntGlobalRestore(restoreVal); }

程序中,dspintcREG赋值为中断复用寄存器INTMUX的地址,同时,将中断复用寄存器INTMUX中相应的INTSEL字段设置为要连接的中断事件源EVT。在这个程序中,是把中断事件1EVT1映射到了CPU可屏蔽中断4了。 IntEventCombineIsr1函数如下所示: #define SYS_INT_EVT1 1 staticvoidIntEventCombineIsr1 (void) { IntEventCombinerDispatch(SYS_INT_EVT1); } IntEventCombinerDispatch(SYS_INT_EVT1);函数如下所示: staticvoidIntEventCombinerDispatch (unsignedint evtReg) { unsignedint dspintcMEFREG, dspintcECREG, evtRcv, evtIndex, offset; /* Get the address of the correct DSPINTC registers */ dspintcMEFREG = SOC_INTC_0_REGS + DSPINTC_MEVTFLAG(evtReg); dspintcECREG = SOC_INTC_0_REGS + DSPINTC_EVTCLR(evtReg); offset = evtReg * 32; evtRcv = HWREG(dspintcMEFREG); while(evtRcv) { /* Clear system events */ HWREG(dspintcECREG) = evtRcv; /* Service system events */ do{ evtIndex = 31 - _lmbd(1, evtRcv); evtRcv &= ~(1 << evtIndex); c674xECMtbl[evtIndex + offset](); }while(evtRcv); /* Check for new system events */ evtRcv = HWREG(dspintcMEFREG); } }

dspintcMEFREG赋值为屏蔽事件标志寄存器1 MEVTFLAG1masked event flag register 1)的地址。 mega手册P169 dspintcECREG赋值为事件清除寄存器1 EVTCLR1Event clear register 1)的地址。 mega手册P169 _lmbd(1, evtRcv);intrinsic函数,intrinsic函数为以下划线'_'号开头的一类特殊的函数,类似于内嵌的汇编指令,可以实现一些用汇编指令很容易实现而用CC++很难实现的功能。根据ccs帮助,lmbd函数定义如下: 这句语句搜索evtRcv变量最左边的1所在的位置,然后返回这个1左边的0的数目,例如,evtRcv=60000 0000 0000 0110bevtRcvunsigned int类型,故为32位数),最左边的1在第2位(下标从0开始),这个1左边一共有290,因此,_lmbd(1, evtRcv)29,其它情况分析类似。IntEventCombinerDispatch主要做的事情是,从evtRcv变量(赋值为屏蔽事件标志寄存器dspintcMEFREG)最左边的1开始(为1表示该为对应的事件发生),一直搜索到最右边的1,即搜索所有的被置位的中断事件标志,对相应的中断事件进行处理(运行中断服务程序c674xECMtbl[evtIndex + offset]();),直到所有的中断事件都得到处理。 mega手册P167 EVT1事件是EVT32EVT63所有事件或的结果,EVT MASK屏蔽相应的事件,让该事件不参与或运算。 mega手册P160 #define SYS_INT_GPIO_B6INT 62// GPIO bank6中断 #define SYS_INT_T64P1_TINT34 48// 定时器中断 // 添加事件 IntEventCombineAdd(SYS_INT_GPIO_B6INT); IntEventCombineAdd(SYS_INT_T64P1_TINT34); IntEventCombineAdd函数如下: voidIntEventCombineAdd(unsignedint sysINT) { unsignedint dspintcREG, restoreValue; /* Check the system event number */ ASSERT((sysINT <= 127)); /* Get the address of the correct event combiner register */ dspintcREG = SOC_INTC_0_REGS + DSPINTC_EVTMASK((sysINT >> 5)); /* Disable interrupts */ restoreValue = IntGlobalDisable(); /* Unmask system event number to be included in the combined event */ HWREG(dspintcREG) &= ~DSPINTC_EVTMASK_EM(sysINT); /* Enable interrupts */ IntGlobalRestore(restoreValue); }

    这两句语句做的事是,根据要组合的事件,对事件屏蔽寄存器EVTMASKnn=0~3)中相应的位清0,不屏蔽这些位所对应的事件,当这些事件中断发生时,发生组合事件中断。EVTMASK寄存器地址如下: mega手册P169 mega手册P174     定时器初始化函数如下: #define SOC_TMR_1_REGS (0x01C21000) #define TMR_CFG_32BIT_UNCH_CLK_BOTH_INT (0x00000017u) voidTimerInit(void) { // 配置定时器 / 计数器 1 为 32 位模式 TimerConfigure(SOC_TMR_1_REGS, TMR_CFG_32BIT_UNCH_CLK_BOTH_INT); // 设置周期 TimerPeriodSet(SOC_TMR_1_REGS, TMR_TIMER34, TMR_PERIOD_32); // 使能定时器 / 计数器 1 TimerEnable(SOC_TMR_1_REGS, TMR_TIMER34, TMR_ENABLE_CONT); } TimerConfigure函数如下: voidTimerConfigure(unsignedint baseAddr, unsignedint config) { /* ** Set the timer control register. This will only affect the clock ** selection bits. All other fields will be reset and the timer counting ** will be disabled. */ HWREG(baseAddr + TMR_TCR) = (config & (TMR_TCR_CLKSRC12 | TMR_TCR_CLKSRC34)); /* Clear the Timer Counters */ HWREG(baseAddr + TMR_TIM12) = 0x0; HWREG(baseAddr + TMR_TIM34) = 0x0; /* Clear the TIMMODE bits and Reset bits */ HWREG(baseAddr + TMR_TGCR) &= ~( TMR_TGCR_TIMMODE | TMR_TGCR_TIM34RS | TMR_TGCR_TIM12RS); /* ** Select the timer mode and disable the timer module from Reset ** Timer Plus features are enabled. */ HWREG(baseAddr + TMR_TGCR) |= (config & (TMR_TGCR_TIMMODE | TMR_TGCR_TIM34RS | TMR_TGCR_TIM12RS | TMR_TGCR_PLUSEN)); }

C6748共有464位定时器timer0timer1timer2timer3ti叫做64-bit timer plus,这个叫法也是挺有意思的,ti似乎想自夸一下自家dsp的外设模块,很多模块都喜欢在平常的名字的前面或后面加点东西,表示我这个东西是加强版,比如PWM模块,ti不叫PWM,他叫EPWM,什么意思?就是增强型PWM的意思(enhanced pwm),这里,这个定时器也不例外,因为它比常见的定时器要大了一号,所以ti管他叫plus,就跟手机一样,iphone plus就比iphone要大上一圈,而ti的这个定时器,不仅仅是位数增加,其功能也的确比普通单片机的定时器要强大得多,所以ti这个标新立异的叫法,虽然有点哗众取宠之嫌,终究还是令人信服的。Timer0timer1的地址如图所示: (手册P22 程序中TimerConfigure设置了定时器控制器TCRtimer control register)的CLKSRC120,将定时器的时钟源设置为内部时钟。定时器内部时钟时钟源为pll输出的AUXCLK (指南P1409 (指南P130 (指南P131 设置了定时器1的定时器全局控制寄存器(TGCR),将timer1设置为dual 32-bit unchained mode,并禁止tim34rstimer12rs复位。当定时器被使能的时候,定时器计数器就会开始计数。 TimerEnable(SOC_TMR_1_REGS, TMR_TIMER34, TMR_ENABLE_CONT);使能定时器1time34部分,禁止timer12,模式为连续模式。 (指南P1410 TimerPeriodSet(SOC_TMR_1_REGS,TMR_TIMER34,TMR_PERIOD_32);timer1timer34的周期设为TMR_PERIOD_32,即(5 * 24 * 1000 * 1000)