When a microcontroller's manual says "check that XX happens" what should one do if it doesn't?

Viewed 98

Many microcontroller datasheets and reference manuals contain instructions like the following [quoted from an ST reference manual]:

  1. Program the new number of wait states to the LATENCY bits in the FLASH_ACR register
  2. Check that the new number of wait states is taken into account to access the Flash memory by reading the FLASH_ACR register
  3. Modify the CPU clock source by writing the SW bits in the RCC_CFGR register...

If the reference manual specified some circumstances in which the value might not take effect immediately, or might fail to take effect at all unless the write is repeated, then code could make allowance for such possibilities. Absent any such specification, how should a diligent programmer be expected to handle step 2? Possibilities would include:

  1. Set FLASH_ACR, check it, and signal a fatal error if the value isn't as expected.

  2. Set FLASH_ACR once, then check it within a do-while loop, looping forever if the correct value never appears.

  3. Set FLASH_ACR once, then check it within a do-while loop, but signal a fatal error after some number of iterations if the correct value does not appear.

  4. Set and check FLASH_ACR within a do-while loop, looping forever if the value never gets set properly.

  5. Set and check FLASH_ACR within a do-while loop, but signal a fatal error after some number of iterations.

  6. Force a read of the hardware register in case that would introduce a necessary delay, and to make the value visible if a debugger breakpoint is set, but otherwise ignore the result.

  7. Ignore step 2 except during development.

It's common for certain operations to have a delayed effect, and for systems to require that code wait for some operations to complete before initiating others. It's unclear, however, in what circumstances FLASH_ACR might fail to become set properly absent chip damage severe enough to render any attempted program execution meaningless. My guess is that the checks are primarily intended as part of a trouble-shooting process in case things don't work as intended, but are not otherwise a necessary part of production code. How do other people handle such checks?

2 Answers

ST's own start-up code takes no such action. For example, from system_stm32f4xx.c version 1.6.9:

    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

#if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx)      
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F40_41xxx || STM32F42_43xxx */

#if defined (STM32F401xx)
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
#endif /* STM32F401xx */

    /* Select the main PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }

It is important that you don't set the timings to values incompatible with PLL clock speed before you switch, but if programming the register fails, then no amount of software is going to be the solution.

It depends on how detailed error handling you want. If you wish to log or display that flash ACR register failed, then you could wait for a certain amount of time, before reverting to a safe error handler mode.

For most systems it will be sufficient to simply enable the watchdog early on, then wait for the register to be set with a busy-wait while loop.

In the case of wait states and clocks specifically, there might not be much you can/want to do in case of an error, since an error there means that the environment that the program runs on is dead. At best, the MCU will revert to a default internal RC oscillator to allow your error handler to "limp home". For some applications you don't even want that, but just a MCU reset.

Related