cancel
Showing results for 
Search instead for 
Did you mean: 

G071 LPTIM encoder mode creeps around

JU
Senior

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 */
}

 

12 REPLIES 12
waclawek.jan
Super User

OK I see you've already enabled the glitch filter - did it make any difference?

JW

No difference - wiggling the encoder produces the fairly clean pulse train in the trace below and a string of counts in one direction only (count rising).

I'm modifying my code to spit out the raw count rather than deltas just to see if anything leaps out.

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?