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

FreeRTOS support in nRF5_SDK v16 uses dynamic allocation, static allocation requested.

Working on a BLE application on a nRF52833 development board with FreeRTOS (external/freertos), and I noticed that the SDK uses dynamic allocation for FreeRTOS, e.g., xTaskCreate() vs xTaskCreateStatic().

Our product is required to use static allocation only for the usual reasons, predictable memory usage, can't run out of heap... While the SDK modules could be translated to configSUPPORT_DYNAMIC_ALLOCATION == 1 && configSUPPORT_DYNAMIC_ALLOCATION == 0, it would really be nice if the SDK provided this support as well.

Also note that the stack size of the softdevice_task() is set in nrf_sdh_freertos.c, and doesn't appear to be sufficient for pairing & bounding. It would be better if the stack size (or the stack), was passed into nrf_sdh_freertos_init().

Bug? nRF5_SDK + FreeRTOS does not support static allocation of RTOS objects, or

Suggestion? it would be really nice if nRF5_SDK + FreeRTOS supported static allocation of RTOS objects, including task stacks.

Parents
  • Bug? nRF5_SDK + FreeRTOS does not support static allocation of RTOS objects

    In the SDK examples, we have not set the flag configSUPPORT_DYNAMIC_ALLOCATION and according to FreeRTOS.h file, not setting the flag will make this flag default to 1, that is dynamic allocation is enabled by default.

    it would be really nice if nRF5_SDK + FreeRTOS supported static allocation of RTOS objects, including task stacks.

    The examples used static allocation, but I do not think that the design of the FreeRTOS port in itself will disallow the application to use dynamic heap. In the example, we have used heap_1.c, to keep the example as simple as possible. But feel free to use other forms of heap as mentioned here. All you need to do is remove heap_1.c file from your project and add the appropriate heap model you want.

    Also note that the stack size of the softdevice_task() is set in nrf_sdh_freertos.c, and doesn't appear to be sufficient for pairing & bounding. It would be better if the stack size (or the stack), was passed into nrf_sdh_freertos_init().

    The softdevice stack size is a one time operation and it is configurable in the same file you mentioned nrf_sdh_freertos.c 
    NRF_BLE_FREERTOS_SDH_TASK_STACK. What is the explicit need for this info to be passed into nrf_sdh_freertos_init() and why does the configuration in NRF_BLE_FREERTOS_SDH_TASK_STACK not suitable in your application?

  • > dynamic allocation is enabled by default

    Correct

    > The examples used static allocation, but I do not think that the design of the FreeRTOS port in itself will disallow the application to use dynamic heap.

    Correct

    >The softdevice stack size is a one time operation … why does the configuration in NRF_BLE_FREERTOS_SDH_TASK_STACK not suitable in your application?

    Because NRF_BLE_FREERTOS_SDH_TASK_STACK is defined in an SDK module, and is not enclosed by a #ifndef NRF_BLE_FREERTOS_SDH_TASK_STACK … #endif - I have to modify the SDK file. Note however, it appears the 256 bytes is sufficient for this task.

    Overall, my question isn't if FreeRTOS supports static allocation, it does, it's that the FreeRTOS support modules in nRF5_SDK v16 do not. For example, they call TaskCreate and not TaskCreateStatic(). As a matter of fact, the SDK FreeRTOS support modules will only with if configSUPPORT_DYNAMIC_ALLOCATION == 1. This forces me to do one of the following 1) support dynamic allocation just for the softdevice, or 2) override the SDK and add support for static allocation.

    My request is for Nordic to add something like my solution to the SDK.

    My solution was to override the SDK files;

    app_timer.h - copy from the SDK to the Application folder, remove components/libraries/timer from the include path, and modify the application copy as follows:

    // app_timer.h ...
    
    #ifdef RTX
    #   define APP_TIMER_NODE_SIZE          40
    #elif defined(FREERTOS) && configSUPPORT_STATIC_ALLOCATION
    #   define APP_TIMER_NODE_SIZE          (32 + sizeof(StaticTimer_t))
    #else
    #   define APP_TIMER_NODE_SIZE          32
    #endif
    

    app_timer_freertos.c - copy from the SDK to the Application folder, remove the SDK version from the project, add the Applicaton copy to the project, and modify the application copy as follows:

    // app_timer_freertos.c...
    
    typedef struct {
        void                      * argument;
        TimerHandle_t               osHandle;
    #if configSUPPORT_STATIC_ALLOCATION == 1
        StaticTimer_t               osCtrlBlock;
    #endif
        app_timer_timeout_handler_t func;
        /**
         * This member is to make sure that timer function is only called if timer is running.
         * FreeRTOS may have timer running even after stop function is called,
         * because it processes commands in Timer task and stopping function only puts command into the queue. */
        bool                        active;
        bool                        single_shot;
    }app_timer_info_t;
    ...
    
    #if configSUPPORT_STATIC_ALLOCATION == 1
    uint32_t app_timer_create(app_timer_id_t const *      p_timer_id,
                              app_timer_mode_t            mode,
                              app_timer_timeout_handler_t timeout_handler)
    {
        app_timer_info_t * pinfo = (app_timer_info_t*)(*p_timer_id);
        uint32_t      err_code = NRF_SUCCESS;
        unsigned long timer_mode;
    
        if ((timeout_handler == NULL) || (p_timer_id == NULL)) {
            return NRF_ERROR_INVALID_PARAM;
            
        } if (pinfo->active) {
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (pinfo->osHandle == NULL) {
            /* New timer is created */
            memset(pinfo, 0, sizeof(app_timer_info_t));
    
            timer_mode = (mode == APP_TIMER_MODE_SINGLE_SHOT) ? pdFALSE : pdTRUE;
            pinfo->single_shot = (mode == APP_TIMER_MODE_SINGLE_SHOT);
            pinfo->func = timeout_handler;
            pinfo->osHandle = xTimerCreateStatic(" ",
                                                1000,
                                                timer_mode,
                                                pinfo,
                                                app_timer_callback,
                                                &pinfo->osCtrlBlock);
    
            if (pinfo->osHandle == NULL)
                err_code = NRF_ERROR_NULL;
                
        } else {
            /* Timer cannot be reinitialized using FreeRTOS API */
            return NRF_ERROR_INVALID_STATE;
        }
    
        return err_code;
    }
    
    #elif configSUPPORT_DYNAMIC_ALLOCATION == 1
    
    uint32_t app_timer_create(app_timer_id_t const *      p_timer_id,
                              app_timer_mode_t            mode,
                              app_timer_timeout_handler_t timeout_handler)
    {
        ... // unchanged
    }
    
    #elif configSUPPORT_STATIC_ALLOCATION == 1 && configSUPPORT_DYNAMIC_ALLOCATION == 1
    #   error "Module does not support both static and dynamic RTOS allocation!"
    #endif
    

    nrf_sdh_freertos.c - copy from the SDK to the Application folder, remove the SDK version from the project, add the Applicaton copy to the project, and modify the application copy as follows:

    // nrf_sdh_freertos.c ...
    
    void nrf_sdh_freertos_init(nrf_sdh_freertos_task_hook_t hook_fn, void * p_context) {
        NRF_LOG_DEBUG("Creating a SoftDevice task.");
    
        m_task_hook = hook_fn;
    
    #if configSUPPORT_STATIC_ALLOCATION == 1
        m_softdevice_task = xTaskCreateStatic(softdevice_task,
                                "BLE",
                                NRF_BLE_FREERTOS_SDH_TASK_STACK,
                                p_context,
                                2,
                                m_softdevice_stack,
                                &m_softdevice_tcb);
        if (m_softdevice_task == NULL) {
            NRF_LOG_ERROR("SoftDevice task not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    
    #elif configSUPPORT_DYNAMIC_ALLOCATION
    
        BaseType_t xReturned = xTaskCreate(softdevice_task,
                                "BLE",
                                NRF_BLE_FREERTOS_SDH_TASK_STACK,
                                p_context,
                                2,
                                &m_softdevice_task);
        if (xReturned != pdPASS) {
            NRF_LOG_ERROR("SoftDevice task not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    #endif
    }
    

    FreeRTOSConfig.h -

    // FreeRTOSConfig.h
    
    #define configSUPPORT_DYNAMIC_ALLOCATION    0
    #define configSUPPORT_STATIC_ALLOCATION     1

    Note that my solution demands either static or dynamic allocation; an SDK solution might want to introduce something in sdk_config.h to support one or the other if both FreeRTOS API's are enabled.

     Make sense?

Reply
  • > dynamic allocation is enabled by default

    Correct

    > The examples used static allocation, but I do not think that the design of the FreeRTOS port in itself will disallow the application to use dynamic heap.

    Correct

    >The softdevice stack size is a one time operation … why does the configuration in NRF_BLE_FREERTOS_SDH_TASK_STACK not suitable in your application?

    Because NRF_BLE_FREERTOS_SDH_TASK_STACK is defined in an SDK module, and is not enclosed by a #ifndef NRF_BLE_FREERTOS_SDH_TASK_STACK … #endif - I have to modify the SDK file. Note however, it appears the 256 bytes is sufficient for this task.

    Overall, my question isn't if FreeRTOS supports static allocation, it does, it's that the FreeRTOS support modules in nRF5_SDK v16 do not. For example, they call TaskCreate and not TaskCreateStatic(). As a matter of fact, the SDK FreeRTOS support modules will only with if configSUPPORT_DYNAMIC_ALLOCATION == 1. This forces me to do one of the following 1) support dynamic allocation just for the softdevice, or 2) override the SDK and add support for static allocation.

    My request is for Nordic to add something like my solution to the SDK.

    My solution was to override the SDK files;

    app_timer.h - copy from the SDK to the Application folder, remove components/libraries/timer from the include path, and modify the application copy as follows:

    // app_timer.h ...
    
    #ifdef RTX
    #   define APP_TIMER_NODE_SIZE          40
    #elif defined(FREERTOS) && configSUPPORT_STATIC_ALLOCATION
    #   define APP_TIMER_NODE_SIZE          (32 + sizeof(StaticTimer_t))
    #else
    #   define APP_TIMER_NODE_SIZE          32
    #endif
    

    app_timer_freertos.c - copy from the SDK to the Application folder, remove the SDK version from the project, add the Applicaton copy to the project, and modify the application copy as follows:

    // app_timer_freertos.c...
    
    typedef struct {
        void                      * argument;
        TimerHandle_t               osHandle;
    #if configSUPPORT_STATIC_ALLOCATION == 1
        StaticTimer_t               osCtrlBlock;
    #endif
        app_timer_timeout_handler_t func;
        /**
         * This member is to make sure that timer function is only called if timer is running.
         * FreeRTOS may have timer running even after stop function is called,
         * because it processes commands in Timer task and stopping function only puts command into the queue. */
        bool                        active;
        bool                        single_shot;
    }app_timer_info_t;
    ...
    
    #if configSUPPORT_STATIC_ALLOCATION == 1
    uint32_t app_timer_create(app_timer_id_t const *      p_timer_id,
                              app_timer_mode_t            mode,
                              app_timer_timeout_handler_t timeout_handler)
    {
        app_timer_info_t * pinfo = (app_timer_info_t*)(*p_timer_id);
        uint32_t      err_code = NRF_SUCCESS;
        unsigned long timer_mode;
    
        if ((timeout_handler == NULL) || (p_timer_id == NULL)) {
            return NRF_ERROR_INVALID_PARAM;
            
        } if (pinfo->active) {
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (pinfo->osHandle == NULL) {
            /* New timer is created */
            memset(pinfo, 0, sizeof(app_timer_info_t));
    
            timer_mode = (mode == APP_TIMER_MODE_SINGLE_SHOT) ? pdFALSE : pdTRUE;
            pinfo->single_shot = (mode == APP_TIMER_MODE_SINGLE_SHOT);
            pinfo->func = timeout_handler;
            pinfo->osHandle = xTimerCreateStatic(" ",
                                                1000,
                                                timer_mode,
                                                pinfo,
                                                app_timer_callback,
                                                &pinfo->osCtrlBlock);
    
            if (pinfo->osHandle == NULL)
                err_code = NRF_ERROR_NULL;
                
        } else {
            /* Timer cannot be reinitialized using FreeRTOS API */
            return NRF_ERROR_INVALID_STATE;
        }
    
        return err_code;
    }
    
    #elif configSUPPORT_DYNAMIC_ALLOCATION == 1
    
    uint32_t app_timer_create(app_timer_id_t const *      p_timer_id,
                              app_timer_mode_t            mode,
                              app_timer_timeout_handler_t timeout_handler)
    {
        ... // unchanged
    }
    
    #elif configSUPPORT_STATIC_ALLOCATION == 1 && configSUPPORT_DYNAMIC_ALLOCATION == 1
    #   error "Module does not support both static and dynamic RTOS allocation!"
    #endif
    

    nrf_sdh_freertos.c - copy from the SDK to the Application folder, remove the SDK version from the project, add the Applicaton copy to the project, and modify the application copy as follows:

    // nrf_sdh_freertos.c ...
    
    void nrf_sdh_freertos_init(nrf_sdh_freertos_task_hook_t hook_fn, void * p_context) {
        NRF_LOG_DEBUG("Creating a SoftDevice task.");
    
        m_task_hook = hook_fn;
    
    #if configSUPPORT_STATIC_ALLOCATION == 1
        m_softdevice_task = xTaskCreateStatic(softdevice_task,
                                "BLE",
                                NRF_BLE_FREERTOS_SDH_TASK_STACK,
                                p_context,
                                2,
                                m_softdevice_stack,
                                &m_softdevice_tcb);
        if (m_softdevice_task == NULL) {
            NRF_LOG_ERROR("SoftDevice task not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    
    #elif configSUPPORT_DYNAMIC_ALLOCATION
    
        BaseType_t xReturned = xTaskCreate(softdevice_task,
                                "BLE",
                                NRF_BLE_FREERTOS_SDH_TASK_STACK,
                                p_context,
                                2,
                                &m_softdevice_task);
        if (xReturned != pdPASS) {
            NRF_LOG_ERROR("SoftDevice task not created.");
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    #endif
    }
    

    FreeRTOSConfig.h -

    // FreeRTOSConfig.h
    
    #define configSUPPORT_DYNAMIC_ALLOCATION    0
    #define configSUPPORT_STATIC_ALLOCATION     1

    Note that my solution demands either static or dynamic allocation; an SDK solution might want to introduce something in sdk_config.h to support one or the other if both FreeRTOS API's are enabled.

     Make sense?

Children
No Data
Related