cancel
Showing results for 
Search instead for 
Did you mean: 

LPTIM not counting down in encoder mode, always counts up (G071)

JU
Associate III

I have an STM32G071CBTx with a rotary encoder wired to GPIO pins PB5 + PB7 (LPTIM1_IN1 and LPTIM1_IN2), but for some reason it will never count down no matter which way the encoder is turned.

I have checked the encoder waveforms and they are as expected, and it's not just "rattling" with one input stuck low or high as I can make the counter run through the full count range by turning the encoder.

Initialisation code (LL) looks like this:

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

	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);

	/*
	 * 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);
	LL_LPTIM_SetEncoderMode(LPTIM1, LL_LPTIM_ENCODER_MODE_RISING_FALLING);



	/* USER CODE END LPTIM1_Init 2 */

}

Reading the counter is always starts at 0 and when I turn the encoder it only ever counts UP before wrapping.

I tried setting LL_LPTIM_ConfigClock(LPTIM1, LL_LPTIM_CLK_FILTER_NONE, LL_LPTIM_CLK_POLARITY_RISING) to LL_LPTIM_CLK_POLARITY_RISING_FALLING but it made no difference.

 What am I doing wrong here?

1 ACCEPTED SOLUTION

Accepted Solutions
JU
Associate III

Well I'm going to answer my own question - by trawling the HAL library, the LL header files and the docs I've arrived at this which does appear to work correctly:

/* LPTIM1 init function */
void MX_LPTIM1_Init(void)
{

	/* USER CODE BEGIN LPTIM1_Init 0 */
	LL_LPTIM_Disable(LPTIM1);
	/* 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_FALLING);
	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 */

}

 

A bit disappointing that the CubeMX/CubeIDE yet again doesn't generate working code but only a part of the initialisation with not even a comment about what's left out.

View solution in original post

1 REPLY 1
JU
Associate III

Well I'm going to answer my own question - by trawling the HAL library, the LL header files and the docs I've arrived at this which does appear to work correctly:

/* LPTIM1 init function */
void MX_LPTIM1_Init(void)
{

	/* USER CODE BEGIN LPTIM1_Init 0 */
	LL_LPTIM_Disable(LPTIM1);
	/* 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_FALLING);
	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 */

}

 

A bit disappointing that the CubeMX/CubeIDE yet again doesn't generate working code but only a part of the initialisation with not even a comment about what's left out.