STM32G4实现正交脉冲T法测速
1. 现状
在ST MCSDK中对正交脉冲测速时仅实现了M法测速,即根据特定周期内的脉冲数来计算当前的速度,当速度很低,或者说脉冲频率很低时,测得的速度误差或者波动就很大。以下是测试条件和对应的测试数据:
Encoder PPR: 1024
Speed Calc Rate: 4KHz
Unit: 0.01Hz
HW: NUCLEO-G431RB
测试的输入脉冲是由TIM1生成的,后面会讲到如何配置.
从测试数据来看,在低速时M法测速的分辨率只有0.25Hz,而且在不停地跳动。
2. 解决方案
STM32 MCU Timer有一些互联的Feature,可以用来实现此功能,此方法的优点是无需额外的引脚,充分利用定时器之间的内部连接:
- Encoder模式下Encoder Clock 可以作为TRGO对外输出,作为下一个TIM的Trigger输入。如下图所示。此功能好像是STM32G4之后才有的,因此本文所述功能可能要G4之后的MCU才能实现
- TimerA的TRGO可以作为捕获的触发信号,用来捕获TimerB的计数脉宽。
因此,可以用TimerA作为Encoder解码,然后将Encoder Clock Output作为TimerA的TRGO和TimerB的捕获触发,来测量正交脉冲的脉宽。配置外设资源时,有以下两点需要考量:
- 当电机转速高的时候,脉冲的频率可能很高,MCU无法处理每次捕获,因此需要DMA将捕获到的脉宽静默地转移到RAM中。
- 需要用32位的Timer来做捕获,而用16位的Timer来解码。如G4的主频为170M,如果用16位Timer作为捕获的话,能分辨的最小脉冲频率为: 170 M H z / 65536 ≈ 2593 H z 170MHz/65536 \approx 2593Hz 170MHz/65536≈2593Hz, 这个频率还是相当高的,对1024线的编码器来说还大于0.5Hz,所以一般需要将Timer3作为解码,Timer2作为捕获,这样可以获得 170 M H z / 2 32 ≈ 0.04 H z 170MHz/2^{32}\approx0.04Hz 170MHz/232≈0.04Hz的脉冲频率,这个分辨率还是相当可以的。笔者也试过用16位Timer捕获然后用诸如调整Prescaler的方法提高分辨率,但是因捕获与速度计算在时间上的异步问题,目前还没解决,在低速时仍会出错。
- 编码器的脉冲解码后的四倍频脉宽会因为制造上的原因造成宽度不相等,所以一般捕获单路脉冲的一个完整周期,然后用类似滑动窗口滤波的方式来计算速度。这里可以充分利用4路捕获来降低软件的负担
因此可以得到外设资源的配置大致如下:
3. 测试环境搭建
STM32G4 MCU的部分Timer上有一个功能叫 Asymmetric PWM Mode,正好可以用来产生正交脉冲,这样就可以把真实的编码器也省了,仅用一块开发板即可以完成测试。各外设STM32CubeMX中的配置截图如下:
- Pinout:
- Timer1 as quadrature pulse generator:
- Timer3 as quadrature pulse decoder:
- Timer2 as capture timer:
4. 测试结果
下图是在一个斜坡速度下的测量结果:
可以看到在0.2Hz以下显示会有动态测量误差,但此误差未必真实存在,至少不会这么大,因为设定速度是在后台以每2ms速度更新的:
static uint32_t timeStamp = 0;
static int16_t acc = 1;
static int16_t dir = 1;
if (HAL_GetTick() - timeStamp > 2) {
speedRpm += acc * dir;
if (speedRpm > 3000) {
dir = -1;
} else if (speedRpm < 3) {
dir = 1;
}
timeStamp = HAL_GetTick();
}
但真实的脉宽更新是在Timer1的Update中断里进行的,所以脉冲的输出并不能实时跟踪设定的速度:
void UpdateEncoderOutput(void)
{
if (prevSpeedRpm != speedRpm) {
uint32_t counterPerSecond = (uint32_t)(speedRpm * M1_ENCODER_PPR / 60);
uint32_t SysClockFreq = HAL_RCC_GetSysClockFreq();
uint32_t pulseWidth = SysClockFreq / (2 * counterPerSecond);
uint16_t prescale = 0;
if (pulseWidth > 0xFFFF) {
prescale = pulseWidth >> 16;
pulseWidth /= (prescale + 1);
}
// pulseWidth = (SysClockFreq >> prescale) / (2 * counterPerSecond);
LL_TIM_SetAutoReload(TIM1, pulseWidth);
LL_TIM_SetPrescaler(TIM1, prescale);
LL_TIM_OC_SetCompareCH1(TIM1, 0);
LL_TIM_OC_SetCompareCH2(TIM1, pulseWidth);
LL_TIM_OC_SetCompareCH3(TIM1, pulseWidth >> 1);
LL_TIM_OC_SetCompareCH4(TIM1, pulseWidth >> 1);
prevSpeedRpm = speedRpm;
}
}
当然,因为速度是以4个脉冲宽度来计算速度的,一定会有延时,在低速时尤其明显,但稳态(即速度为恒定时)时误差会要好得多。
这是在0.1Hz时两种方法的细节对比:
从图片可以直观地看到T法的测量结果要比M法的精度高得多。
下图是在不同的恒定速度下测量误差精度的统计,可以看到低速时的测量误差T法要优于M法一个数量级以上。
全文完结