Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Sleep mode does not work correctly with FreeRTOS SDK 15.3?

Hello, 

I'm trying to implement a sleep mode for my application. Currently it has around 8 tasks.

I need to disable them all + disable some HW, such as GPS module. And wait for ISRs to wake it up from either: GSM module or accelerometer.

There are 2 problems currently: 

1. First as it was mentioned in many tickets before f.e. here, that sleep mode actually does not sleep when all tasks are disabled. 
Device wakes up constantly for unknown event/ISR and goes back to sleep. 
It seems that SD is actually doing some job and constantly wakes up here:

            if (nrf_sdh_is_enabled())
            {
                uint32_t err_code = sd_app_evt_wait();
                APP_ERROR_CHECK(err_code);
            }

In addition, WDG is enabled and even though it configured to freeze in sleep mode, soon it will reset the system.
Additional info:  
- configUSE_TICKLESS_IDLE is enabled

- also SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; instruction is used to indicate DeepSleep

Is there something else that needs to be done to have a correct behaviour in deep sleep mode ?

Here is trace record from SystemView:

After all tasks were suspended ISR triggers constantly after 1-2 ms.

2. Since all tasks use xTaskDelayUntil(), when there is a wakeup ISR that returns system back to normal. Call to
xTaskResume(), makes all those

tasks to execute immediately for all that time that was skipped, which of course breaks the system. Thus the question is what is the correct way to put FreeRTOS system in deep sleep?

  • Hello Susheel, I have found a different solution. Using critical section 

    portENTER_CRITICAL();

    during crypto operations allows both to execute crypto operations correctly and enter both regular sleep mode and deep sleep, cleaning pending Crypto and FPU IQRs before sleep mode, correclty as well. Thus, I will not test compilation of soft-float library.

    Here is a final code sample of custom implemented 

    portSUPPRESS_TICKS_AND_SLEEP():


    /* Define the function that is called by portSUPPRESS_TICKS_AND_SLEEP(). */
    void vApplicationSleep( TickType_t xExpectedIdleTime )
    {
        /*
         * Implementation note:
         *
         * To help debugging the option configUSE_TICKLESS_IDLE_SIMPLE_DEBUG was presented.
         * This option would make sure that even if program execution was stopped inside
         * this function no more than expected number of ticks would be skipped.
         *
         * Normally RTC works all the time even if firmware execution was stopped
         * and that may lead to skipping too much of ticks.
         */
        TickType_t enterTime;
        eSleepModeStatus eSleepStatus;
    
        /* 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
    
        enterTime = nrf_rtc_counter_get(portNRF_RTC_REG);
    
        /* Ensure it is still ok to enter the sleep mode. */
        eSleepStatus = eTaskConfirmSleepModeStatus();
    
        if ( eSleepStatus == eStandardSleep )
        {
            TickType_t xModifiableIdleTime;
            TickType_t wakeupTime = (enterTime + xExpectedIdleTime) & portNRF_RTC_MAXTICKS;
    
            /* Stop tick events */
            nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
    
            /* Configure CTC interrupt */
            nrf_rtc_cc_set(portNRF_RTC_REG, 0, wakeupTime);
            nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
            nrf_rtc_int_enable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
    
            __DSB();
    
            /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
             * set its parameter to 0 to indicate that its implementation contains
             * its own wait for interrupt or wait for event instruction, and so wfi
             * should not be executed again.  However, the original expected idle
             * time variable must remain unmodified, so a copy is taken. */
            xModifiableIdleTime = xExpectedIdleTime;
            configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
            if ( xModifiableIdleTime > 0 )
            {
    #ifdef SOFTDEVICE_PRESENT
                if (nrf_sdh_is_enabled())
                {
                    uint32_t err_code = sd_app_evt_wait();
                    APP_ERROR_CHECK(err_code);
                }
                else
    #endif
                {
                    /* No SD -  we would just block interrupts globally.
                    * BASEPRI cannot be used for that because it would prevent WFE from wake up.
                    */
                    do{
                        __WFE();
                    } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
                }
            }
            configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
    
            nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
            nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
    
            /* Correct the system ticks */
            {
                TickType_t diff;
                TickType_t exitTime;
    
                nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK);
                nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
    
                exitTime = nrf_rtc_counter_get(portNRF_RTC_REG);
                diff =  (exitTime - enterTime) & portNRF_RTC_MAXTICKS;
    
                /* It is important that we clear pending here so that our corrections are latest and in sync with tick_interrupt handler */
                NVIC_ClearPendingIRQ(portNRF_RTC_IRQn);
    
                if ((configUSE_TICKLESS_IDLE_SIMPLE_DEBUG) && (diff > xExpectedIdleTime))
                {
                    diff = xExpectedIdleTime;
                }
    
                if (diff > 0)
                {
                    vTaskStepTick(diff);
                }
            }
        }
        else if(eSleepStatus == eNoTasksWaitingTimeout)
        {
            /* Stop tick events */
            nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
            CM_LOG_DEBUG("Deep sleep");
    
            __set_FPSCR(__get_FPSCR() & ~(0x0000009F));
            (void) __get_FPSCR();
            NVIC_ClearPendingIRQ(FPU_IRQn);
    
            sd_nvic_ClearPendingIRQ(CRYPTOCELL_IRQn);
    
            __DSB();
    
    #ifdef SOFTDEVICE_PRESENT
            if (nrf_sdh_is_enabled())
            {
                CM_LOG_DEBUG("SD Deep sleep");
                uint32_t err_code = sd_app_evt_wait();
                APP_ERROR_CHECK(err_code);
            }
            else
    #endif
            {
                /* No SD -  we would just block interrupts globally.
                * BASEPRI cannot be used for that because it would prevent WFE from wake up.
                */
                do{
                    __WFE();
                } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
            }
    
            nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
    
            NRF_WDT->RR[0] = 0x6E524635;	//this value must be written in all enabled reload registers (ref. manual p112)
        }
        else
        {
            /* No implementation */
        }
    #ifdef SOFTDEVICE_PRESENT
        uint32_t err_code = sd_nvic_critical_region_exit(0);
        APP_ERROR_CHECK(err_code);
    #else
        __enable_irq();
    #endif
    }

    Note! 

    configPRE_SLEEP_PROCESSING() also has instructions that clear pending FPU and Crypto IRQs.


    Should the second part of the questions be discussed here, or should I create a separate thread for it ?

Related