TMS320C6748_GPIO_KEY_TIMER_EventCombine

组合事件中断初始化EventCombineInterruptInit();函数完成组合事件中断初始化,其中

// 使能定时器 /计数器中断
TimerIntEnable(SOC_TMR_1_REGS,TMR_INT_TMR34_NON_CAPT_MODE);

该函数使能了定时器中断。 

SOC_TMR_1_REGS为(0x01C21000),即timer1的地址,如图所示:

(手册P22)

偏移44h,为定时器中断控制和状态寄存器INTCTLSTAT(Timer 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中断的中断号分别为62和48,都在32到63的范围,所以组合事件为EVT1。IntEventCombineInit函数中的这句语句

IntRegister(ecmINT1, IntEventCombineIsr1);将ECM1的中断服务函数IntEventCombineIsr1注册为了CPU可屏蔽中断4(ecmINT1传参为4)的中断服务函数(c674xISRtbl[cpuINT] = userISR;)则当CPU可屏蔽中断4发生时,CPU将会执行函数指针c674xISRtbl[4]所指向的中断服务函数,这里是注册的函数IntEventCombineIsr1。IntEventMap(ecmINT1, SYS_INT_EVT1);这句语句将事件中断1EVT1映射到CPU可屏蔽中断,中断号为参数ecmINT1.

(mega手册P166)

IntEventMap函数如下:

void IntEventMap (unsigned int cpuINT, unsigned int sysINT)
{
  unsigned int 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
static void IntEventCombineIsr1 (void)
{
  IntEventCombinerDispatch(SYS_INT_EVT1);
}

IntEventCombinerDispatch(SYS_INT_EVT1);函数如下所示: 

static void IntEventCombinerDispatch (unsignedint evtReg)
{
  unsigned int 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 MEVTFLAG1(masked event flag register 1)的地址。

(mega手册P169)

dspintcECREG赋值为事件清除寄存器1 EVTCLR1(Event clear register 1)的地址。

(mega手册P169)

_lmbd(1, evtRcv);intrinsic函数,intrinsic函数为以下划线'_'号开头的一类特殊的函数,类似于内嵌的汇编指令,可以实现一些用汇编指令很容易实现而用C\C++很难实现的功能。根据ccs帮助,lmbd函数定义如下:

这句语句搜索evtRcv变量最左边的1所在的位置,然后返回这个1左边的0的数目,例如,evtRcv=6(0000 0000 0000 0110b,evtRcv为unsigned int类型,故为32位数),最左边的1在第2位(下标从0开始),这个1左边一共有29个0,因此,_lmbd(1, evtRcv)29,其它情况分析类似。IntEventCombinerDispatch主要做的事情是,从evtRcv变量(赋值为屏蔽事件标志寄存器dspintcMEFREG)最左边的1开始(为1表示该为对应的事件发生),一直搜索到最右边的1,即搜索所有的被置位的中断事件标志,对相应的中断事件进行处理(运行中断服务程序c674xECMtbl[evtIndex + offset]();),直到所有的中断事件都得到处理。

(mega手册P167)

EVT1事件是EVT32到EVT63所有事件或的结果,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函数如下: 

void Int EventCombineAdd(unsignedint sysINT)
{
  unsigned int 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);
}

 这两句语句做的事是,根据要组合的事件,对事件屏蔽寄存器EVTMASKn(n=0~3)中相应的位清0,不屏蔽这些位所对应的事件,当这些事件中断发生时,发生组合事件中断。EVTMASK寄存器地址如下:

(mega手册P169)

(mega手册P174)

    定时器初始化函数如下:

#define SOC_TMR_1_REGS (0x01C21000)
#define TMR_CFG_32BIT_UNCH_CLK_BOTH_INT (0x00000017u)
void Timer Init(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函数如下: 

void TimerConfigure(unsigned int baseAddr, unsigned int 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共有4个64位定时器timer0,timer1,timer2和timer3。ti叫做64-bit timer plus,这个叫法也是挺有意思的,ti似乎想自夸一下自家dsp的外设模块,很多模块都喜欢在平常的名字的前面或后面加点东西,表示我这个东西是加强版,比如PWM模块,ti不叫PWM,他叫EPWM,什么意思?就是增强型PWM的意思(enhanced pwm),这里,这个定时器也不例外,因为它比常见的定时器要大了一号,所以ti管他叫plus,就跟手机一样,iphone plus就比iphone要大上一圈,而ti的这个定时器,不仅仅是位数增加,其功能也的确比普通单片机的定时器要强大得多,所以ti这个标新立异的叫法,虽然有点哗众取宠之嫌,终究还是令人信服的。Timer0和timer1的地址如图所示:

(手册P22)

程序中TimerConfigure设置了定时器控制器TCR(timer control register)的CLKSRC12为0,将定时器的时钟源设置为内部时钟。定时器内部时钟时钟源为pll输出的AUXCLK。

(指南P1409)

(指南P130)

(指南P131)

设置了定时器1的定时器全局控制寄存器(TGCR),将timer1设置为dual 32-bit unchained mode,并禁止tim34rs和timer12rs复位。当定时器被使能的时候,定时器计数器就会开始计数。

TimerEnable(SOC_TMR_1_REGS, TMR_TIMER34, TMR_ENABLE_CONT);使能定时器1的time34部分,禁止timer12,模式为连续模式。

(指南P1410)

TimerPeriodSet(SOC_TMR_1_REGS,TMR_TIMER34,TMR_PERIOD_32);timer1的timer34的周期设为TMR_PERIOD_32,即(5 * 24 * 1000 * 1000)。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值