Delay on systick fails on any optimalization

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Delay on systick fails on any optimalization

ソリューションへジャンプ
1,278件の閲覧回数
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 件の賞賛
返信
1 解決策
1,194件の閲覧回数
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 件の賞賛
返信
1 返信
1,195件の閲覧回数
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 件の賞賛
返信