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

Bus Fault after calling __get_FPSCR in FreeRTOS configPRE_SLEEP_PROCESSING(x)

I'm trying to set up a project with SDK 16.0.0 using FreeRTOS with the softdevice.  The device will be battery powered and therefore power management capabilities are required.

My freeRTOSConfig.h is the same as in the ble_app_hrs_freertos_pca10040_s132 with the following additions:

#if ( __FPU_PRESENT)
#define PWR_MGMT_FPU_SLEEP_PREPARE() pwr_mgmt_fpu_sleep_prepare()
extern void pwr_mgmt_fpu_sleep_prepare(void);
#else
#define PWR_MGMT_FPU_SLEEP_PREPARE()
#endif // NRF_PWR_MGMT_CONFIG_FPU_SUPPORT_ENABLED

#define configPRE_SLEEP_PROCESSING(x) PWR_MGMT_FPU_SLEEP_PREPARE()

#define configSUPPORT_STATIC_ALLOCATION

Based on this thread I tried to add pwr_mgmt_fpu_sleep_prepare in main.c, however my code gets a busfault any time I use the __get_FPSCR() or __set_FPSCR() macro.

My application works as expected except not sleeping when I comment out the FPSCR macros.

When I uncomment the macro's the busfault breakpoint triggers and the PC is stopped at address 0xA60.

Do I need to implement this sleep prepare step?

Why do these FPSCR macro's cause a bus fault?

Given:

1) I'm not even using the FPU.

2) This example only performs some I2C operations once per second

3) I have RTC2 enabled and operating at 32KHz with only overflow interrupt enabled ( for tracking time independent from freeRTOS )

4) I have an idle task hook that does NRF_LOG_FLUSH with NRF_LOG_ENABLED

Then will it be reasonable to expect the sd_app_evt_wait() call to sleep for some amount of time?  It seems at the moment it will never sleep despite every task being blocked/suspended.

Parents Reply Children
  • Yes based on the many issues reported here on devzone, I implemented the workaround for FPU errata. 

    Yes I am experiencing immediate wakes... the call to sd_app_evt_wait returns with no time passed.

    My project contains proprietary code that I cannot release publicly.  

    Is there an example project that demonstrates low power operation with freertos on nrf52832 while using ble and nrf log library with an RTT backend?   

  • I did a test with the HRS FreeRTOS example. The only modifications I made was to enable RTT logging and disable UART logging:

    //==========================================================
    // <e> NRF_LOG_BACKEND_RTT_ENABLED - nrf_log_backend_rtt - Log RTT backend
    //==========================================================
    #ifndef NRF_LOG_BACKEND_RTT_ENABLED
    #define NRF_LOG_BACKEND_RTT_ENABLED 1
    #endif
    
    // <e> NRF_LOG_BACKEND_UART_ENABLED - nrf_log_backend_uart - Log UART backend
    //==========================================================
    #ifndef NRF_LOG_BACKEND_UART_ENABLED
    #define NRF_LOG_BACKEND_UART_ENABLED 0
    #endif

    And add a call to sd_app_evt_wait() in the application idle hook:

    void vApplicationIdleHook( void )
    {
    #if NRF_LOG_ENABLED
         vTaskResume(m_logger_thread);
    #endif
        if (nrf_sdh_is_enabled())
        {
            uint32_t err_code = sd_app_evt_wait();
            APP_ERROR_CHECK(err_code);
        }
    }

    This is the current that I measure (average over 24 seconds, and average IDLE current between BLE events):

    Are you sure that you are not in debug mode when you measure the current? This could happen if you read the logs over RTT/SWD.

  • After modifying the freertos example to eliminate the vApplicationIdleHook and instead unblock the logger task from a hook in the logger library, I have been able to see the freertos port sleep as expected.

    The immediate wakes were caused by the idle hook resuming the logger task.  This causes freertos to always have a task to run and never sleep.  Nordic should remove this from the example, it doesn't work and causes customers to waste engineering time.  

    I will implement FPU interrupt to handle FPU errors next and I may still have some questions.

  • what exact change did you make to eliminate the vApplicationIdleHook and where exactly did you unblock the logger task?

    Did you understand why it was keeping your system awake if unblocking in idleHook? It is the safest way to run the logs when rest of the rtos tasks are not running. 

    The change that you said does not make sense unless you have changed the priority of the logger task so high that it is not allowing any other task to run. 

    Nordic should remove this from the example, it doesn't work and causes customers to waste engineering time.  

    The example is done correctly in terms of how logging is handled. It very much looks like this was caused due to choosing of wrong priorities of the tasks. 

  • I have not changed the priorities of any tasks.  I proved this problem on the example project with no modifications.  

    The logging task in the example uses simple suspend and resume.  The logger task is the lowest priority however since it is resumed every time the system is idle, the scheduler always has an unblocked task to run and therefore it can never sleep.  

    This is very easy to verify.  In port_cmdsis_systick.c, the vPortSuppressTicksAndSleep task calculates the time it was sleeping.  I added the calculated sleep time to a static variable m_sleep_time and could verify that no time was actually spent asleep in sd_app_evt_wait().

    Here is the code I added to track sleep time:

    //exisintg code

    diff = (exitTime - enterTime) & portNRF_RTC_MAXTICKS;

    //my code

    static uint32_t m_sleep_time=0;

    m_sleep_time+=diff;

    Then I monitor m_sleep_time from the debugger.

    To improve this situation, the logger task needs to block until logs need to be flushed.

    For this I modified nrf_log_frontend.c buf_prealloc static function.  I added a weakly defined function vLogPendingHook() 

    Then I override the vLogPendingHook() in my application to use direct to task notification to signal to the logger task that logs need to be flushed:

    void vLogPendingHook( void )
    {
    #if NRF_LOG_ENABLED
    BaseType_t result = pdFAIL;

    if ( __get_IPSR() != 0 )
    {
    BaseType_t higherPriorityTaskWoken = pdFALSE;
    result = xTaskNotifyFromISR( m_logger_thread, LOG_PENDING_EVT, eSetValueWithoutOverwrite, &higherPriorityTaskWoken );

    if ( pdFAIL != result )
    {
    portYIELD_FROM_ISR( higherPriorityTaskWoken );
    }
    }
    else
    {
    UNUSED_RETURN_VALUE(xTaskNotify( m_logger_thread, LOG_PENDING_EVT, eSetValueWithoutOverwrite ));
    }

    #endif //NRF_LOG_ENABLED
    }

Related