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.

  • I assumed that I could add configSUPPORT_STATIC_ALLOCATION == 1 support but imminently ran into some weirdness (bug?) in the SDK code:

    // app_timer.h
    typedef struct {
        nrf_sortlist_item_t         list_item;     /**< Token used by sortlist. */
        uint64_t                    end_val;       /**< RTC counter value when timer expires. */
        uint32_t                    repeat_period; /**< Repeat period (0 if single shot mode). */
        app_timer_timeout_handler_t handler;       /**< User handler. */
        void *                      p_context;     /**< User context. */
        NRF_LOG_INSTANCE_PTR_DECLARE(p_log)        /**< Pointer to instance of the logger object (Conditionally compiled). */
        volatile bool               active;        /**< Flag indicating that timer is active. */
    } app_timer_t;
    
    typedef app_timer_t * app_timer_id_t;

    and

    // app_timer_freertos.c
    typedef struct {
        void                      * argument;
        TimerHandle_t               osHandle;
        app_timer_timeout_handler_t func;
        bool                        active;
        bool                        single_shot;
    } app_timer_info_t;
    
    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);
            ...
    }
    

    So it appears that app_timer_create() cases time_id from a constant app_timer_id_t to a mutable app_timer_info_t; two completely different structures! Am I reading this correctly, and if so, its a bug, right!?!!

  • Hi.

    I'll need to talk to one of our engineers more experienced with FreeRTOS and then get back to you.

    Best regards,
    Joakim

  • Some feedback from Daniel Veilleux;

    "In app_timer.h we see that the original app_timer_t was just a data buffer that you could bend to your will:

    “””

    typedef struct app_timer_t { uint32_t data[CEIL_DIV(APP_TIMER_NODE_SIZE, sizeof(uint32_t))]; } app_timer_t;

    “””

    The definition for app_timer_t you found is from APP_TIMER_V2. For some reason, it doesn’t look like APP_TIMER_V2 support was added to app_timer_freertos.c when SDK16 was released. I agree that it’s a bad idea to use APP_TIMER_V2 with the FreeRTOS example!"

    APP_TIMER_V2 being in my project is my mistake, mostly due to merging a desentent of ble_app_uart with ble_app_hrs_freertos. Without APP_TIMER_V2, I'm using the array of uint32_t's version of app_timer_t.

    This seems to clear up the "weirdness in the SDK" part of my question, just leaving the request for guidance on creating a version of SDK FreeRTOS support for static allocation.

  • Once I removed APP_TIMER_V2 from my project, I started on a port to using RTOS static allocation. My goal was to copy app_timer_freertos.c and nrf_sdh_freertos.c from the SDK into my application, and modify them.

    However it quickly became apparent that I had to modify app_timer.h as well, to change APP_TIMER_NODE_SIZE do to adding a TimerStatic_t to app_timer_info_t. Trying to keep a local, modified, copy of app_timer.h while excluding the SDK version would be a pain.

    The alternate is to modify the SDK, and making sure to merge my changes into every SDK update. Not a scenario I like.

    So... the best solution is for Nordic to release a version of the SDK that supports either static or dynamic RTOS allocation. Note that FreeRTOS supports both APIs being enabled at the same time, i.e., both onfigSUPPORT_STATIC_ALLOCATION  and configSUPPORT_DYNAMIC_ALLOCATION can be == 1. The SDK would either have to favor one other the other, I'd vote for static allocation, or introduce a sdk_config.h settings to select one or the other.

    Once I have a working solution, I'll upload it as a patch here for your reference and suggestions.

  • 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?

Related