Search code examples
carmembeddedinteger-overflow

Using ARM Cortex SysTick for calculating elapsed time; what happens when SysTick counter rolls over?


I'm currently auditing an online edX course about embedded systems, and learning about using the SysTick timer to calculate elapsed time.

Picture of logic I'm referring to

Code of logic I'm referring to

However, there is one point that is confusing me. I understand the idea of subtracting "now" from "last" to get the elapsed time. However, what do you do when the "now" rolls over when the SysTick timer hits 0 and gets reloaded, but the "last" is the value from BEFORE the SysTick timer rolled over (so "now" is > than "last", when normally it should be smaller)? The value is being stored in an unsigned long, so does it break the program? Or does this just never happen, and if so why? I would appreciate any help on clearing this up!

I looked at the only other link I could find that was similar to my question here: How to deal with a wrapping counter in embedded C but I didn't find a clear answer to my question from that.


Solution

  • Take a 3 bit counter, it all scales up the same to 24 or 32 (I think the systick timers are 24.

    So counting up or down doesnt matter, you just need to adjust the operands correctly. So say counting down 7,6,5,4 7 - 4 is 3 counts. but what about 1,0,7,6 in binary 1 - 6 = 001 - 110

         1
       001
    +  001
    =======
    

    and solve it

       011
       001
    +  001
    =======
       011     
    

    and clipping to 3 bits that is the right answer.

    Should be simple to write a program for a 4 or 5 bit counter try random sized counts. Or use fixed sized counts allowing for roll over using prime numbers

    #include <stdio.h>
    #define BITMASK 0xF
    int main ( void )
    {
        unsigned int now;
        unsigned int beg;
        unsigned int end;
        unsigned int ra;
        unsigned int rb;
        now=0;
        for(ra=0;ra<100000;ra++)
        {
            beg=now;
            for(rb=0;rb<13;rb++) now--;
            end=now;
            if(((beg-now)&BITMASK)!=13)
            {
                printf("Error 0x%X 0x%X\n",beg,end);
            }
        }
        printf("Done.\n");
        return(1);
    }
    

    This ONLY works if it is a counter that rolls over from all zeros to all ones or all ones to all zeros depending on the direction. I would hope it obvious if you set a hypothetical 3 bit timer to start at 5 and it rolled over from zero back to that 5 set point then three steps could be 1,0,5,4 and 1-4 is not 3

        111
        001
    +   011
    =========
        101
    

    Another way to think of this is yet another feature of twos complement, near the wraparound point

    101  -3
    110  -2
    111  -1
    000  +0
    001  +1
    010  +2
    

    It is just like the number line we used in grade school. From the bit pattern 110 to 010 is 4 steps +2 - -2 = 4 or 4 units on the number line. Basically using the beauty of twos complement and we know that addition and subtraction in binary thanks to twos complement is not unsigned or signed specific the same bit patterns result in the same bit patterns. It is just how we interpret them. So we are cheating a little, taking signed math and interpreting the result as unsigned.