2026-04-08 4:46 AM
I'm using LPTIM1 in encoder mode and have noticed that, if there's jitter on one of the encoder signals the count will gradually creep up which should not be possible in encoder mode.
This is on a decent encoder that's got an RC network (per the Bourns data sheet / appnote) in front of it too so this isn't nasty HF noise, it's good solid pulses of 50-100ms or more on one channel but the counter seems to creep up.
Identical encoders wired to TIM2 / TIM3 behave normally, and my colleague has seen the same issue in another project using the same setup - LPTIM has a problem where TIMx does not.
Init code for LPTIM1:
/* LPTIM1 init function */
void MX_LPTIM1_Init(void)
{
/* USER CODE BEGIN LPTIM1_Init 0 */
/* USER CODE END LPTIM1_Init 0 */
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_PCLK1);
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
/**LPTIM1 GPIO Configuration
PB5 ------> LPTIM1_IN1
PB7 ------> LPTIM1_IN2
*/
GPIO_InitStruct.Pin = ENC1_As_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(ENC1_As_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ENC1_Bs_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(ENC1_Bs_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN LPTIM1_Init 1 */
/* USER CODE END LPTIM1_Init 1 */
LL_LPTIM_SetClockSource(LPTIM1, LL_LPTIM_CLK_SOURCE_INTERNAL);
LL_LPTIM_SetPrescaler(LPTIM1, LL_LPTIM_PRESCALER_DIV1);
LL_LPTIM_SetPolarity(LPTIM1, LL_LPTIM_OUTPUT_POLARITY_REGULAR);
LL_LPTIM_SetUpdateMode(LPTIM1, LL_LPTIM_UPDATE_MODE_IMMEDIATE);
LL_LPTIM_SetCounterMode(LPTIM1, LL_LPTIM_COUNTER_MODE_EXTERNAL);
LL_LPTIM_ConfigClock(LPTIM1, LL_LPTIM_CLK_FILTER_NONE, LL_LPTIM_CLK_POLARITY_RISING);
LL_LPTIM_TrigSw(LPTIM1);
LL_LPTIM_SetInput1Src(LPTIM1, LL_LPTIM_INPUT1_SRC_GPIO);
LL_LPTIM_SetInput2Src(LPTIM1, LL_LPTIM_INPUT2_SRC_GPIO);
/* USER CODE BEGIN LPTIM1_Init 2 */
/*
* To activate the Encoder mode the ENC bit has to be set to ‘1’. The LPTIM must first be
* configured in Continuous mode.
* When Encoder mode is active, the LPTIM counter is modified automatically following the
* speed and the direction of the incremental encoder.
*/
LL_LPTIM_StartCounter(LPTIM1,LL_LPTIM_OPERATING_MODE_CONTINUOUS);
// This function must be called when the LPTIM instance is disabled.
LL_LPTIM_SetEncoderMode(LPTIM1, LL_LPTIM_ENCODER_MODE_RISING/*_FALLING*/);
/*
* This function must be called when the LPTIM instance is disabled.
* In this mode the LPTIM instance must be clocked by an internal clock
* source. Also, the prescaler division ratio must be equal to 1.
* LPTIM instance must be configured in continuous mode prior enabling
* the encoder mode.
*/
LL_LPTIM_EnableEncoderMode(LPTIM1);
LL_LPTIM_Enable(LPTIM1);
/*
* The counter just counts continuously between 0 and the
* auto-reload value programmed into the LPTIM_ARR register
* (0 up to ARR or ARR down to 0 depending on the direction).
* Therefore LPTIM_ARR must be configured before starting
*/
LL_LPTIM_SetAutoReload(LPTIM1, ENCODER_RELOAD);
//LPTIM instance must be enabled before starting the counter.
LL_LPTIM_StartCounter(LPTIM1,LL_LPTIM_OPERATING_MODE_CONTINUOUS);
/* USER CODE END LPTIM1_Init 2 */
}
2026-04-09 5:00 AM
OK I see you've already enabled the glitch filter - did it make any difference?
JW
2026-04-09 6:48 AM
2026-04-14 2:13 AM
Well even trying a wrinkle mentioned in the reference manual didn't help...
RM0444 pg 842:
It should be noted that to read reliably the content of the LPTIM_CNT register two
successive read accesses must be performed and compared. A read access can be
considered reliable when the value of the two read accesses is equal. Unfortunately
when asynchronous reset is enabled there is no possibility to read twice the
LPTIM_CNT register.
The code:
// Read counter until value is the same twice
while(now != chk)
{
if(e > 0)
{
NOP;
}
now = LL_LPTIM_GetCounter((LPTIM_TypeDef *)gEncs[enc]);
chk = LL_LPTIM_GetCounter((LPTIM_TypeDef *)gEncs[enc]);
e++;
}Unless I span the encoder very fast I never saw the two values disagree with each other, even while the encoder count was creeping up with successive up/down twiddling of the encoder.
So, is there some bug with the LPTIM peripheral or have I missed something else in the code / config?