P-NUCLEO-WB55-Nucleo as well as custom board using STM32WB55VG
IDE STM32CubeIDE and STM32CubeMX
When using the STM_WPAN middleware, if the Hardware Time Server (HW_TS) is not initialized quickly enough after the RTC initialization (via
MX_RTC_Init()), the code might get stuck in an infinite loop in the
HW_TS_RTC_Wakeup_Handler() function (file
At startup, the code hangs completely
Suspected modules: STM32_WPAN middleware, in particular the implementation of the time server.
This is due to the fact that the
MX_RTC_Init initializes the RTC and enables the RTC Wakeup interrupt but the hardware server not being already initialized, the first wakeup interrupt will call the
HW_TS_RTC_Wakeup_Handler. However, the pointer phrtc is still set to 0x00. Subsequent calls to the various
__HAL_RTC** functions in the interrupt handler will write in an unknown location, causing these calls to be useless. We will then end up near the end of the function where the code waits for the RTC to signal that the Wakeup Timer is stopped. However, because phrtc is still set to 0x00, the WUTWF will never read as something else than RESET, turning line 565 to an infinite loop:
while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
In order to reproduce the bug:
Generate some default code with CubeMX. You need to activate the radio module. The configuration I used when encountering the bug was using BLE in server mode (server profile, with only Custom P2P server enabled, no debug option selected). Do not forget to enable the HSEM and IPCC with their respective interrupts enabled. The RTC also needs to be enabled in order for the STM32_WPAN module to work. I enabled the generation of the wakeup interrupt in CubeMX. If running the code as-is, it should be working properly. However, if we add a task long enough between the RTC initialization and the MX_APPE_Init() call, the code will hang in the previously identified location. I tested it with a task composed of a 1ms delay (using
HAL_Delay(1) added in block
/* USER CODE BEGIN 2 */) and the code hang as expected (verified with the project compiled in debug mode).
Several solutions are possible:
One could simply ask CubeMX not to enable the wakeup interrupt of the RTC and then reimplement the RTC Wakeup handler in user code. Because the STM32_WPAN code (re-)configures the required parameters of the RTC as needed, this do work. However I think this is not the best solution because there is still a possibility for a user to encounter this bug if said user did not read this post. Also the possibility for some part of the code to rely upon an uninitialized pointer gives m the chills and prevents me from sleeping at night.
One could avoid the possibility to insert code between the RTC initialization and the BLE initialization. This however reduces the flexibility of the generated code and should be avoided. Also, see the end of the previous solution.
I believe the real solution should be to avoid using an uninitialised pointer. This can be done by modifying the macro definition of
#define HAL_RTCEx_WakeUpTimerIRQHandler(...) HW_TS_RTC_Wakeup_Handler( )
would then become
#define HAL_RTCEx_WakeUpTimerIRQHandler(__HANDLE__) HW_TS_RTC_Wakeup_Handler(__HANDLE__)
This also requires the following changes :
- In file
void HW_TS_RTC_Wakeup_Handler(RTC_HandleTypeDef* hrtc);
- and in file
void HW_TS_RTC_Wakeup_Handler(RTC_HandleTypeDef* hrtc)
- All the calls to functions using
phrtc as argument would also require to be changed to use the new
hrtc (not show here for the sake of clarity).
This is to me the best solution even though it might require some more thinking. Because the WB series is a contains only one RTC, there is little to no risk that we get the wrong handle in any call to the HW_TS functions. I do not see the use to having several RTCs in a same device but hey, you never know what the future will be.
- On my custom PCB on which most of the exploration was done, the CM4 core runs at 64MHz and the debug probe used is a J-Link EDU. Te code was mostly running in debug mode so this might somewhat change the timings involved.
- I found this bug because I needed to initialize a shell before the BLE gets initialized but after the USART1 got initialized.
- I would gladly propose a pull-request implementing the changes but I could not figure out the location of the file responsible for the generation of the
app_conf.h file. I tried to bring the change to all the projects contained in this repository but the generated file stayed the same.
I will now be listening to your comments about this whole thing which took me too much time to discover than I am willing to admit!
EDIT: corrected some file names