在学习这个C6748时候,发现定时器真的挺难的.好像都可以随意级联还是怎么的.
官方文档描述有如下的特性:
- 64-bit count-up counter [64位向上计算器]
- Timer modes [定时器模式]
- 64-bit general-purpose timer mod”e [64位通用定时器模式]
- Dual 32-bit unchained general-purpose timer mode [两个32Bit的无关联定时器]
- Dual 32-bit chained timer mode [两个32Bit的关联定时器]
- Watchdog timer mode [看门狗定时器]
- 2 possible clock sources [2个可用的时钟源]
- Internal clock [内部时钟源]
- External clock/event input via timer input pins [外部时钟源/使用定时器引脚进行事件输入]
- 3 possible operation modes [3个可用的操作模式]
- One-time operation (timer runs for one period then stops) [定时器走了一个周期,中断后就把他停止了.]
- Continuous operation (timer automatically resets to zero after each period and continues to operate) [定时器每次结束后都清零,然后再继续一个周期.]
- Continuous operation with period reload (timer automatically assumes the value of the reload registers after each period and continues to operate) [定时器每次结束后都重装到一个固定值,然后再继续一个周期.]
- Generates interrupts to CPU [产生中断给CPU]s
- ,
- Generates sync events to DMA [产生同步事件给DMA]
- Generates output event to device reset (watchdog only) [输出一个事件到复位,就是相当于看门狗.]
- Generates output event to timer output pins (if pins are available) [输出一个事件到一个引脚]
- External event capture via timer input pins (if pins are available) [外部事件输入,不是时钟源啊,估计是捕获,比如红外捕获.]
如果说是64位定时器,其实我觉得不准,其实是两个32位定时器,低32位叫TMR12,高32位叫TMR34,组起来才是TMR64.所以每个定时器,应该是16B的.在手册中表示T01和T23时钟是不一样的.
其中T01是旁路时钟,我现在板子是24MHz晶体呢,所以时钟也就是24MHz了.T23就是默认PLL0_SYSCLK2,默认系统主频一半.打开到仿真可以看到4个定时器.
我使用的板子,GPIO用了GPIO109,GPIO110作为LED的引脚.首先系统进入后要使能相应的外设,因为TMR是绑定在CPU总线上的,所以只需要初始化GPIO外设就可以了.
1
|
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.
再用TI的Startware库,把GPIO设置成输出模式.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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.设置好后就可以开始计时.
1
2
3
4
5
6
|
#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);
|
然后看到寄存器已经填充这个数值,其他寄存器含义可以查手册.
然后要马上注册中断.其中关于P2的中断功能太多了,我们只用 Timer64P2 Combined Interrupt 事件.
当然全局中断也要记得打开.进入中断后马上关闭中断功能,然后清除标志位,翻转LED,整个动作完成了.可以烧到NAND里面,然后Boot看看.可以看得到,就算刷这么高的reload,TMR2还是跑很快,原因是时钟就很快,如果时钟比较慢的TMR1,又是如何,试试TMR1的两个32B的模式.因为TMR1是24MHz时钟,就算32B,也要178秒才能完成整个过程,如果是64B,跑完就要2W4千年了,那时候DSP是个什么东西,所以TMR01做64B感觉意义不大.
现在先搞好程序,让IO配置还是那两个GPIO,但是配置定时器时候就不一样了.第一个定一秒,第二个定两秒.
然后设置中断,为什么不用TMR2呢,因为TMR2不一样,TMR1可以做两个中断,TMR2不能,要自行判断.分别配置两个中断就好了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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);
}
|
两个定时器中断是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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的状态应该如下:
- 第0秒,GPIO109 = 0,GPIO110 = 0.
- 第1秒,GPIO109 = 1,GPIO110 = 0.TMR12进入中断了.
- 第2秒,GPIO109 = 0,GPIO110 = 1,TMR12,TMR34都能中断,TMR12因此变成0.
- 第3秒,GPIO109 = 1,GPIO110 = 1,TMR12中断,翻转了,TMR34还没反应.
- 第4秒和第0秒重叠了.
另外做双32位时候,还可以前置一个分频,当然是TMR34的福利了.先把TMR_PERIOD34缩小10倍,然后设置分频10倍,应该得到如上一样的效果.
而如果是做32B关联的,就可以理解为TMR34是个预分频计数器,TMR12是个真正的计数器.手册上图所示.
之前初始化,用的都是TMR_CFG_32BIT_UNCH_CLK_BOTH_INT模式,这次只要初始化改成TMR_CFG_32BIT_CH_CLK_INT模式就可以,如下先用TMR34把24MHz分频成1MHz,然后用1MHz定时1秒.
1
2
3
4
5
6
7
8
9
10
|
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的芯片,其他我还没玩过,哈,一定是太..了.
|