How to wake up the STM32U5 from STOP2 using LPUART?
This article will show you how wake up the STM32U5 MCU from Stop 2 Low Power mode using the LPUART1 supplied by LSE or HSI Clock Source. By the end of this article, you will know the needed steps to properly set the LPUART, RCC and PWR peripheral registers in order to maintain the LPUART1 running while in low power mode and prepared it to wake up the MCU when receiving any data.
For this tutorial, a NUCLEO-U575ZI-Q with an STM32U575ZIT6Q will be used, but the steps should be the same for any STM32U5, with very minor adjustments.
To get startetd, open the STM32CubeIDE and create a new project with the microcontroller you’re using and give it a name you desire.1. Click on File -> New -> STM32 Project 2. In the STM32 Target selector, find for you microcontroller, you can type the part number to easy navigation, then click NEXT. In our case the STM32U575ZIT6Q will be used. 3. Give a name (avoid special characters and space) for your project and click FINISH: Now, all the steps regarding the project creation are done. In the opened MCU configuration tool, let’s set the LPUART1, GPIOs and overall RCC settings.4. In the list, look for CONNECTIVITY -> LPUART1: 5. Change the LPUART Mode to ASYNCHRONOUS using the drop-down list: 6. The peripheral settings can be left as default, but you can freely change to accommodate your application's necessity (just make sure to select a Baud Rate compatible with your clock settings selection, refer to the MCU Reference Manual for more details). 7. We should enable the LPUART1 GLOBAL INTERRUPT at NVIC. For this, open the System Core -> NVCI, then enable the respective interrupt: 8. Now, configure the PG7 as GPIO_Output (this step is optional, it PG7 is tied to the LED available on the Nucleo Board). We will use the name LED_BLUE in the code as a macro relating the GPIO: 9. Select the LPUART1 Clock Source in the CLOCK CONFIGURATION tab. You can only select the LSE, HSI or MSIK source, because only these are able to maintain the LPUART working in the Stop 2 Mode. In this example, you can select the HSI or the LSE (please be aware that whenever using the LSE as the clock source, the LPUART Baud Rate upper limited is 9600). 9.1 OPTIONAL: If you’re planning to use the LSE, don’t forget to enable the crystal at System Core -> RCC selecting the Crystal/Ceramic Resonator setting at Low Speed Clock (LSE) drop-down list: 10. Now, all the settings are done. You can generate the code, clicking on DEVICE CONFIGURATION TOOL CODE GENERATION, or using the Alt + k shortcut for it. 11. All the code changes will be made at MAIN.C file, so open it in your project tree at Project Explorer tab, the next steps will give the necessary code for the implementation. The most important topics of the firmware implementation are explained in the next text topic. Open the main.c file and include the STDIO.H library which some resources will be used.
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
12. Add the following define, you cna uncomment this line if you’re using the LSE as LPUART clock source:
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define USE_LPUART_LSE 0x55
/* USER CODE END PD */
13. Declare these global variables that will be used for buffering the incoming data and flagging it:
/* USER CODE BEGIN PV */
uint8_t u8pData[2];
uint8_t u8UartRxFlag;
/* USER CODE END PV */
14. Create the function prototype:
/* USER CODE BEGIN PFP */
void EnterStopMode(void);
/* USER CODE END PFP */
15. Add the following code to redirect the printf content to the LPUART1 (for further details of this implementation, refer the related article shown in the reference links at the final of this article):
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int __io_putchar(int ch)
{
HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch,1,1000);
return ch;
}
/* USER CODE END 0 */
16. After the peripheral initialization add the code below:
/* USER CODE BEGIN 2 */
#ifndef USE_LPUART_LSE
/* Specify HSI as the clock source used after wake up from stop mode */
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
__HAL_RCC_KERWAKEUPSTOP_CLK_CONFIG(RCC_STOP_KERWAKEUPCLOCK_HSI);
#endif
printf("LPUART DEMO WFI\r\n");
printf("Press 'p' to enter in low power\r\n");
HAL_UART_Receive_IT(&hlpuart1, u8pData, 1);
/* USER CODE END 2 */
17. Add the following code into the while infinite loop:
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_RESET);
printf("LED OFF\r\n");
HAL_Delay(200);
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_SET);
printf("LED ON\r\n");
HAL_Delay(200);
if(u8UartRxFlag)
{
if(u8pData[0] == 'p')
{
EnterStopMode();
}
else
{
printf("Press 'p' to enter in low power\r\n");
}
u8UartRxFlag = 0;
}
/* USER CODE END 3 */
18. Finally add the Receive Complete Callback function and the custom function to enter in STOP2 mode:
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
u8UartRxFlag = 1;
HAL_UART_Receive_IT(&hlpuart1, u8pData, 1);
}
void EnterStopMode(void)
{
/* Make sure that no LPUART transfer is on-going */
while (__HAL_UART_GET_FLAG(&hlpuart1, USART_ISR_BUSY) == SET);
/* Make sure that LPUART is ready to receive */
while (__HAL_UART_GET_FLAG(&hlpuart1, USART_ISR_REACK) == RESET);
/* Enable the LPUART clock in Autonomous Mode */
__HAL_RCC_LPUART1_CLKAM_ENABLE();
/* Enable the LPUART in Stop Mode */
HAL_UARTEx_EnableStopMode(&hlpuart1);
#ifndef USE_LPUART_LSE
/* Enable the HSI Clock source while in STOP Mode */
__HAL_RCC_HSISTOP_ENABLE();
#endif
/* Suspend the SysTick */
HAL_SuspendTick();
/* Enter the system to STOP2 mode */
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
/* Check that the system was resumed from stop 2 */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_STOPF) == 0U)
{
Error_Handler();
}
/* Clear stop flag */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_STOPF);
/* Check that stop flag is cleared */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_STOPF) != 0U)
{
Error_Handler();
}
/* Call the system clock config */
SystemClock_Config();
/* Resume the SysTick */
HAL_ResumeTick();
/* Wake Up based on RXNE flag successful */
HAL_UARTEx_DisableStopMode(&hlpuart1);
HAL_UART_Receive_IT(&hlpuart1, u8pData, 1);
}
/* USER CODE END 4 */
19. Now, all the code implementations are done! You should be able to compile properly, program and debug your code clicking on the debug button: 20. The LPUART1 isn’t connected to the ST-LINK VCOM in the NUCLEO-U575ZI-Q. To make this communication line available, you can connect the PG7/PG8 to an USB bridge or change the solder bridge configuration, as the table below shows (for more details, refer the Nucleo board User Manual): 21. To open a Virtual COM into the STM32CubeIDE Interface, click on the button shown in the image below (this button is in the right side of the Console view tab), then clink on Command Shell Console: 22. In the pop-up menu, select the Serial Port at Connection Type drop-down list, and click on New… : 23. Give any connection name, select your respective Serial Port, change the Baud Rate, then click on Finish: 24. Click on OK button in the new window, and check that a COM Console was opened (if the tab didn’t show up or was closed, you can open it from the highlighted button). Once the VCOM is connected, press RESUME and you should see the messages in the terminal Code Explanation:Running the code, the Blue LED should start to blink and the “LED ON” and “LED OFF” message should be sent through the LPUART. If you type the letter “p” the MCU should be enter in Stop 2 Low-power mode and the blink LED will stop. To wake up the MCU you can send any character via terminal to the LPUART, as result the code will resume back to be executed.Here are some important highlights from the code that are interesting to be pointed out: - When using HSI: The macros below are necessary to use the HSI as clock source when the MCU awakes.
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
__HAL_RCC_KERWAKEUPSTOP_CLK_CONFIG(RCC_STOP_KERWAKEUPCLOCK_HSI);
- When using HSI: The macro below is necessary to maintain the HSI clocking while the MCU is in Stop 2.
__HAL_RCC_HSISTOP_ENABLE();
- The following macro and function are necessary to set the registers to maintain the LPUART running in autonomous mode while the MCU is in Stop 2.
__HAL_RCC_LPUART1_CLKAM_ENABLE();
HAL_UARTEx_EnableStopMode(&hlpuart1);
Congratulations making this far! Now you’re able to implement the LPUART to wake up the STM32U5 from the STOP2 Low-Power mode. A feature that can be useful in several low-power applications over the STM32U5 series. With some few changes, the example shown can be adapted for any other STM32U5 part.Hope you enjoyed!
REFERENCE LINKS:Here are some links related to this article which can be useful for your application:STM32U5 Nucleo-144 board - User manualSTM32U575ZI - Main pageSTM32U575xx - DatasheetSTM32U5 Series - Reference manualHow to redirect the printf function to a UART for debug messages - ST Community Article