ARM-software / CMSIS_5

CMSIS Version 5 Development Repository
http://arm-software.github.io/CMSIS_5/index.html
Apache License 2.0
1.31k stars 1.08k forks source link

osEventFlagsSet() after osKernelSuspend() in RTOS2 tick-less operation #1536

Open fabriziopic opened 2 years ago

fabriziopic commented 2 years ago

Hi all,

I'm implementing a low power application based on CMSIS RTOS2 with ATSAML22 MCU. I have an RTOS2 tick-less operation like this:

// OS Idle Thread
__NO_RETURN void osRtxIdleThread (void *argument)
{
    (void)argument; 

    for (;;) 
    {   
        // Returns OS ticks to sleep
        osTickSleep = osKernelSuspend();

        if (osTickSleep > 0) 
        {
            // Is there some time to sleep?

            // Start the wake up timer
            WakeUp_TIMER_Start();
            // Enter the low power state
            LowPower_MCU_Enter();

#ifdef __DEBUG__
            // Go to IDLE mode
            _set_sleep_mode(2);
#endif /* #ifdef __DEBUG__ */
#ifdef __RELEASE__
            // Go to SLEEP mode
            _set_sleep_mode(4);
#endif /* #ifdef __RELEASE__ */

            __DSB():
            __WFI();

            __NOP();
            // Leave the low power state
            LowPower_MCU_Exit();

            // Check if wake up timer interrupt happened
            WakeUp_TIMER_Check();

            // Calculate how long we slept
            osTickSleep = (dwWakeUpTimerValue * OS_TICK_FREQ + (WAKE_UP_TIMER_CLOCK - 1U)) / WAKE_UP_TIMER_CLOCK;
        }

        // Adjust the kernel ticks with the amount of ticks slept
        osKernelResume(osTickSleep);
    }

}   /* END of function osRtxIdleThread */

When an interrupt is fired while in stop mode I can wakeup and continue working in my app. But the problem is when the interrupt is fired between osKernelSuspend() and go to sleep. The interrupt have is like this:

void IRQHandler (void) 
{
    osEventFlagsSet(evt_id, EVT_FLAG_1);
}

Theorically, when the IRQHandler() is fired the thread which is waiting for the event is resumed from blocked state. But if the IRQHandler() is fired between osKernelSuspend() and go to sleep the thread is not resumed and the MCU enters in sleep. I know that the solution should be to use WFE instead of WFI but it seems that ATSAML22 MCU does not support the WFE instruction and I fixed the idle thread like:

// OS Idle Thread
__NO_RETURN void osRtxIdleThread (void *argument)
{
    (void)argument;

    for (;;) 
    {   
        // Get enabled IRQs in NVIC
        uint32_t dwEnableIRQn = NVIC->ISER[0];
        // Disable all IRQs in NVIC
        NVIC->ICER[0] = 0xFFFFFFFF;
        __DSB();
        __ISB();

        // Returns OS ticks to sleep
        osTickSleep = osKernelSuspend();

        if (osTickSleep > 0) 
        {
            // Is there some time to sleep?

            // Start the wake up timer
            WakeUp_TIMER_Start();

            // Enter the low power state
            LowPower_MCU_Enter();

#ifdef __DEBUG__
            // Go to IDLE mode
            _set_sleep_mode(2);
#endif /* #ifdef __DEBUG__ */
#ifdef __RELEASE__
            // Go to SLEEP mode
            _set_sleep_mode(4);
#endif /* #ifdef __RELEASE__ */

            // Some IRQ pending?
            if (NVIC->ISPR[0] == 0)
            {
                // Re-Enable IRQs in NVIC
                __COMPILER_BARRIER();
                NVIC->ISER[0] = dwEnableIRQn;
                __COMPILER_BARRIER();

                _go_to_sleep();
            }

            __NOP();
            // Leave the low power state
            LowPower_MCU_Exit();

            // Check if wake up timer interrupt happened
            WakeUp_TIMER_Check();

            // Calculate how long we slept
            osTickSleep = (dwWakeUpTimerValue * OS_TICK_FREQ + (WAKE_UP_TIMER_CLOCK - 1U)) / WAKE_UP_TIMER_CLOCK;
        }

        // Adjust the kernel ticks with the amount of ticks slept
        osKernelResume(osTickSleep);

        // Re-Enable IRQs in NVIC
        __COMPILER_BARRIER();
        NVIC->ISER[0] = dwEnableIRQn;
        __COMPILER_BARRIER();
    }

}   /* END of function osRtxIdleThread */

Is it a good solution? Or, how can I know if there is any thread right now in ready state to avoid enter in stop mode?

Best regards

Fabrizio

JonatanAntoni commented 2 years ago

Hi Fabrizio,

I am sorry for not being able to be much of a help for specific microcontrollers. Did you try to work on this with the Atmel community?

I can only say that WFI is always prone for race conditions. I think your solutions is the best you can achieve. Still, if the interrupt happens just between the check and the _go_to_sleep() you might lose it.

And another typical source for issues is calculating the sleep time. Using a separate timer for counting sleep time (low power timer) compared to run time (systick) introduces a jitter. If such a jitter hurts depends on your accuracy requirements.

Cheers, Jonatan

fabriziopic commented 2 years ago

Hi Jonatan,

Microchip support confirms that WFE is not supported and suggest a similar solution of the one I used.

Br Fabrizio

Da: Jonatan Antoni @.> Inviato: martedì 26 luglio 2022 10:46 A: ARM-software/CMSIS_5 @.> Cc: Fabrizio Picotto @.>; Author @.> Oggetto: [EXT] Re: [ARM-software/CMSIS_5] osEventFlagsSet() after osKernelSuspend() in RTOS2 tick-less operation (Issue #1536)

Hi Fabrizio,

I am sorry for not being able to be much of a help for specific microcontrollers. Did you try to work on this with the Atmel community?

I can only say that WFI is always prone for race conditions. I think your solutions is the best you can achieve. Still, if the interrupt happens just between the check and the _go_to_sleep() you might lose it.

And another typical source for issues is calculating the sleep time. Using a separate timer for counting sleep time (low power timer) compared to run time (systick) introduces a jitter. If such a jitter hurts depends on your accuracy requirements.

Cheers, Jonatan

— Reply to this email directly, view it on GitHubhttps://github.com/ARM-software/CMSIS_5/issues/1536#issuecomment-1195190032, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AZOOLR6CMUNBXJP2NWBUYX3VV6QUZANCNFSM54UXRBGA. You are receiving this because you authored the thread.Message ID: @.**@.>>


Il contenuto di questo messaggio e-mail e di ogni eventuale allegato è strettamente confidenziale e indirizzato esclusivamente al destinatario indicato. Tutte le informazioni contenute sono soggette ad obbligo di riservatezza ai sensi del Regolamento UE 2016/679 GDPR e del D.Lgs 196/2003 e sm. Il trattamento non autorizzato del contenuto trasmesso e/o allegato dal mittente è vietato. In caso di erronea ricezione il destinatario è pregato di contattare immediatamente il mittente e cancellare al più presto il messaggio. Grazie.

The contents and any attachments of this e-mail are strictly confidential and addressed exclusively to the designated addressee. Any information in this e-mail is subject to an obligation of confidentiality in accordance with EU regulation 2016/679 and D.Lgs. 196/2003. Unauthorized treatment of the content and/or any attachments of this e-mail is forbidden. In the event of incorrect reception the recipient must immediately contact the sender and delete as soon as possible the e-mail. Thank you. Lutech Spa – P.IVA 02824320176 – Milano – REA-MI 1666842