STM32WLE5 System hangs / infinite loop in modem_supervisor_init() during MX_LoRaWAN_Init()
Hello STM32 Community,
I am encountering an issue on an STM32WL project using the ST LoRaWAN Middleware stack. When I enable and call MX_LoRaWAN_Init(), the MCU gets stuck or enters an infinite loop inside modem_supervisor_init() in modem_supervisor_light.c.
Environment Details
MCU: STM32WLE5CCU6
Board: RAK3172 Module
CubeMX / Firmware Package: STM32CubeWL v1.6.0
Problem Description
When calling MX_LoRaWAN_Init(), execution fails inside modem_supervisor_init(). Debugging shows execution stuck in the for loop below :
void modem_supervisor_init( void )
{
memset( &task_manager, 0, sizeof( stask_manager ) );
for( uint8_t i = 0; i < NUMBER_OF_TASKS * NUMBER_OF_STACKS; i++ )
{
task_manager.modem_task[i].priority = TASK_FINISH;
task_manager.modem_task[i].id = ( task_id_t ) i;
task_manager.modem_task[i].stack_id = 0;
task_manager.modem_task[i].updated_locked = false;
}
........
}What I Have Checked / Observed
Clock & Peripheral Init: RTC, SubGHzSPI, and RNG are initialized prior to calling MX_LoRaWAN_Init().
Sequencer: UTIL_SEQ_Init() and UTIL_TIMER_Init() are called.
Behavior: Halting execution with a debugger shows it never completes modem_supervisor_init().
Any insights or recommendations on how to debug this further would be greatly appreciated!
Thanks in advance.
Here is the main.c code:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "app_lorawan.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32_seq.h"
#include "stm32_timer.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LED_PORT GPIOA
#define LED_PIN GPIO_PIN_1
#define LED_BLINK_PERIOD_MS 500U /* toggle period -> ~1 Hz blink */
#define BTN_DEBOUNCE_MS 200U
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
RNG_HandleTypeDef hrng;
RTC_HandleTypeDef hrtc;
SUBGHZ_HandleTypeDef hsubghz;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
static UTIL_TIMER_Object_t LedBlinkTimer;
static volatile uint8_t BlinkEnabled = 1;
static volatile uint32_t LastBtnTick = 0;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RNG_Init(void);
/* USER CODE BEGIN PFP */
static void LedBlinkTimer_Cb(void *context);
static void LedToggle_Task(void);
static void ButtonPress_Task(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/**
* @brief UTIL_TIMER callback, fired every LED_BLINK_PERIOD_MS.
* Keep it short: just schedule the sequencer task, never touch
* GPIO or do real work directly inside a timer/IRQ callback.
*/
static void LedBlinkTimer_Cb(void *context)
{
UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_LedToggle), CFG_SEQ_Prio_0);
}
/**
* @brief Sequencer task: actually toggles the LED pin.
*/
static void LedToggle_Task(void)
{
HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
}
/**
* @brief Sequencer task: handles a debounced button press.
* Toggles BlinkEnabled and starts/stops the blink timer.
*/
static void ButtonPress_Task(void)
{
BlinkEnabled = !BlinkEnabled;
if (BlinkEnabled)
{
UTIL_TIMER_Start(&LedBlinkTimer);
}
else
{
UTIL_TIMER_Stop(&LedBlinkTimer);
/* Force LED off so it doesn't get stuck lit mid-blink */
HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET);
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_RNG_Init();
MX_LoRaWAN_Init();
/* USER CODE BEGIN 2 */
/* Register sequencer tasks (IDs come from utilities_def.h) */
UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_LedToggle), UTIL_SEQ_RFU, LedToggle_Task);
UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_ButtonPress), UTIL_SEQ_RFU, ButtonPress_Task);
/* Create and start the periodic LED blink timer */
UTIL_TIMER_Create(&LedBlinkTimer, LED_BLINK_PERIOD_MS, UTIL_TIMER_PERIODIC,
LedBlinkTimer_Cb, NULL);
UTIL_TIMER_Start(&LedBlinkTimer);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
// MX_LoRaWAN_Process();
/* USER CODE BEGIN 3 */
UTIL_SEQ_Run(UTIL_SEQ_DEFAULT);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE
|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_10;
RCC_OscInitStruct.LSIDiv = RCC_LSI_DIV1;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Enable MSI Auto calibration
*/
HAL_RCCEx_EnableMSIPLLMode();
/** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK
|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief RNG Initialization Function
* @param None
* @retval None
*/
static void MX_RNG_Init(void)
{
/* USER CODE BEGIN RNG_Init 0 */
/* USER CODE END RNG_Init 0 */
/* USER CODE BEGIN RNG_Init 1 */
/* USER CODE END RNG_Init 1 */
hrng.Instance = RNG;
hrng.Init.ClockErrorDetection = RNG_CED_ENABLE;
if (HAL_RNG_Init(&hrng) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN RNG_Init 2 */
/* USER CODE END RNG_Init 2 */
}
/**
* @brief RTC Initialization Function
* @param None
* @retval None
*/
void MX_RTC_Init(void)
{
/* USER CODE BEGIN RTC_Init 0 */
/* USER CODE END RTC_Init 0 */
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
RTC_AlarmTypeDef sAlarm = {0};
/* USER CODE BEGIN RTC_Init 1 */
/* USER CODE END RTC_Init 1 */
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
hrtc.Init.BinMode = RTC_BINARY_NONE;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Check_RTC_BKUP */
/* USER CODE END Check_RTC_BKUP */
/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 0x0;
sTime.Minutes = 0x0;
sTime.Seconds = 0x0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x1;
sDate.Year = 0x0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
/** Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 0x0;
sAlarm.AlarmTime.Minutes = 0x0;
sAlarm.AlarmTime.Seconds = 0x0;
sAlarm.AlarmTime.SubSeconds = 0x0;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 0x1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN RTC_Init 2 */
/* USER CODE END RTC_Init 2 */
}
/**
* @brief SUBGHZ Initialization Function
* @param None
* @retval None
*/
void MX_SUBGHZ_Init(void)
{
/* USER CODE BEGIN SUBGHZ_Init 0 */
/* USER CODE END SUBGHZ_Init 0 */
/* USER CODE BEGIN SUBGHZ_Init 1 */
/* USER CODE END SUBGHZ_Init 1 */
hsubghz.Init.BaudratePrescaler = SUBGHZSPI_BAUDRATEPRESCALER_8;
if (HAL_SUBGHZ_Init(&hsubghz) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SUBGHZ_Init 2 */
/* USER CODE END SUBGHZ_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pin : PA1 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : BTN_Pin */
GPIO_InitStruct.Pin = BTN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(BTN_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/**
* @brief HAL GPIO EXTI callback, fired from the EXTI9_5 IRQ handler.
* Keep this minimal: debounce with a tick check, then only
* schedule a sequencer task. No blocking calls, no HAL_Delay,
* no direct GPIO toggling here.
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == BTN_Pin)
{
uint32_t now = HAL_GetTick();
if ((now - LastBtnTick) > BTN_DEBOUNCE_MS)
{
LastBtnTick = now;
UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_ButtonPress), CFG_SEQ_Prio_0);
}
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
