Quadrature Decoder Sometimes Fails to Reload When Passing Through 0 on STM32L151
I'm seeing a strange issue with the Quadrature Decoder functionality with TIM3 and TIM4 on STM32L151 (also seeing the same issue on a NUCLEO-L152RE). Sometimes when the count decrements to zero, the counter doesn't reload. Sometimes it does, picking up the reload value I set. In contrast, when the counter reaches 0xFFFF it always rolls over properly.
I'm using the Zephyr QDEC driver, which configures the timer like this:
static int qdec_stm32_initialize(const struct device *dev)
{
const struct qdec_stm32_dev_cfg *const dev_cfg = dev->config;
int retval;
LL_TIM_ENCODER_InitTypeDef init_props;
uint32_t max_counter_value;
retval = pinctrl_apply_state(dev_cfg->pin_config, PINCTRL_STATE_DEFAULT);
if (retval < 0) {
return retval;
}
if (!device_is_ready(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE))) {
LOG_ERR("Clock control device not ready");
return -ENODEV;
}
retval = clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),
(clock_control_subsys_t)&dev_cfg->pclken);
if (retval < 0) {
LOG_ERR("Could not initialize clock");
return retval;
}
if (dev_cfg->counts_per_revolution < 1) {
LOG_ERR("Invalid number of counts per revolution (%d)",
dev_cfg->counts_per_revolution);
return -EINVAL;
}
LL_TIM_ENCODER_StructInit(&init_props);
if (dev_cfg->is_input_polarity_inverted) {
init_props.IC1ActiveInput = LL_TIM_IC_POLARITY_FALLING;
init_props.IC2ActiveInput = LL_TIM_IC_POLARITY_FALLING;
}
init_props.IC1Filter = dev_cfg->input_filtering_level * LL_TIM_IC_FILTER_FDIV1_N2;
init_props.IC2Filter = dev_cfg->input_filtering_level * LL_TIM_IC_FILTER_FDIV1_N2;
/* Ensure that the counter will always count up to a multiple of counts_per_revolution */
if (IS_TIM_32B_COUNTER_INSTANCE(dev_cfg->timer_inst)) {
max_counter_value = UINT32_MAX - (UINT32_MAX % dev_cfg->counts_per_revolution) - 1;
} else {
max_counter_value = UINT16_MAX - (UINT16_MAX % dev_cfg->counts_per_revolution) - 1;
}
LL_TIM_SetAutoReload(dev_cfg->timer_inst, max_counter_value);
if (LL_TIM_ENCODER_Init(dev_cfg->timer_inst, &init_props) != SUCCESS) {
LOG_ERR("Initalization failed");
return -EIO;
}
LL_TIM_EnableCounter(dev_cfg->timer_inst);
return 0;
}Is there something I'm missing in how the decoder needs to be configured?
