AnsweredAssumed Answered

STM32L1 + Instruction Prefetch + Voltage Scaling + Debugger = Unexpected Memory  Values

Question asked by Andrew Sund on Aug 11, 2017
Latest reply on Aug 25, 2017 by Andrew Sund

Hi, we are using an STM32L151VET device, using CubeMX generated startup code (any modifications seem benign to me for reasons that follow) and have been encountering a strange error when running with a debugger attached.

  • Processor is running on MSI @ 2MHz, internal flash (flash latency not an issue at this point)
  • Instruction prefetch is enabled prior to this in HAL_Init(), using __HAL_FLASH_PREFETCH_BUFFER_ENABLE().
  • Multiple boards used.
  • Segger J-Link and ST-Link/v2 debuggers used.

The error occurs in SystemClock_Config(), code is as generated (with two modifications):

void SystemClock_Config(void)
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;


while ( READ_BIT( PWR->CSR, PWR_CSR_VOSF ) ); /* Coworkers added these after encountering this problem. */
while ( READ_BIT( PWR->CSR, PWR_CSR_VOSF ) ); /* Coworkers added these after encountering this problem. */

RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

The polling loops on PWR_CSR_VOSF are recommended by the reference manual, but it also says the clock is stopped while it's switching voltages, so they seem pointless. CubeMX omits them. My coworkers added them when they first encountered this issue and it made it go away. The issue has been seen since, so I suspect it was a red herring "fix". I'd much prefer to get to the bottom of this than to pepper the code with delays and statements which have an unknown effect... Anyways, on to the problem:


When I reset with a debugger attached, Error_Handler is called. Setting a breakpoint at HAL_RCC_OscConfig line and viewing memory shows the first 4 members of RCC_OscInitStruct (code populates them in memory order) are not the expected 7,1,5,1. Inserting __NOP() calls after the last polling loop changes these values:

  • 0 __NOPs: 0,7,5,7 (2nd and 4th values are the same because they come from same register, loaded once)
  • __NOP: 0,1,5,1
  • 2 __NOPs: 8,1,5,1
  • 3+ __NOPs: 7,1,5,1 (desired)

Inserting a multiple of 4 __NOPs (0,4,8) before the voltage scaling call preserves this behaviour. Inserting 1-3, 5-7, resolves it.


When I step through the code with the debugger, the memory looks as expected. Unplugging the debugger and power cycling cause the exact same code to execute fine and the system starts up.



My Conclusion

From these results, I suspect something strange is going on with the debugger, instruction prefetch (64-bit prefetch, 16-bit nops, points to the multiple of 4 nops), voltage scaling setting (clock is supposed to be stopped during this time, maybe debugger or prefetch are doing something weird during this time), etc.


Disabling prefetch seems to resolve this, but I don't know why and would like an explanation before I make any changes.


Has anyone seen anything like this or have any other troubleshooting tips?