目录
问题描述:
(1)捕获timer初始化
(2)捕获中断处理函数
(3)速度计算公式
原因查找:
(1)库函数的原因
(2)timer_channel_capture_value_register()位置的原因
问题描述:
四个脉冲捕获通道均给1000Hz 的脉冲,运行一段时间后,四个通道捕获的脉冲数差距
较大,增加相邻脉冲差值计算代码后,发现同一通道的采集的两个脉冲之间的时钟计数差值
可能是正常情况下的2 倍/3 倍/4 倍/5 倍/6 倍。
排查了一两个月,怀疑单板,怀疑芯片,怀疑测试台,怀疑软件,怀疑人生....
我原来的程序是下面这样的:
(1)捕获timer初始化
void initialize_CAP_IN_timer(void)
{uint32_t timer = TIMER1;uint32_t timer_clk = RCU_TIMER1;timer_parameter_struct timer_initpara;timer_ic_parameter_struct timer_icinitpara;rcu_periph_clock_enable(timer_clk);rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);timer_deinit(timer);timer_initpara.prescaler = 199u;timer_initpara.alignedmode = TIMER_COUNTER_EDGE;timer_initpara.counterdirection = TIMER_COUNTER_UP;timer_initpara.period = 0xFFFFFFFFu;timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0u;timer_init(timer, &timer_initpara);timer_auto_reload_shadow_enable(timer);timer_channel_input_struct_para_init(&timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_0, &timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_1, &timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_2, &timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_3, &timer_icinitpara);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH0);timer_interrupt_enable(timer, TIMER_INT_CH0);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH1);timer_interrupt_enable(timer, TIMER_INT_CH1);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH2);timer_interrupt_enable(timer, TIMER_INT_CH2);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH3);timer_interrupt_enable(timer, TIMER_INT_CH3);timer_enable(timer);timer_interrupt_flag_clear(timer, TIMER_INT_FLAG_UP);return;
}
(2)捕获中断处理函数
void TIMER1_IRQHandler(void)
{if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0)){gw_CAP_NUM_INT[0]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH1)){gw_CAP_NUM_INT[1]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH1);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH2)){gw_CAP_NUM_INT[2]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH2);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH3)){gw_CAP_NUM_INT[3]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH3);}
}
(3)速度计算公式
简单来说,就是看20ms内发生了多少个脉冲。
static void CALC_velocity_and_FRQ(void)
{UINT_8 i, j;UINT_32 sum[4] = {0, 0, 0, 0};UINT_32 every_pulse_tick_avg[4];.../* 获得速度脉冲计数和时钟脉冲计数 */for (i=0; i<=3; i++){gw_CAP_NUM_last[i] = gw_CAP_NUM[i];gl_CAP_TCNT_last[i] = gl_CAP_TCNT[i];/* 读取速度捕获脉冲中断计数值 */gw_CAP_NUM[i] = gw_CAP_NUM_INT[i];gl_CAP_TCNT[i] = timer_channel_capture_value_register_read(TIMER1, i); }/* for (i=0; i<=3; i++) *//* 计算速度脉冲计数和时钟脉冲计数的差值,并计算各轴速度 */for (i=0; i<=3; i++){/* 备份上个周期计算的差值 */gw_CAP_NUM_delta_backup[i] = gw_CAP_NUM_delta[i];gl_CAP_TCNT_delta_backup[i] = gl_CAP_TCNT_delta[i];/* 计算本周期的差值 */gw_CAP_NUM_delta[i] = gw_CAP_NUM[i] - gw_CAP_NUM_last[i];gl_CAP_TCNT_delta[i] = gl_CAP_TCNT[i] - gl_CAP_TCNT_last[i];if (gl_CAP_TCNT_delta[i] > 0) /* 除数为0处理 */{gw_velocity_value[i] = (gl_wheel_with_COEF[i] * gw_CAP_NUM_delta[i])/ gl_CAP_TCNT_delta[i];}...} /* for (i=0; i<=3; i++) */return;
} /* CALC_velocity_and_FRQ() */
原因查找:
经过代码排查,最后发现是下面两个原因导致的,芯片售后没有给出具体解释,我也搞不懂。
(1)库函数的原因
这版有问题的程序用的是V2.0.0
/*!\file gd32f4xx_timer.c\brief TIMER driver\version 2016-08-15, V1.0.0, firmware for GD32F4xx\version 2018-12-12, V2.0.0, firmware for GD32F4xx
*/...void timer_interrupt_flag_clear(uint32_t timer_periph, uint32_t interrupt)
{TIMER_INTF(timer_periph) &= (~(uint32_t)interrupt);
}...
需要用新版的库,V2.1.0以后好像都把上面那个“&”给去掉了,中断标志是硬件置位的,软件写0清标志,写1没有影响。按理来讲两种写法没有区别,但是不知道官方为什么会修正这个函数,可能有硬件设计方面的原因?
/*!\file gd32f4xx_timer.c\brief TIMER driver\version 2016-08-15, V1.0.0, firmware for GD32F4xx\version 2018-12-12, V2.0.0, firmware for GD32F4xx\version 2020-09-30, V2.1.0, firmware for GD32F4xx\version 2022-03-09, V3.0.0, firmware for GD32F4xx
*/void timer_interrupt_flag_clear(uint32_t timer_periph, uint32_t interrupt)
{TIMER_INTF(timer_periph) = (~(uint32_t)interrupt);
}
(2)timer_channel_capture_value_register()位置的原因
读取脉冲发生时刻timer_count寄存器值的函数timer_channel_capture_value_register()放在中断里,而不能放在20ms中断里。也是搞不懂。。。
uint32_t gl_timer_channel_capture_value[i]; /*用来存放触发时刻timer寄存器的值*/void TIMER1_IRQHandler(void)
{if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0)){gw_CAP_NUM_INT[0]++;gl_timer_channel_capture_value[0] = timer_channel_capture_value_register_read(TIMER1, 0); timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH1)){gw_CAP_NUM_INT[1]++;gl_timer_channel_capture_value[1] = timer_channel_capture_value_register_read(TIMER1, 1); timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH1);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH2)){gw_CAP_NUM_INT[2]++;gl_timer_channel_capture_value[2] = timer_channel_capture_value_register_read(TIMER1, 2); timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH2);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH3)){gw_CAP_NUM_INT[3]++;gl_timer_channel_capture_value[3] = timer_channel_capture_value_register_read(TIMER1, 3); timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH3);}
}
static void CALC_velocity_and_FRQ(void)
{UINT_8 i, j;UINT_32 sum[4] = {0, 0, 0, 0};UINT_32 every_pulse_tick_avg[4];.../* 获得速度脉冲计数和时钟脉冲计数 */for (i=0; i<=3; i++){gw_CAP_NUM_last[i] = gw_CAP_NUM[i];gl_CAP_TCNT_last[i] = gl_CAP_TCNT[i];/* 读取速度捕获脉冲中断计数值 */gw_CAP_NUM[i] = gw_CAP_NUM_INT[i];gl_CAP_TCNT[i] = gl_timer_channel_capture_value[i]; /*这里改用全局变量读取*/}/* for (i=0; i<=3; i++) *//* 计算速度脉冲计数和时钟脉冲计数的差值,并计算各轴速度 */for (i=0; i<=3; i++){/* 备份上个周期计算的差值 */gw_CAP_NUM_delta_backup[i] = gw_CAP_NUM_delta[i];gl_CAP_TCNT_delta_backup[i] = gl_CAP_TCNT_delta[i];/* 计算本周期的差值 */gw_CAP_NUM_delta[i] = gw_CAP_NUM[i] - gw_CAP_NUM_last[i];gl_CAP_TCNT_delta[i] = gl_CAP_TCNT[i] - gl_CAP_TCNT_last[i];if (gl_CAP_TCNT_delta[i] > 0) /* 除数为0处理 */{gw_velocity_value[i] = (gl_wheel_with_COEF[i] * gw_CAP_NUM_delta[i])/ gl_CAP_TCNT_delta[i];}...} /* for (i=0; i<=3; i++) */return;
} /* CALC_velocity_and_FRQ() */
有人遇到同样的问题吗?