This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Interrupts not waking FreeRTOS up in Tickless mode

Hi

I'm working with FreeRTOS with Tickless (RTC) and I was wondering what one should do in order to avoid the FreeRTOS Idle Task to be waken up every time an Interrupt Service Routine has completed the execution.

In Cortex-M4 the SLEEPONEXIT flag in SCR should help with this feature but I cannot let it work with Nordic. Any hints?

Thanks in Advance.

  • dfer said:
    I forgot to mention that the tick interrupt will always reset the SLEEPONEXIT flag (a Task switch is Always necessary in tickless mode at this Point).

     This will be a good failsafe mechanism. I think it should work.

  • Hi Susheel do you have any idea why the SLEEPONEXIT functionality doesn't work?

  • I am not sure Davide, it should work, it is an ARM feature and does not seem to be optional.

  • Hi Susheel

    after several attempts it seems that the SPEEPONEXIT functionality is somehow prevented by the softdevice.

    Everything gets stuck after a time and I cannot understand why.

    I would have another suggestion that would prevent the vPortSuppressTicksAndSleep to always be executed twice before managing to go to sleep:

        /* Make sure the SysTick reload value does not overflow the counter. */
        if ( xExpectedIdleTime > portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
        {
            xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP;
        }
        /* Block all the interrupts globally */
    #ifdef SOFTDEVICE_PRESENT
        do{
            uint8_t dummy = 0;
            uint32_t err_code = sd_nvic_critical_region_enter(&dummy);
            APP_ERROR_CHECK(err_code);
        }while (0);
    #else
        __disable_irq();
    #endif
    
        __SEV(); __WFE();// reset the event flag, if an interrupt has occured and has triggered a task it will be cought in eTaskConfirmSleepModeStatus
    
        enterTime = nrf_rtc_counter_get(portNRF_RTC_REG);
    
        if ( eTaskConfirmSleepModeStatus() != eAbortSleep )
        {
            TickType_t xModifiableIdleTime;
            TickType_t wakeupTime = (enterTime + xExpectedIdleTime) & portNRF_RTC_MAXTICKS;
    

    The __SEV(); __WFE(); sequence resets the Event flag. If it was set because an Interrupt has occured, and this Interrupt has triggered a FreeRTOS Task, the subsequent eTaskConfirmSleepModeStatus would detect this and Abort the Sleep sequence.

    The Event flag is Always set because either a Task has been Yielded or an Interrupt has occured while the processor was not sleeping. The first time __WFE(); is executed will almost always go Forward without sleeping, causing another call to vPortSuppressTicksAndSleep form FreeRTOS.

    What do you think about this? I've tested it quickly and it seems working.

  • Or even better here:

        /* Make sure the SysTick reload value does not overflow the counter. */
        if ( xExpectedIdleTime > portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
        {
            xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP;
        }
    
        __SEV(); __WFE();// reset the event flag, if an interrupt has occurred and has triggered a task it will be caught in eTaskConfirmSleepModeStatus
    
        /* Block all the interrupts globally */
    #ifdef SOFTDEVICE_PRESENT
        do{
            uint8_t dummy = 0;
            uint32_t err_code = sd_nvic_critical_region_enter(&dummy);
            APP_ERROR_CHECK(err_code);
        }while (0);
    #else
        __disable_irq();
    #endif
    
        enterTime = nrf_rtc_counter_get(portNRF_RTC_REG);
    
        if ( eTaskConfirmSleepModeStatus() != eAbortSleep )
        {

Related