diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 610f7510fc6..35840a1d414 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -543,7 +543,7 @@ bt_status_t btc_init(void) { const size_t workqueue_len[] = {BTC_TASK_WORKQUEUE0_LEN, BTC_TASK_WORKQUEUE1_LEN}; btc_thread = osi_thread_create(BTC_TASK_NAME, BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE, - BTC_TASK_WORKQUEUE_NUM, workqueue_len); + BTC_TASK_WORKQUEUE_NUM, workqueue_len, false); if (btc_thread == NULL) { return BT_STATUS_NOMEM; } diff --git a/components/bt/common/osi/include/osi/thread.h b/components/bt/common/osi/include/osi/thread.h index 85ba611f3a9..eb72d94e26d 100644 --- a/components/bt/common/osi/include/osi/thread.h +++ b/components/bt/common/osi/include/osi/thread.h @@ -36,10 +36,11 @@ typedef enum { * param stack_size: thread stack size * param priority: thread priority * param core: the CPU core which this thread run, OSI_THREAD_CORE_AFFINITY means unspecific CPU core - * param work_queue_num: speicify queue number, the queue[0] has highest priority, and the priority is decrease by index + * param work_queue_num: specify queue number, the queue[0] has highest priority, and the priority is decrease by index + * param in_psram: place the task in PSRAM * return : if create successfully, return thread handler; otherwise return NULL. */ -osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[]); +osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[], bool in_psram); /* * brief: Destroy a thread or task diff --git a/components/bt/common/osi/thread.c b/components/bt/common/osi/thread.c index 95475670be5..1b5bd8b00e5 100644 --- a/components/bt/common/osi/thread.c +++ b/components/bt/common/osi/thread.c @@ -43,6 +43,10 @@ struct osi_thread { struct work_queue **work_queues; /*!< Point to queue array, and the priority inverse array index */ osi_sem_t work_sem; osi_sem_t stop_sem; +#if (CONFIG_BT_BLUEDROID_TASK_STACK_IN_EXT_MEM) + StackType_t *stack; + StaticTask_t *task; +#endif }; struct osi_thread_start_arg { @@ -179,10 +183,9 @@ static void osi_thread_run(void *arg) } } - thread->thread_handle = NULL; osi_sem_give(&thread->stop_sem); - vTaskDelete(NULL); + vTaskSuspend(NULL); } static int osi_thread_join(osi_thread_t *thread, uint32_t wait_ms) @@ -204,14 +207,20 @@ static void osi_thread_stop(osi_thread_t *thread) //join ret = osi_thread_join(thread, 1000); //wait 1000ms - //if join failed, delete the task here - if (ret != 0 && thread->thread_handle) { + //delete the task here + if (thread->thread_handle) { + if (ret == 0) { + while (eTaskGetState(thread->thread_handle) != eSuspended) { + vTaskDelay(1); + } + } vTaskDelete(thread->thread_handle); + thread->thread_handle = NULL; } } //in linux, the stack_size, priority and core may not be set here, the code will be ignore the arguments -osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[]) +osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[], bool in_psram) { int ret; struct osi_thread_start_arg start_arg = {0}; @@ -257,9 +266,32 @@ osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priorit if (ret != 0) { goto _err; } - - if (xTaskCreatePinnedToCore(osi_thread_run, name, stack_size, &start_arg, priority, &thread->thread_handle, core) != pdPASS) { + if (in_psram) { +#if (CONFIG_BT_BLUEDROID_TASK_STACK_IN_EXT_MEM) + thread->task = heap_caps_calloc(1, sizeof(StaticTask_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (thread->task == NULL) { + goto _err; + } + thread->stack = heap_caps_calloc_prefer(1, stack_size * sizeof(StackType_t), + 2, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT, + MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (thread->stack == NULL) { + goto _err; + } + thread->thread_handle = xTaskCreateStaticPinnedToCore(osi_thread_run, name, + stack_size, &start_arg, + priority, thread->stack, + thread->task, core); + if (thread->thread_handle == NULL) { + goto _err; + } +#else goto _err; +#endif + }else{ + if (xTaskCreatePinnedToCore(osi_thread_run, name, stack_size, &start_arg, priority, &thread->thread_handle, core) != pdPASS) { + goto _err; + } } osi_sem_take(&start_arg.start_sem, OSI_SEM_MAX_TIMEOUT); @@ -297,6 +329,16 @@ _err: if (thread->stop_sem) { osi_sem_free(&thread->stop_sem); } +#if (CONFIG_BT_BLUEDROID_TASK_STACK_IN_EXT_MEM) + if (thread->stack) { + heap_caps_free(thread->stack); + thread->stack = NULL; + } + if (thread->task) { + heap_caps_free(thread->task); + thread->task = NULL; + } +#endif osi_free(thread); } @@ -330,6 +372,16 @@ void osi_thread_free(osi_thread_t *thread) if (thread->stop_sem) { osi_sem_free(&thread->stop_sem); } +#if (CONFIG_BT_BLUEDROID_TASK_STACK_IN_EXT_MEM) + if (thread->stack) { + heap_caps_free(thread->stack); + thread->stack = NULL; + } + if (thread->task) { + heap_caps_free(thread->task); + thread->task = NULL; + } +#endif osi_free(thread); diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 3e935d04429..1aebcc2908f 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -1279,6 +1279,34 @@ config BT_ALLOCATION_FROM_SPIRAM_FIRST help This select can save the internal RAM if there have the PSRAM +config BT_BLUEDROID_TASK_STACK_IN_EXT_MEM + bool "Place BT task stack in external memory" + depends on FREERTOS_TASK_CREATE_ALLOW_EXT_MEM && (!IDF_TARGET_ESP32 || SPIRAM_CACHE_WORKAROUND) + default n + help + Common prerequisites for placing Bluedroid host + task stacks in PSRAM. + +config BT_BLUEDROID_BTU_TASK_STACK_IN_EXT_MEM + bool "Place BTU task stack in external memory" + depends on BT_BLUEDROID_TASK_STACK_IN_EXT_MEM + default n + help + Allocate BTU_TASK stack from external SPIRAM using static task + allocation. TCB remains in internal DRAM. + + BTU does not perform NVS operations directly. + +config BT_BLUEDROID_HCI_TASK_STACK_IN_EXT_MEM + bool "Place HCI host task stack in external memory" + depends on BT_BLUEDROID_TASK_STACK_IN_EXT_MEM + default n + help + Allocate HCI host task (hciT) stack from external SPIRAM using + static task allocation. TCB remains in internal DRAM. + + HCI does not perform NVS operations. + config BT_BLE_DYNAMIC_ENV_MEMORY bool "Use dynamic memory allocation in BT/BLE stack" depends on BT_BLUEDROID_ENABLED diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 7ca7ad03256..a2265a90eb3 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -114,8 +114,13 @@ int hci_start_up(void) } const size_t workqueue_len[] = {HCI_HOST_TASK_WORKQUEUE0_LEN, HCI_HOST_TASK_WORKQUEUE1_LEN}; +#if (!CONFIG_BT_BLUEDROID_HCI_TASK_STACK_IN_EXT_MEM) hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, - HCI_HOST_TASK_WORKQUEUE_NUM, workqueue_len); + HCI_HOST_TASK_WORKQUEUE_NUM, workqueue_len, false); +#else + hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, + HCI_HOST_TASK_WORKQUEUE_NUM, workqueue_len, true); +#endif if (hci_host_thread == NULL) { goto error; } diff --git a/components/bt/host/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c index 67b48effa50..1bcad2f7ce5 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -195,8 +195,13 @@ bool BTU_StartUp(void) osi_mutex_new(&btu_l2cap_alarm_lock); const size_t workqueue_len[] = {BTU_TASK_WORKQUEUE0_LEN}; +#if (!CONFIG_BT_BLUEDROID_BTU_TASK_STACK_IN_EXT_MEM) btu_thread = osi_thread_create(BTU_TASK_NAME, BTU_TASK_STACK_SIZE, BTU_TASK_PRIO, BTU_TASK_PINNED_TO_CORE, - BTU_TASK_WORKQUEUE_NUM, workqueue_len); + BTU_TASK_WORKQUEUE_NUM, workqueue_len, false); +#else + btu_thread = osi_thread_create(BTU_TASK_NAME, BTU_TASK_STACK_SIZE, BTU_TASK_PRIO, BTU_TASK_PINNED_TO_CORE, + BTU_TASK_WORKQUEUE_NUM, workqueue_len, true); +#endif if (btu_thread == NULL) { goto error_exit; }