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

SOFTDEVICE_PRESENT versus sd_softdevice_is_enabled()

Hello -

We are developing some low power code on the nRF52840-DK, using SDK 15.3.0 on FreeRTOS. I noticed that in the port_cmsys_systick.c file, in the vPortSuppressTicksAndSleep() function, that the code just checks if SOFTDEVICE_PRESENT is defined before calling a SoftDevice function:

#ifdef SOFTDEVICE_PRESENT

        uint32_t err_code = sd_app_evt_wait();
        APP_ERROR_CHECK(err_code);
#else

In our case, we currently enable the SoftDevice when requiring BLE, but otherwise we do not request that the SoftDevice is enabled. In other words, we only call nrf_sdh_enable_request() when using BLE. We do however have SOFTDEVICE_PRESENT defined in our Makefile.

I am wondering if the port_cmsys_systick.c code is correct when the application does not have a SoftDevice enabled. At first glance it seems that defining SOFTDEVICE_PRESET implicitly assumes that the SoftDevice has been enabled, which may not be the case.

Regards,

Brian

Parents
  • H

    this seems to be addressed in SDK v16.0.0, where sd_app_evt_wait() is wrapped in a   if (nrf_sdh_is_enabled()) statement, see below

    #ifdef SOFTDEVICE_PRESENT
                if (nrf_sdh_is_enabled())
                {
                    uint32_t err_code = sd_app_evt_wait();
                    APP_ERROR_CHECK(err_code);
                }
                else
    #endif

    Here is the complete vPortSuppressTicksAndSleep function from port_cmsis_systick.c in SDK v16.0.0

    void vPortSuppressTicksAndSleep( 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;
    
        /* 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);
    
        if ( eTaskConfirmSleepModeStatus() != eAbortSleep )
        {
            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);
                }
            }
        }
    #ifdef SOFTDEVICE_PRESENT
        uint32_t err_code = sd_nvic_critical_region_exit(0);
        APP_ERROR_CHECK(err_code);
    #else
        __enable_irq();
    #endif
    }

    Best regards

    Bjørn

Reply
  • H

    this seems to be addressed in SDK v16.0.0, where sd_app_evt_wait() is wrapped in a   if (nrf_sdh_is_enabled()) statement, see below

    #ifdef SOFTDEVICE_PRESENT
                if (nrf_sdh_is_enabled())
                {
                    uint32_t err_code = sd_app_evt_wait();
                    APP_ERROR_CHECK(err_code);
                }
                else
    #endif

    Here is the complete vPortSuppressTicksAndSleep function from port_cmsis_systick.c in SDK v16.0.0

    void vPortSuppressTicksAndSleep( 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;
    
        /* 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);
    
        if ( eTaskConfirmSleepModeStatus() != eAbortSleep )
        {
            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);
                }
            }
        }
    #ifdef SOFTDEVICE_PRESENT
        uint32_t err_code = sd_nvic_critical_region_exit(0);
        APP_ERROR_CHECK(err_code);
    #else
        __enable_irq();
    #endif
    }

    Best regards

    Bjørn

Children
No Data
Related