cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4R9 reset reason flags always 0 (RCC->CSR)

DerekR
Senior

Details:

MCU: STM32L4R9ZGJ6

IDE: STM32CubeIDE v1.6.1

SDK: STM32Cube_FW_L4_V1.14.0

Board: Custom PCB

Hello,

I am seeing really strange behavior where bits 31-24 in the RCC->CSR register are usually always 0. I have verified this behavior on two boards. The only bit I ever see set is PINRSTF but only after programming the board with the debugger attached. Subsequent resets with NVIC_SystemReset(), toggling NRST, watchdog reset, etc do not set the reset bits accordingly.

I have tried reading the registers after basic system init and immediately upon entering main() with the same result. Below are two tests that read RCC->CSR just after calling NVIC_SystemReset().

Test 1 (Read CSR after basic system init):

0693W00000Uon68QAB.png 

Test 2 (Read CSR as soon as main() is entered):

0693W00000Uon7LQAR.png 

I can't figure out why this would be happening. I skimmed through the MCU erratas and didn't see anything, but I could have overlooked something.

Thanks,

Derek

1 ACCEPTED SOLUTION

Accepted Solutions
DerekR
Senior

I am updating my fix as the previous one did not work 100% even though the code ran fine.

Fix: Just delete HAL_RCC_DeInit() from the end of the bootloader and allow the application to reconfigure it as necessary.

I originally had moved HAL_RCC_DeInit() from the end of the bootloader to the start of main() in the application as shown above, but this lead to an assert in HAL_InitTick() once I enabled the USE_FULL_ASSERT macro. The code now runs as expected with the macro enabled.

Derek

View solution in original post

7 REPLIES 7
DerekR
Senior

I think it just dawned on me. This device uses a bootloader so I imagine the HAL API in said bootloader might be clearing the reset bits. This would explain why they are only set when I program the device because the PC (Program Counter) jumps to the start of the application and the bootloader is not run. That has to be it. I'll update this post once I confirm.

Edit:

My suspicion was correct. The bootloader calls HAL_RCC_DeInit() before jumping to the application.

HAL_StatusTypeDef HAL_RCC_DeInit(void)
{
   ...
   /* Clear all reset flags */
  SET_BIT(RCC->CSR, RCC_CSR_RMVF);
}

Will update this post with a mitigation when I fin one.

 Derek

Piranha
Chief II

Honestly clearing of the reset flags in RCC "deinitialization" doesn't make a sense. Those flags were not set as a result of initialization and therefore should not be touched at deinitialization. But the HAL developer's thought is simple - everything in RCC peripheral must be cleared. No capabilities of deeper analysis... This just shows again and again that the designers of HAL are incapable of designing a useful API.

DerekR
Senior

The fix I implemented was to read RCC->CSR at the start of main() and move HAL_RCC_DeInit() from the end of the bootloader to just after reading RCC->CSR.

int main(void)
{
   // Get reset reason
   reset_flag = RCC->CSR;
  
   // Reset clock config set by bootloader and clear reset reason bits
   HAL_RCC_DeInit();
   
   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
   HAL_Init();
 
   // Configure the system clock
   //Sys Clock - 120MHz
   SystemClock_Config();
   
   MX_DMA_Init();
   ....
}

@Piranha​ I agree in that some of the HAL API implementation doesn't make sense, but at least it's a start and better than writing registers directly. I'll take whatever help I can get :)

Derek

DerekR
Senior

I am updating my fix as the previous one did not work 100% even though the code ran fine.

Fix: Just delete HAL_RCC_DeInit() from the end of the bootloader and allow the application to reconfigure it as necessary.

I originally had moved HAL_RCC_DeInit() from the end of the bootloader to the start of main() in the application as shown above, but this lead to an assert in HAL_InitTick() once I enabled the USE_FULL_ASSERT macro. The code now runs as expected with the macro enabled.

Derek

Piranha
Chief II

> better than writing registers directly

By what metric? You will say "it's easier", but did you tried? Initialization with register code takes 10-20 lines, straightforward and reliable. HAL code, on the contrary, takes several KB of compiled broken bloatware, which doesn't even work in some scenarios.

Also that bootloader design is unreliable. A proper and much simpler design can be seen here:

https://community.st.com/s/question/0D50X0000AFpTmUSQV/using-nvicsystemreset-in-bootloaderapplication-jumps

DerekR
Senior

I agree that writing to registers takes less lines of code, but it's not nearly as user friendly as an API and takes much longer unless you know the processor inside and out. As someone who works with different MCU's on a week to week basis, I don't have the time to read a 2000 page reference manual for each MCU and learn all the registers. It's much easier to start with an example from the SDK and build on top of that. HAL API in theory should also be well tested and fairly reliable and easy to port between projects. I only modify registers directly if there is an absolute need to.

If you don't clear RCC->CSR after reading it, then it may not get cleared when the MCU is reset, leading to an inaccurate representation of the reason for the last reset.

For example, on an STM32L496, if I connect power, resulting in the reset reasons BORRST, PINRST; and then I trigger a software reset without clearing the reset reason; I get the reasons BORRST, SFTRST, PINRST instead of SFTRST, PINRST.

To ensure RCC->CSR only contains the reset reasons for the last reset, one can clear it after reading it (without uninitializing the RCC more generally) via:

__HAL_RCC_CLEAR_RESET_FLAGS();