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

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

 

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

 

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.