WRansohoff / STM32_quickstart

Another 'quickstart' recipe for starting a new STM32-based GCC project. I've tried a few different project layouts for bare-metal C applications targeting Cortex-M microcontrollers, and this repository is an effort to reduce the common pain points that I encounter by minimizing external dependencies and auto-generating tedious compenets like the vector table.
MIT License
5 stars 4 forks source link

Preventing rollover bug on 'systick' value #2

Open jmunt opened 4 years ago

jmunt commented 4 years ago

There's a simple rule for avoiding rollover issues. The rule is to use unsigned vars and compare durations rather than compare beginning and end timestamps like you've done.

void delay_ms( uint32_t ms ) { uint32_t start = systick; while ((systick - start) < ms); //Rollover safe : loop while (current_duration < desired_duration) }

You may even want to do a blog entry about this, it's one of those things that's not immediately obvious to most and good to know ASAP. Blog would ideally do calculated examples of what happens when systick rolls over and thus is less than the recorded start timestamp. Below is a better way to represent you existing code IMO because it shows how very close the two solutions are, and thus better emphasises the key difference of comparing durations instead of comparing timestamps:

void delay_ms( uint32_t ms ) { uint32_t start = systick; while ( systick < (start + ms)); //Not rollover safe! : loop while (current_timestamp < desired_timestamp) }

Obviously you'd not rely on systick interrupt if you wanted precision, ignoring that I think it's also generally more appropriate for delay functions to target "at least" the requested delay, in which case you want to also replace ms with (ms+1). ie. Change the delay error from between (roughly) -1ms to 0ms to between (roughly) 0ms and +1ms. Roughly just because of instruction cycle timing themselves, which is trivial in this case relative to the reliance on 1ms systick interrupts.

WRansohoff commented 3 years ago

Thank you for the tip! It's very nice to hear about a simple math trick to handle this sort of bug, and I'll look into updating these methods when I find the time.

jmunt commented 3 years ago

Something I'd forgotten, the result of subtracting larger uint's from smaller uint's is language dependent so watch out for that, it should be fine for c/c++ since its defined behaviour in the standard I believe, but this math will often fail elsewhere. It's not just a problem for code porting and code re-use but also if you try to use a random programmers calculator to check how this rollover works you'll most likely get results that make the code look incorrect even if you did the right thing by finding an appropriate calculator that lets you specify unsigned integer math with the same bit width.