Delay on systick fails on any optimalization

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Delay on systick fails on any optimalization

Jump to solution
725 Views
errorek123
Contributor III

Hello,

I've created simple delay for my project using systick as it is not used for anything else but once i start raising optimalizations it stops working.

void delay_us(uint32_t us)
{
         unsigned long actualSysTick;
         unsigned long desiredSysTick;
         unsigned long us_delay=us;

         (void)SYSTICK_CSR;

         desiredSysTick=SYSTICK_CURRENT - CORE_1US;

         do
         {
                  while((actualSysTick = SYSTICK_CURRENT) > desiredSysTick)
                  {
                        if(SYSTICK_CSR & SYSTICK_COUNTFLAG)
                        {
                                 (void)SYSTICK_CSR;
                                 break;
                        }
                }

               desiredSysTick = actualSysTick - CORE_1US;

         }while(--us_delay);
}

I noticed while debugging that if i set O1 optimalization or highter my program is stuck on do-while because when us_delay hits 0  instead of leaving do-while it jumps to us value again and it's just sits there forever. I heard once that it's best to program on desired optimalization from the start to avoid future problems but seems like compiler is doing some extreme level optimalization and i can't even spot what's wrong.

0 Kudos
1 Solution
641 Views
mjbcswitzerland
Specialist V

Brian

It looks like your routine is based on the uTasker code (commented version below):

extern void fnDelayLoop(unsigned long ulDelay_us)
{
    #define CORE_US (CORE_CLOCK/1000000)                                 // the number of core clocks in a us
    register unsigned long ulMatch;
    register unsigned long _ulDelay_us = ulDelay_us;                     // ensure that the compiler puts the variable in a register rather than work with it on the stack
    if (_ulDelay_us == 0) {                                              // minimum delay is 1us
        _ulDelay_us = 1;
    }
    (void)SYSTICK_CSR;                                                   // clear the SysTick reload flag
    ulMatch = ((SYSTICK_CURRENT - CORE_US) & SYSTICK_COUNT_MASK);        // first 1us match value (SysTick counts down)
    do {
        while (SYSTICK_CURRENT > ulMatch) {                              // wait until the us period has expired
            if ((SYSTICK_CSR & SYSTICK_COUNTFLAG) != 0) {                // if we missed a reload (that is, the SysTick was reloaded with its reload value after reaching zero)
                (void)SYSTICK_CSR;                                       // clear the SysTick reload flag
                break;                                                   // assume a single us period expired
            }
        }
        ulMatch -= CORE_US;                                              // set the next 1us match
        ulMatch &= SYSTICK_COUNT_MASK;                                   // respect SysTick 24 bit counter mask
    } while (--_ulDelay_us != 0);                                        // one us period has expired so count down the requested periods until zero
}

I always run with highest optimisation so I suspect that you don't have SYSTICK_CURRENT defined as a volatile register.

Regards

Mark

View solution in original post

0 Kudos
1 Reply
642 Views
mjbcswitzerland
Specialist V

Brian

It looks like your routine is based on the uTasker code (commented version below):

extern void fnDelayLoop(unsigned long ulDelay_us)
{
    #define CORE_US (CORE_CLOCK/1000000)                                 // the number of core clocks in a us
    register unsigned long ulMatch;
    register unsigned long _ulDelay_us = ulDelay_us;                     // ensure that the compiler puts the variable in a register rather than work with it on the stack
    if (_ulDelay_us == 0) {                                              // minimum delay is 1us
        _ulDelay_us = 1;
    }
    (void)SYSTICK_CSR;                                                   // clear the SysTick reload flag
    ulMatch = ((SYSTICK_CURRENT - CORE_US) & SYSTICK_COUNT_MASK);        // first 1us match value (SysTick counts down)
    do {
        while (SYSTICK_CURRENT > ulMatch) {                              // wait until the us period has expired
            if ((SYSTICK_CSR & SYSTICK_COUNTFLAG) != 0) {                // if we missed a reload (that is, the SysTick was reloaded with its reload value after reaching zero)
                (void)SYSTICK_CSR;                                       // clear the SysTick reload flag
                break;                                                   // assume a single us period expired
            }
        }
        ulMatch -= CORE_US;                                              // set the next 1us match
        ulMatch &= SYSTICK_COUNT_MASK;                                   // respect SysTick 24 bit counter mask
    } while (--_ulDelay_us != 0);                                        // one us period has expired so count down the requested periods until zero
}

I always run with highest optimisation so I suspect that you don't have SYSTICK_CURRENT defined as a volatile register.

Regards

Mark

0 Kudos