Skip to content

Commit 5ddb441

Browse files
async_context_freertos: Add support for configSUPPORT_STATIC_ALLOCATION (#2436)
* async_context_freertos: Add support for configSUPPORT_STATIC_ALLOCATION The implementation of async_context_freertos currently assumes that FreeRTOS has been configured with `configSUPPORT_DYNAMIC_ALLOCATION`, which causes it to allocate semaphores, timers and tasks from the heap. However, some projects may prefer `configSUPPORT_STATIC_ALLOCATION`, which requires memory to be allocated ahead of time. This change allows async_context_freertos to support either static or dynamic allocation. The way this works is when `configSUPPORT_STATIC_ALLOCATION` is enabled, `async_context_freertos` struct will reserve extra space for the static objects (e.g. `StaticSemaphore_t`) and it will prefer to use the static creation functions (e.g. `xSemaphoreCreateBinaryStatic()`). For the task creation, the user will be responsible for allocating the stack memory and setting the task_stack field in `async_context_freertos_config_t`. For convenience, The `cyw43_arch_init_default_async_context()` function will reserve `CYW43_TASK_STACK_SIZE` words of stack space in static memory. * Assert that task_stack is set * Add CYW43_NO_DEFAULT_TASK_STACK In theory you can use your own async context therefore bypassing cyw43_arch_init_default_async_context, which would leave cyw43_async_context_freertos_task_stack unused. Add a #define for this rare situation. * Update documentaton for async_context_freertos_config.task_stack --------- Co-authored-by: Peter Harper <[email protected]>
1 parent 893a06b commit 5ddb441

File tree

4 files changed

+56
-1
lines changed

4 files changed

+56
-1
lines changed

src/rp2_common/pico_async_context/async_context_freertos.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,43 @@ bool async_context_freertos_init(async_context_freertos_t *self, async_context_f
109109
self->core.type = &template;
110110
self->core.flags = ASYNC_CONTEXT_FLAG_CALLBACK_FROM_NON_IRQ;
111111
self->core.core_num = get_core_num();
112+
#if configSUPPORT_STATIC_ALLOCATION
113+
assert(config->task_stack);
114+
self->lock_mutex = xSemaphoreCreateRecursiveMutexStatic(&self->lock_mutex_buf);
115+
self->work_needed_sem = xSemaphoreCreateBinaryStatic(&self->work_needed_sem_buf);
116+
self->timer_handle = xTimerCreateStatic( "async_context_timer", // Just a text name, not used by the kernel.
117+
portMAX_DELAY,
118+
pdFALSE, // The timers will auto-reload themselves when they expire.
119+
self,
120+
timer_handler,
121+
&self->timer_buf);
122+
self->task_handle = xTaskCreateStatic( async_context_task,
123+
"async_context_task",
124+
config->task_stack_size,
125+
self,
126+
config->task_priority,
127+
config->task_stack,
128+
&self->task_buf);
129+
#else
112130
self->lock_mutex = xSemaphoreCreateRecursiveMutex();
113131
self->work_needed_sem = xSemaphoreCreateBinary();
114132
self->timer_handle = xTimerCreate( "async_context_timer", // Just a text name, not used by the kernel.
115133
portMAX_DELAY,
116134
pdFALSE, // The timers will auto-reload themselves when they expire.
117135
self,
118136
timer_handler);
137+
#endif
119138

120139
if (!self->lock_mutex ||
121140
!self->work_needed_sem ||
122141
!self->timer_handle ||
142+
#if configSUPPORT_STATIC_ALLOCATION
143+
!self->task_handle
144+
#else
123145
pdPASS != xTaskCreate(async_context_task, "async_context_task", config->task_stack_size, self,
124-
config->task_priority, &self->task_handle)) {
146+
config->task_priority, &self->task_handle)
147+
#endif
148+
) {
125149
async_context_deinit(&self->core);
126150
return false;
127151
}
@@ -179,6 +203,9 @@ void async_context_freertos_lock_check(__unused async_context_t *self_base) {
179203
typedef struct sync_func_call{
180204
async_when_pending_worker_t worker;
181205
SemaphoreHandle_t sem;
206+
#if configSUPPORT_STATIC_ALLOCATION
207+
StaticSemaphore_t sem_buf;
208+
#endif
182209
uint32_t (*func)(void *param);
183210
void *param;
184211
uint32_t rc;
@@ -197,7 +224,11 @@ uint32_t async_context_freertos_execute_sync(async_context_t *self_base, uint32_
197224
call.worker.do_work = handle_sync_func_call;
198225
call.func = func;
199226
call.param = param;
227+
#if configSUPPORT_STATIC_ALLOCATION
228+
call.sem = xSemaphoreCreateBinaryStatic(&call.sem_buf);
229+
#else
200230
call.sem = xSemaphoreCreateBinary();
231+
#endif
201232
async_context_add_when_pending_worker(self_base, &call.worker);
202233
async_context_set_work_pending(self_base, &call.worker);
203234
xSemaphoreTake(call.sem, portMAX_DELAY);

src/rp2_common/pico_async_context/include/pico/async_context_freertos.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ typedef struct async_context_freertos_config {
5656
* \brief Stack size for the async_context task
5757
*/
5858
configSTACK_DEPTH_TYPE task_stack_size;
59+
/**
60+
* \brief Pointer to stack memory for the async_context task.
61+
*/
62+
#if configSUPPORT_STATIC_ALLOCATION
63+
StackType_t *task_stack;
64+
#endif
5965
/**
6066
* \brief the core ID (see \ref portGET_CORE_ID()) to pin the task to.
6167
* This is only relevant in SMP mode.
@@ -71,6 +77,12 @@ struct async_context_freertos {
7177
SemaphoreHandle_t work_needed_sem;
7278
TimerHandle_t timer_handle;
7379
TaskHandle_t task_handle;
80+
#if configSUPPORT_STATIC_ALLOCATION
81+
StaticSemaphore_t lock_mutex_buf;
82+
StaticSemaphore_t work_needed_sem_buf;
83+
StaticTimer_t timer_buf;
84+
StaticTask_t task_buf;
85+
#endif
7486
uint8_t nesting;
7587
volatile bool task_should_exit;
7688
};

src/rp2_common/pico_cyw43_arch/cyw43_arch_freertos.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,20 @@
2525

2626
static async_context_freertos_t cyw43_async_context_freertos;
2727

28+
#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK
29+
static StackType_t cyw43_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE];
30+
#endif
31+
2832
async_context_t *cyw43_arch_init_default_async_context(void) {
2933
async_context_freertos_config_t config = async_context_freertos_default_config();
3034
#ifdef CYW43_TASK_PRIORITY
3135
config.task_priority = CYW43_TASK_PRIORITY;
3236
#endif
3337
#ifdef CYW43_TASK_STACK_SIZE
3438
config.task_stack_size = CYW43_TASK_STACK_SIZE;
39+
#endif
40+
#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK
41+
config.task_stack = cyw43_async_context_freertos_task_stack;
3542
#endif
3643
if (async_context_freertos_init(&cyw43_async_context_freertos, &config))
3744
return &cyw43_async_context_freertos.core;

src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch/arch_freertos.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
#ifndef _PICO_CYW43_ARCH_ARCH_FREERTOS_H
88
#define _PICO_CYW43_ARCH_ARCH_FREERTOS_H
99

10+
// PICO_CONFIG: CYW43_NO_DEFAULT_TASK_STACK, Disables the default static allocation of the CYW43 FreeRTOS task stack, type=bool, default=0, group=pico_cyw43_arch
11+
#ifndef CYW43_NO_DEFAULT_TASK_STACK
12+
#define CYW43_NO_DEFAULT_TASK_STACK 0
13+
#endif
14+
1015
// PICO_CONFIG: CYW43_TASK_STACK_SIZE, Stack size for the CYW43 FreeRTOS task in 4-byte words, type=int, default=1024, group=pico_cyw43_arch
1116
#ifndef CYW43_TASK_STACK_SIZE
1217
#define CYW43_TASK_STACK_SIZE 1024

0 commit comments

Comments
 (0)