TMS320C6748 学习[定时器学习]

/ 0评 / 1

在学习这个C6748时候,发现定时器真的挺难的.好像都可以随意级联还是怎么的.
官方文档描述有如下的特性:

  1. 64-bit count-up counter [64位向上计算器]
  2. Timer modes [定时器模式]
    1. 64-bit general-purpose timer mod''e [64位通用定时器模式]
    2. Dual 32-bit unchained general-purpose timer mode [两个32Bit的无关联定时器]
    3. Dual 32-bit chained timer mode [两个32Bit的关联定时器]
    4. Watchdog timer mode [看门狗定时器]
  3. 2 possible clock sources [2个可用的时钟源]
    1. Internal clock [内部时钟源]
    2. External clock/event input via timer input pins [外部时钟源/使用定时器引脚进行事件输入]
  4. 3 possible operation modes [3个可用的操作模式]
    1. One-time operation (timer runs for one period then stops) [定时器走了一个周期,中断后就把他停止了.]
    2. Continuous operation (timer automatically resets to zero after each period and continues to operate) [定时器每次结束后都清零,然后再继续一个周期.]
    3. Continuous operation with period reload (timer automatically assumes the value of the reload registers after each period and continues to operate) [定时器每次结束后都重装到一个固定值,然后再继续一个周期.]
  5. Generates interrupts to CPU [产生中断给CPU]s
  6.                  ,
  7. Generates sync events to DMA [产生同步事件给DMA]
  8. Generates output event to device reset (watchdog only) [输出一个事件到复位,就是相当于看门狗.]
  9. Generates output event to timer output pins (if pins are available) [输出一个事件到一个引脚]
  10. External event capture via timer input pins (if pins are available) [外部事件输入,不是时钟源啊,估计是捕获,比如红外捕获.]

如果说是64位定时器,其实我觉得不准,其实是两个32位定时器,低32位叫TMR12,高32位叫TMR34,组起来才是TMR64.所以每个定时器,应该是16B的.在手册中表示T01和T23时钟是不一样的.
微信截图_20160420194540
其中T01是旁路时钟,我现在板子是24MHz晶体呢,所以时钟也就是24MHz了.T23就是默认PLL0_SYSCLK2,默认系统主频一半.打开到仿真可以看到4个定时器.
微信截图_20160420202613
我使用的板子,GPIO用了GPIO109,GPIO110作为LED的引脚.首先系统进入后要使能相应的外设,因为TMR是绑定在CPU总线上的,所以只需要初始化GPIO外设就可以了.

 PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_GPIO, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);

其中GPIO109就是P6.12,GPIO110就是P6.13,对应的PINMUX13,使用PINMUX工具可以计算,把他们两都弄成是GPIO.
微信截图_20160420204139
再用TI的Startware库,把GPIO设置成输出模式.

void GPIOBankPinInit(void)
{
    // GPIO0[0] 1
    // GPIO1[0] 17
    // GPIO2[0] 33
    // GPIO3[0] 49
    // GPIO4[0] 65
    // GPIO5[0] 81
    // GPIO6[0] 97
    // GPIO7[0] 113
    // GPIO8[0] 129
    GPIODirModeSet(SOC_GPIO_0_REGS, 109, GPIO_DIR_OUTPUT);  // GPIO6[12]
    GPIODirModeSet(SOC_GPIO_0_REGS, 110, GPIO_DIR_OUTPUT);  // GPIO6[13]
}

这一个用过定时器应该就知道了.然后开始初始化定时器2,先是初始化成64B模式,然后填MSB,LSB的32B, CPU是456MHz的,他的一半就是228MHz,现在哪个单片机跑这么快啊.所以228,000,000个周期后溢出,就是1秒了.要0.1秒溢出,就是22,800,000,换算到32B就是15BE680.所以LSB就是15BE680,MSB是0.设置好后就可以开始计时.

#define TMR_PERIOD_LSB32  (0x015BE680)
#define TMR_PERIOD_MSB32  (0)
TimerConfigure(SOC_TMR_2_REGS, TMR_CFG_64BIT_CLK_INT);
TimerPeriodSet(SOC_TMR_2_REGS, TMR_TIMER12, TMR_PERIOD_LSB32);
TimerPeriodSet(SOC_TMR_2_REGS, TMR_TIMER34, TMR_PERIOD_MSB32);
TimerEnable(SOC_TMR_2_REGS, TMR_TIMER12, TMR_ENABLE_CONT);

然后看到寄存器已经填充这个数值,其他寄存器含义可以查手册.
Unnamed QQ Screenshot20160420205004
然后要马上注册中断.其中关于P2的中断功能太多了,我们只用 Timer64P2 Combined Interrupt 事件.
微信截图_20160420205322
当然全局中断也要记得打开.进入中断后马上关闭中断功能,然后清除标志位,翻转LED,整个动作完成了.可以烧到NAND里面,然后Boot看看.可以看得到,就算刷这么高的reload,TMR2还是跑很快,原因是时钟就很快,如果时钟比较慢的TMR1,又是如何,试试TMR1的两个32B的模式.因为TMR1是24MHz时钟,就算32B,也要178秒才能完成整个过程,如果是64B,跑完就要2W4千年了,那时候DSP是个什么东西,所以TMR01做64B感觉意义不大.
现在先搞好程序,让IO配置还是那两个GPIO,但是配置定时器时候就不一样了.第一个定一秒,第二个定两秒.
微信截图_20160420213336
然后设置中断,为什么不用TMR2呢,因为TMR2不一样,TMR1可以做两个中断,TMR2不能,要自行判断.分别配置两个中断就好了.

void TimerInterruptInit(void)
{
	// 注册中断服务函数
	IntRegister(C674X_MASK_INT4, Timer12Isr);
	IntRegister(C674X_MASK_INT5, Timer34Isr);
	// 映射中断到 DSP 可屏蔽中断
	IntEventMap(C674X_MASK_INT4, SYS_INT_T64P1_TINT12);
	IntEventMap(C674X_MASK_INT5, SYS_INT_T64P1_TINT34);
	// 使能 DSP 可屏蔽中断
	IntEnable(C674X_MASK_INT4);
	IntEnable(C674X_MASK_INT5);
	// 使能 定时器 / 计数器 中断
	TimerIntEnable(SOC_TMR_1_REGS, TMR_INT_TMR12_NON_CAPT_MODE | TMR_INT_TMR34_NON_CAPT_MODE);
}

两个定时器中断是这样的:

void Timer12Isr(void)
{
    // 禁用定时器 / 计数器中断
    TimerIntDisable(SOC_TMR_1_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    // 清除中断标志
    IntEventClear(SYS_INT_T64P1_TINT12);
    TimerIntStatusClear(SOC_TMR_1_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    Time12++;
    if(Time12 % 2 == 1){
        GPIOPinWrite(SOC_GPIO_0_REGS, 109, 1);
    }else{
        GPIOPinWrite(SOC_GPIO_0_REGS, 109, 0);
    }
    // 使能 定时器 / 计数器 中断
    TimerIntEnable(SOC_TMR_1_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
}
void Timer34Isr(void)
{
    // 禁用定时器 / 计数器中断
    TimerIntDisable(SOC_TMR_1_REGS, TMR_INT_TMR34_NON_CAPT_MODE);
    // 清除中断标志
    IntEventClear(SYS_INT_T64P1_TINT34);
    TimerIntStatusClear(SOC_TMR_1_REGS, TMR_INT_TMR34_NON_CAPT_MODE);
    Time34++;
    if(Time34 % 2 == 1){
        GPIOPinWrite(SOC_GPIO_0_REGS, 110, 1);
    }else{
        GPIOPinWrite(SOC_GPIO_0_REGS, 110, 0);
    }
    // 使能 定时器 / 计数器 中断
    TimerIntEnable(SOC_TMR_1_REGS, TMR_INT_TMR34_NON_CAPT_MODE);
}

LED的状态应该如下:

  1. 第0秒,GPIO109 = 0,GPIO110 = 0.
  2. 第1秒,GPIO109 = 1,GPIO110 = 0.TMR12进入中断了.
  3. 第2秒,GPIO109 = 0,GPIO110 = 1,TMR12,TMR34都能中断,TMR12因此变成0.
  4. 第3秒,GPIO109 = 1,GPIO110 = 1,TMR12中断,翻转了,TMR34还没反应.
  5. 第4秒和第0秒重叠了.

另外做双32位时候,还可以前置一个分频,当然是TMR34的福利了.先把TMR_PERIOD34缩小10倍,然后设置分频10倍,应该得到如上一样的效果.
Unnamed QQ Screenshot20160420214520
而如果是做32B关联的,就可以理解为TMR34是个预分频计数器,TMR12是个真正的计数器.手册上图所示.
Unnamed QQ Screenshot20160420215024
之前初始化,用的都是TMR_CFG_32BIT_UNCH_CLK_BOTH_INT模式,这次只要初始化改成TMR_CFG_32BIT_CH_CLK_INT模式就可以,如下先用TMR34把24MHz分频成1MHz,然后用1MHz定时1秒.

void TimerInit(void)
{
    // 配置 定时器 / 计数器 1 为 32 位模式
    TimerConfigure(SOC_TMR_1_REGS, TMR_CFG_32BIT_CH_CLK_INT);
    // 设置周期
    TimerPeriodSet(SOC_TMR_1_REGS, TMR_TIMER12, 1 * 1000 * 1000);
    TimerPeriodSet(SOC_TMR_1_REGS, TMR_TIMER34, 24);
    // 使能 定时器 / 计数器 1
    TimerEnable(SOC_TMR_1_REGS, TMR_TIMER12, TMR_ENABLE_CONT);
}

其他就没区别了,至于看门狗,就不用中断服务函数,其他就一样了,还要定期用TimerWatchdogReactivate喂狗,用TimerWatchdogActivate启动狗,杀狗只需要杀掉定时器.总的来说,C6000的TIM肯定不是电机TIM,但是功能也是很强大的,主要是,速度这么快的定时器,除了跑Linux的芯片,其他我还没玩过,哈,一定是太..了.
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注