最近在论坛上获得了Ai-M61-32S的开发板,基于这个开发板来学习一下先是定时器,Ai-M61-32S内部有2个32位的定时器可用
基于timer例程先写个简单的程序
- #include "bflb_mtimer.h"
- #include "bflb_timer.h"
- #include "board.h"
- struct bflb_device_s *timer0;
- void timer0_isr(int irq, void *arg)
- {
- bool status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_0);
- if (status) {
- bflb_timer_compint_clear(timer0, TIMER_COMP_ID_0);
- printf("timer TIMER_COMP_ID_0\r\n");
- }
- status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_1);
- if (status) {
- bflb_timer_compint_clear(timer0, TIMER_COMP_ID_1);
- printf("timer TIMER_COMP_ID_1\r\n");
- }
- status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_2);
- if (status) {
- bflb_timer_compint_clear(timer0, TIMER_COMP_ID_2);
- printf("timer TIMER_COMP_ID_2\r\n");
- }
- }
- int main(void)
- {
- board_init();
- printf("timer init\r\n");
- /* timer clk = XCLK/(div + 1 )*/
- struct bflb_timer_config_s cfg0;
- cfg0.counter_mode = TIMER_COUNTER_MODE_PROLOAD; /* preload when match occur */
- cfg0.clock_source = TIMER_CLKSRC_XTAL;
- cfg0.clock_div = 39; /* for bl616/bl808/bl606p is 39, for bl702 is 31 */
- cfg0.trigger_comp_id = TIMER_COMP_ID_2;
- cfg0.comp0_val = 1000000 - 1; /* match value 0 */
- cfg0.comp1_val = 2000000 - 1; /* match value 1 */
- cfg0.comp2_val = 3000000 - 1; /* match value 2 */
- cfg0.preload_val = 0; /* preload value */
- timer0 = bflb_device_get_by_name("timer0");
- /* Timer init with default configuration */
- bflb_timer_init(timer0, &cfg0);
- bflb_irq_attach(timer0->irq_num, timer0_isr, NULL);
- bflb_irq_enable(timer0->irq_num);
- /* Enable timer */
- bflb_timer_start(timer0);
- printf("case success.\r\n");
- while (1) {
- bflb_mtimer_delay_ms(1500);
- }
- }
复制代码 接下来消化一下这个例程的内容
cfg0.counter_mode,这个参数是指定定时器的运行模式的,在BL616/618的手册里介绍定时器支持2种定时器模式:PreLoad 模式和 FreeRun 模式,PreLoad模式可以指定计数初始值和最大值,FreeRun 模式无法指定初始值和最大值会从0开始一直跑到0xFFFFFFFF再从0开始
cfg0.clock_source,这个参数指定了定时器使用的时钟源,这里使用的是外部40MHz的晶振作为时钟源
cfg0.clock_div,这个参数作为对时钟源的分频系数,这里设置为39表示对时钟源进行40分频,也就是定时器计数频率为1MHz
cfg0.trigger_comp_id,这个参数和下面的三个值配合使用决定了,PreLoad模式下触发重载的条件
cfg0.compX_val,当计数值和这3个值其中之一相等时就会触发中断,这里设置数值相隔1000000,每隔1秒触发一次中断
cfg0.preload_val,PreLoad模式下的初始计数值
bflb_irq_attach(timer0->irq_num, timer0_isr, NULL),这个方法指定了中断的处理方法
运行效果
可以看到每隔1秒就会触发一次对应的中断,当计数到达TIMER_COMP_ID_2对应的数值时,计数会从头开始
这时修改一下重载的数值让它大于TIMER_COMP_ID_0的数值看看会发生什么
- cfg0.preload_val = 1500000 - 1;
复制代码
可以看到TIMER_COMP_ID_0对应的中断不再触发,因为重载后的计数值已经大于TIMER_COMP_ID_0对应的数值
接下来将TIMER_COMP_ID_2对应的数值设置小于TIMER_COMP_ID_1,看看会发生什么
- cfg0.comp2_val = 1500000 - 1;
- cfg0.preload_val = 0;
复制代码
可以看到TIMER_COMP_ID_1对应的中断不再触发,因为在计数值到达TIMER_COMP_ID_1的值之前会先到达TIMER_COMP_ID_2的值然后触发重载
接下来将重载条件设置为TIMER_COMP_ID_1看看会发生什么
- cfg0.trigger_comp_id = TIMER_COMP_ID_1;
- cfg0.comp0_val = 1000000 - 1;
- cfg0.comp1_val = 2000000 - 1;
- cfg0.comp2_val = 1500000 - 1;
- cfg0.preload_val = 0;
复制代码
可以看到虽然TIMER_COMP_ID_2的值比TIMER_COMP_ID_1的值小但也不会触发TIMER_COMP_ID_2的中断
又或者将重载条件设置为TIMER_COMP_ID_0,然后将TIMER_COMP_ID_0的值设置地比其他值都大
- cfg0.trigger_comp_id = TIMER_COMP_ID_0;
- cfg0.comp0_val = 3000000 - 1;
- cfg0.comp1_val = 2000000 - 1;
- cfg0.comp2_val = 1500000 - 1;
- cfg0.preload_val = 0;
复制代码
可以看到这时只会触发TIMER_COMP_ID_0对应的中断,因此可以推断中断的触发条件不光要看计数值是否符合,还要看TIMER_COMP_ID是否不大于重载用的ID
另外将cfg0.trigger_comp_id 设置为TIMER_COMP_NONE后我原版以为只是以为最大值会变为0xFFFFFFFF结果一个中断都不会触发了,在FreeRun 模式下cfg0.trigger_comp_id的值也会限制中断的触发,感觉实际使用并不和手册描述的完全一样,有兴趣的可以试试
|