2025-09-24 8:50 AM
I'm developing an application where I need to have both USART1 and LPUART1 configured to receive commands. I'm using STOP1 mode to ensure the commands can be received by both peripherals (USART1 will not work with STOP2 mode from my understanding). I'm seeing extremely weird behavior and it's perhaps the way I'm implementing the wake up.
The same exact setup I use in USART1 has a completely different current consumption with LPUART1. I have another MCU on my board but in STOP1 mode with USART1 enabled only I get about 500uA current consumption and when I swap it for LPUART1 I get 4mA.
# ENVIRONMENT
# PROBLEM DESCRIPTION
My application flow is as follows:
This exact same flow with LPUART1 consumes 4mA after the first reception. Functionally, it still works. With USART1 it stays at 500uA. Keep in mind I have another MCU on the board so I am aware that 500uA might be high but I'm not too surprised. I set an IO LOW when I'm asleep and it does actually show that the MCU goes to sleep in both scenarios. In either case I'm sending a PING once a second. I also must add that I occassionally do see it go to 500uA but it's only once in a blue moon. Is it related to LPUART1? How come it works every time with USART1?
# WHAT I'VE ALREADY TRIED
I thought it was the HSI on the LPUART1 but even when I switch the baudrate to 9600 and HSI to LSE as the clock source I'm still consuming a lot. My next assumption is that the DMA is the culprit. However, why would the DMA be a problem with LPUART1 but not with USART1.
# CONFIGURATION AND CODE
Unfortunately, unlike my other post, I cannot share entire files but I can share the core of it.
When I replace "LPUART1_EnterStopMode()" with "USART1_EnterStopMode()" the current consumption goes from 4mA to 500uA.
void UTIL_SEQ_Idle(void) {
#if (CFG_LPM_SUPPORTED == 1)
if (LPUART1_EnterStopMode()) {
UTIL_LPM_EnterLowPower();
}
#endif
}
stm32wbxx_it.c
void USART1_IRQHandler(void) {
HAL_UART_IRQHandler(&USART1_Handle);
}
void LPUART1_IRQHandler(void) {
HAL_UART_IRQHandler(&LPUART1_Handle);
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);
if (huart->Instance == LPUART1) {
LPUART1_RxHandler();
} else if (huart->Instance == USART1) {
USART1_RxHandler();
}
}
void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart) {
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF);
if (huart->Instance == LPUART1) {
LPUART1_WakeUpHandler();
} else if (huart->Instance == USART1) {
USART1_WakeupHandler();
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == LPUART1) {
LPUART1_ErrorHandler();
} else if (huart->Instance == USART1) {
USART1_ErrorHandler();
}
}
stm32wbxx_hal_msp.c
void HAL_UART_MspInit(UART_HandleTypeDef *huart) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if (huart->Instance == LPUART1) {
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;
PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
Error_Handler();
}
__HAL_RCC_LPUART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
DMA_Luart1RxHandle.Instance = DMA1_Channel3;
DMA_Luart1RxHandle.Init.Request = DMA_REQUEST_LPUART1_RX;
DMA_Luart1RxHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
DMA_Luart1RxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Luart1RxHandle.Init.MemInc = DMA_MINC_ENABLE;
DMA_Luart1RxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
DMA_Luart1RxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
DMA_Luart1RxHandle.Init.Mode = DMA_CIRCULAR;
DMA_Luart1RxHandle.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&DMA_Luart1RxHandle) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(huart, hdmarx, DMA_Luart1RxHandle);
DMA_Luart1TxHandle.Instance = DMA1_Channel4;
DMA_Luart1TxHandle.Init.Request = DMA_REQUEST_LPUART1_TX;
DMA_Luart1TxHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Luart1TxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Luart1TxHandle.Init.MemInc = DMA_MINC_ENABLE;
DMA_Luart1TxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
DMA_Luart1TxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
DMA_Luart1TxHandle.Init.Mode = DMA_NORMAL;
DMA_Luart1TxHandle.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&DMA_Luart1TxHandle) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(huart, hdmatx, DMA_Luart1TxHandle);
HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
} else if (huart->Instance == USART1) {
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_HSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
Error_Handler();
}
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
DMA_Uart1RxHandle.Instance = DMA1_Channel2;
DMA_Uart1RxHandle.Init.Request = DMA_REQUEST_USART1_RX;
DMA_Uart1RxHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
DMA_Uart1RxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Uart1RxHandle.Init.MemInc = DMA_MINC_ENABLE;
DMA_Uart1RxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
DMA_Uart1RxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
DMA_Uart1RxHandle.Init.Mode = DMA_CIRCULAR;
DMA_Uart1RxHandle.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&DMA_Uart1RxHandle) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(huart, hdmarx, DMA_Uart1RxHandle);
DMA_Uart1TxHandle.Instance = DMA1_Channel1;
DMA_Uart1TxHandle.Init.Request = DMA_REQUEST_USART1_TX;
DMA_Uart1TxHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Uart1TxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Uart1TxHandle.Init.MemInc = DMA_MINC_ENABLE;
DMA_Uart1TxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
DMA_Uart1TxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
DMA_Uart1TxHandle.Init.Mode = DMA_NORMAL;
DMA_Uart1TxHandle.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&DMA_Uart1TxHandle) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(huart, hdmatx, DMA_Uart1TxHandle);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
lpuart1.c
HAL_StatusTypeDef LPUART1_Initialize() {
LPUART1_Handle.Instance = LPUART1;
LPUART1_Handle.Init.BaudRate = 9600;
LPUART1_Handle.Init.WordLength = UART_WORDLENGTH_8B;
LPUART1_Handle.Init.StopBits = UART_STOPBITS_1;
LPUART1_Handle.Init.Parity = UART_PARITY_NONE;
LPUART1_Handle.Init.Mode = UART_MODE_TX_RX;
LPUART1_Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
LPUART1_Handle.Init.OverSampling = UART_OVERSAMPLING_8;
LPUART1_Handle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
LPUART1_Handle.Init.ClockPrescaler = UART_PRESCALER_DIV1;
LPUART1_Handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_StatusTypeDef res = HAL_UART_Init(&LPUART1_Handle);
if (res != HAL_OK) {
return res;
}
res = HAL_UARTEx_SetTxFifoThreshold(&LPUART1_Handle, UART_TXFIFO_THRESHOLD_1_8);
if (res != HAL_OK) {
return res;
}
res = HAL_UARTEx_SetRxFifoThreshold(&LPUART1_Handle, UART_RXFIFO_THRESHOLD_1_8);
if (res != HAL_OK) {
return res;
}
res = HAL_UARTEx_DisableFifoMode(&LPUART1_Handle);
if (res != HAL_OK) {
return res;
}
LPUART1ReadPos = 0;
// TASK INITIALIZATION
UTIL_SEQ_RegTask(1 << CFG_TASK_LPUART1_PROCESS, UTIL_SEQ_RFU, sLPUART1_ProcessBytesReceived);
UTIL_SEQ_RegTask(1 << CFG_TASK_LPUART1_TRANSMIT, UTIL_SEQ_RFU, sLPUART1_TransmitQueuedFrames);
__HAL_UART_ENABLE_IT(&LPUART1_Handle, UART_IT_IDLE);
return HAL_UARTEx_ReceiveToIdle_DMA(&LPUART1_Handle, LPUART1_RxDmaBuffer, LPUART1_RX_BUFFER_SIZE);
}
HAL_StatusTypeDef LPUART1_RxHandler(void) {
sLPUART1_IsFrameIncoming = false;
UTIL_SEQ_SetTask(1 << CFG_TASK_LPUART1_PROCESS, CFG_SCH_PRIO_0);
return HAL_OK;
}
HAL_StatusTypeDef LPUART1_ErrorHandler(void) {
LPUART1ReadPos = 0;
return HAL_UARTEx_ReceiveToIdle_DMA(&LPUART1_Handle, LPUART1_RxDmaBuffer, LPUART1_RX_BUFFER_SIZE);
}
HAL_StatusTypeDef LPUART1_WakeUpHandler(void) {
sLPUART1_IsFrameIncoming = true;
return HAL_OK;
}
bool LPUART1_EnterStopMode(void) {
if (sLPUART1_IsFrameIncoming) {
return false;
}
if (__HAL_UART_GET_FLAG(&LPUART1_Handle, USART_ISR_BUSY) == SET) {
return false;
}
if (__HAL_UART_GET_FLAG(&LPUART1_Handle, USART_ISR_REACK) == RESET) {
return false;
}
UART_WakeUpTypeDef wakeUpConfig = {0};
wakeUpConfig.WakeUpEvent = UART_WAKEUP_ON_STARTBIT;
HAL_UARTEx_StopModeWakeUpSourceConfig(&LPUART1_Handle, wakeUpConfig);
__HAL_UART_ENABLE_IT(&LPUART1_Handle, UART_IT_WUF);
HAL_UARTEx_EnableStopMode(&LPUART1_Handle);
return true;
}
void sLPUART1_TxHandler(const uint8_t* buffer, uint8_t size) {
HAL_UART_Transmit(&LPUART1_Handle, (uint8_t*)buffer, size, HAL_MAX_DELAY);
}
usart1.c
HAL_StatusTypeDef USART1_Initialize() {
USART1_Handle.Instance = USART1;
USART1_Handle.Init.BaudRate = 115200;
USART1_Handle.Init.WordLength = UART_WORDLENGTH_8B;
USART1_Handle.Init.StopBits = UART_STOPBITS_1;
USART1_Handle.Init.Parity = UART_PARITY_NONE;
USART1_Handle.Init.Mode = UART_MODE_TX_RX;
USART1_Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
USART1_Handle.Init.OverSampling = UART_OVERSAMPLING_8;
USART1_Handle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
USART1_Handle.Init.ClockPrescaler = UART_PRESCALER_DIV1;
USART1_Handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_StatusTypeDef res = HAL_UART_Init(&USART1_Handle);
if (res != HAL_OK) {
return res;
}
res = HAL_UARTEx_SetTxFifoThreshold(&USART1_Handle, UART_TXFIFO_THRESHOLD_1_8);
if (res != HAL_OK) {
return res;
}
res = HAL_UARTEx_SetRxFifoThreshold(&USART1_Handle, UART_RXFIFO_THRESHOLD_1_8);
if (res != HAL_OK) {
return res;
}
res = HAL_UARTEx_DisableFifoMode(&USART1_Handle);
if (res != HAL_OK) {
return res;
}
Usart1ReadPos = 0;
// TASK INITIALIZATION
UTIL_SEQ_RegTask(1 << CFG_TASK_USART1_PROCESS, UTIL_SEQ_RFU, sUSART1_ProcessBytesReceived);
UTIL_SEQ_RegTask(1 << CFG_TASK_USART1_TRANSMIT, UTIL_SEQ_RFU, sUSART1_TransmitQueuedFrames);
__HAL_UART_ENABLE_IT(&USART1_Handle, UART_IT_IDLE);
return HAL_UARTEx_ReceiveToIdle_DMA(&USART1_Handle, USART1_RxDmaBuffer, RX_BUFFER_SIZE);
}
HAL_StatusTypeDef USART1_RxHandler(void) {
sUSART1_IsFrameIncoming = false;
UTIL_SEQ_SetTask(1 << CFG_TASK_USART1_PROCESS, CFG_SCH_PRIO_0);
return HAL_OK;
}
HAL_StatusTypeDef USART1_ErrorHandler(void) {
Usart1ReadPos = 0;
return HAL_UARTEx_ReceiveToIdle_DMA(&USART1_Handle, USART1_RxDmaBuffer, RX_BUFFER_SIZE);
}
HAL_StatusTypeDef USART1_WakeupHandler(void) {
sUSART1_IsFrameIncoming = true;
return HAL_OK;
}
bool USART1_EnterStopMode(void) {
if (sUSART1_IsFrameIncoming) {
return false;
}
if (__HAL_UART_GET_FLAG(&USART1_Handle, USART_ISR_BUSY) == SET) {
return false;
}
if (__HAL_UART_GET_FLAG(&USART1_Handle, USART_ISR_REACK) == RESET) {
return false;
}
UART_WakeUpTypeDef wakeUpConfig = {0};
wakeUpConfig.WakeUpEvent = UART_WAKEUP_ON_STARTBIT;
HAL_UARTEx_StopModeWakeUpSourceConfig(&USART1_Handle, wakeUpConfig);
__HAL_UART_ENABLE_IT(&USART1_Handle, UART_IT_WUF);
HAL_UARTEx_EnableStopMode(&USART1_Handle);
return true;
}
void sUSART1_TxHandler(const uint8_t* buffer, uint8_t size) {
HAL_UART_Transmit(&USART1_Handle, (uint8_t*)buffer, size, HAL_MAX_DELAY);
}
Solved! Go to Solution.
2025-09-24 1:23 PM
# CONCLUSION
This is extremely embarrassing. It looks like the problem wasn't the STM32. It was my PIC that wasn't going back to sleep. I'm so sorry. Hopefully my setup will be useful to someone in the future.
2025-09-24 12:54 PM
# FOLLOW-UP
I concluded that the receive isn't the problem, it's the going to sleep after a transmission. For whatever reason, if I transmit and go into STOP1 mode AFTER the transmission is complete, it just remains at 4mA. When I receive a command and don't transmit anything the current consumption remains at 500uA. I'm trying to understand the timing of things, but so far this is all I can deduce.
2025-09-24 1:23 PM
# CONCLUSION
This is extremely embarrassing. It looks like the problem wasn't the STM32. It was my PIC that wasn't going back to sleep. I'm so sorry. Hopefully my setup will be useful to someone in the future.