cancel
Showing results for 
Search instead for 
Did you mean: 

LPTIM with external clock (no synchronization – STM32L0)

ToStei
Associate II

Dear all,

I am working on a project with an L081KZ and want to count pulses with a frequency higher than the clock. In the post here (community.st.com/s/question/0D53W00001EyzG5SAJ/) I thankfully got the tip to use the LPTIM as it has an asynchronous feature.

Sadly I cant get the LPTIM to run at all with an external clock and would like your help. There must be a fundamental problem I am overlooking.

I apply a signal (quite slow with 1kHz and 3Vpp) onto PB5 / LPTIM but neither do I get a 1/20th of the signal (counting to 10 and 2 times because of the toggle-function) on PB3 / TOGGLE nor do I reach the breakpoints in “LPTIM1_IRQHandler�?. In “Instance�? → “CNT�? is always 0.

Looking at the “Low-power timer block diagram“ i get i want the „LPTIM_IN1„ as input and not the trigger so I don’t get constrains by the Mux. Do I need to specify anywhere that it is PB5 or is it implied as there is no other pin possible? Also I activated the interrupt checkbox NVIC.

I configured the LPTIM via the CubeIDE as shown in the image and tried the minimal code shown below.

I would really appreciate a hint on what I am missing or where my assumptions are wrong.

Best wishes

Tobias

0693W00000HntvSQAR.jpg 

#include "main.h"
 
LPTIM_HandleTypeDef hlptim1;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_LPTIM1_Init(void);
 
/* USER CODE BEGIN*/
void  HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
}
/* USER CODE END*/
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_LPTIM1_Init();
  /* USER CODE BEGIN*/
  HAL_LPTIM_Counter_Start_IT(&hlptim1, 10);
  /* USER CODE END*/
  while (1)
  {
  }
}
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV16;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
  PeriphClkInit.LptimClockSelection = RCC_LPTIM1CLKSOURCE_PCLK;
 
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_LPTIM1_Init(void)
{
  hlptim1.Instance = LPTIM1;
  hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_ULPTIM;
  hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
  hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING;
  hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
  hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
  hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
  hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
  hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL;
  if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOB_CLK_ENABLE();
  HAL_GPIO_WritePin(TOGGLE_GPIO_Port, TOGGLE_Pin, GPIO_PIN_RESET);
  GPIO_InitStruct.Pin = TOGGLE_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(TOGGLE_GPIO_Port, &GPIO_InitStruct);
}
 
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}
 
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

1 ACCEPTED SOLUTION

Accepted Solutions
ToStei
Associate II

Dear all,

i would like to post a solution i found, so that others have it a bit easier.

Hardware:

  • STM32L081KZTx (LQFP32) but it should wok with other MCUs too
  • Impulse input is the pin selected by the CubeIDE - PB5

Software:

  • FW_L0 1.12.12
  • Configuration through CubeMX / CubeIDE
  • using HAL and LL

I use the configuration as shown in the image with the checkbox for NVIC. The generated code is via HAL but the solution utilizes some LL functions, so we need to include "stm32l0xx_ll_lptim.h" from \STM32Cube\Repository\STM32Cube_FW_LXXXXXXXX\Drivers\STM32L0xx_HAL_Driver\Inc . After initializing the LPTIM we can set the missing bits with two of these LL functions whereafter the timer works as expected, counting up the pulses of a source with a frequency higher or lower than the system clock. Below you can find the minimal code I used successfully.

Best wishes

Tobias

#include "main.h"
 
/* USER CODE BEGIN*/
#include "stm32l0xx_ll_lptim.h"
/* USER CODE END*/
 
LPTIM_HandleTypeDef hlptim1;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_LPTIM1_Init(void);
 
/* USER CODE BEGIN*/
void  HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
	//ping - here LPTIM reached the count 1000 - do somethings like
	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); //toggle PB3 as a feedback
}
/* USER CODE END*/
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_LPTIM1_Init();
  /* USER CODE BEGIN*/
  HAL_LPTIM_Counter_Start_IT(&hlptim1, 1000); //counts to 1000 than polls an interrupt
  LL_LPTIM_EnableIT_ARRM(LPTIM1); // low level enable interrupt on autoreload match
  LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS); // low level start the counter in continuous
  /* USER CODE END*/
  while (1)
  {
  }
}
 
 
//no changes from here onward
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV16;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
  PeriphClkInit.LptimClockSelection = RCC_LPTIM1CLKSOURCE_PCLK;
 
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_LPTIM1_Init(void)
{
  hlptim1.Instance = LPTIM1;
  hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_ULPTIM;
  hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
  hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING;
  hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
  hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
  hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
  hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
  hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL;
  if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOB_CLK_ENABLE();
  HAL_GPIO_WritePin(TOGGLE_GPIO_Port, TOGGLE_Pin, GPIO_PIN_RESET);
  GPIO_InitStruct.Pin = TOGGLE_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(TOGGLE_GPIO_Port, &GPIO_InitStruct);
}
 
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}
 
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

View solution in original post

4 REPLIES 4

Read out and check/post LPTIM and relevant GPIO registers content.

JW

Dear @Community member​ ,

thank you again very much for your answer.

I hope the attached register is what you want? If not please be so kind and refer me to the specific part (I'm quite new to the STMverse and HAL especially). I didn't post the GPIO register because the pin cant be toggled if the LPTIM doesn't count up and the Callback isnt polled (breakpoint is not reached).

Best wishes

Tobias0693W00000Hnus5QAB.jpg 

> I didn't post the GPIO register

Read out, check/post them (GPIOB) - PB5 has to be set to AF in MODER, and the LPTIM AF number has to be set for it in AFR.

JW

ToStei
Associate II

Dear all,

i would like to post a solution i found, so that others have it a bit easier.

Hardware:

  • STM32L081KZTx (LQFP32) but it should wok with other MCUs too
  • Impulse input is the pin selected by the CubeIDE - PB5

Software:

  • FW_L0 1.12.12
  • Configuration through CubeMX / CubeIDE
  • using HAL and LL

I use the configuration as shown in the image with the checkbox for NVIC. The generated code is via HAL but the solution utilizes some LL functions, so we need to include "stm32l0xx_ll_lptim.h" from \STM32Cube\Repository\STM32Cube_FW_LXXXXXXXX\Drivers\STM32L0xx_HAL_Driver\Inc . After initializing the LPTIM we can set the missing bits with two of these LL functions whereafter the timer works as expected, counting up the pulses of a source with a frequency higher or lower than the system clock. Below you can find the minimal code I used successfully.

Best wishes

Tobias

#include "main.h"
 
/* USER CODE BEGIN*/
#include "stm32l0xx_ll_lptim.h"
/* USER CODE END*/
 
LPTIM_HandleTypeDef hlptim1;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_LPTIM1_Init(void);
 
/* USER CODE BEGIN*/
void  HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
	//ping - here LPTIM reached the count 1000 - do somethings like
	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); //toggle PB3 as a feedback
}
/* USER CODE END*/
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_LPTIM1_Init();
  /* USER CODE BEGIN*/
  HAL_LPTIM_Counter_Start_IT(&hlptim1, 1000); //counts to 1000 than polls an interrupt
  LL_LPTIM_EnableIT_ARRM(LPTIM1); // low level enable interrupt on autoreload match
  LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS); // low level start the counter in continuous
  /* USER CODE END*/
  while (1)
  {
  }
}
 
 
//no changes from here onward
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV16;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
  PeriphClkInit.LptimClockSelection = RCC_LPTIM1CLKSOURCE_PCLK;
 
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_LPTIM1_Init(void)
{
  hlptim1.Instance = LPTIM1;
  hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_ULPTIM;
  hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
  hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING;
  hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
  hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
  hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
  hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
  hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL;
  if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOB_CLK_ENABLE();
  HAL_GPIO_WritePin(TOGGLE_GPIO_Port, TOGGLE_Pin, GPIO_PIN_RESET);
  GPIO_InitStruct.Pin = TOGGLE_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(TOGGLE_GPIO_Port, &GPIO_InitStruct);
}
 
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}
 
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif