From ed46976f4129890a97e622a1e873a272f44c79b1 Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Fri, 30 Mar 2018 11:39:42 +0800 Subject: [PATCH] esp32/bt/driver: support static allocation of FreeRTOS queues used by ISR routine Support static allocation of FreeRTOS queues used by ISR routine in WiFi/BT/esp_timer/driver etc --- components/bt/bt.c | 241 +++++++++++++++++++ components/driver/ledc.c | 17 +- components/esp32/Kconfig | 1 + components/esp32/esp_timer.c | 12 + components/esp32/include/esp_wifi_internal.h | 5 + components/esp32/lib | 2 +- components/esp32/wifi_internal.c | 60 +++++ 7 files changed, 336 insertions(+), 2 deletions(-) diff --git a/components/bt/bt.c b/components/bt/bt.c index 1b92a20cc..3a274a703 100644 --- a/components/bt/bt.c +++ b/components/bt/bt.c @@ -17,6 +17,8 @@ #include #include +#include "sdkconfig.h" +#include "esp_heap_caps.h" #include "esp_heap_caps_init.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -115,6 +117,17 @@ static btdm_dram_available_region_t btdm_dram_available_region[] = { {ESP_BT_MODE_BTDM, 0x3ffbdb28, 0x3ffc0000}, }; +#if CONFIG_SPIRAM_USE_MALLOC +typedef struct { + QueueHandle_t handle; + void *storage; + void *buffer; +} btdm_queue_item_t; +#define BTDM_MAX_QUEUE_NUM (5) +static btdm_queue_item_t btdm_queue_table[BTDM_MAX_QUEUE_NUM]; +SemaphoreHandle_t btdm_queue_table_mux = NULL; +#endif /* #if CONFIG_SPIRAM_USE_MALLOC */ + struct osi_funcs_t { xt_handler (*_set_isr)(int n, xt_handler f, void *arg); void (*_ints_on)(unsigned int mask); @@ -159,6 +172,52 @@ static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED; static esp_pm_lock_handle_t s_pm_lock; #endif +#if CONFIG_SPIRAM_USE_MALLOC +bool IRAM_ATTR btdm_queue_generic_register(const btdm_queue_item_t *queue) +{ + if (!btdm_queue_table_mux || !queue) { + return NULL; + } + + bool ret = false; + btdm_queue_item_t *item; + xSemaphoreTake(btdm_queue_table_mux, portMAX_DELAY); + for (int i = 0; i < BTDM_MAX_QUEUE_NUM; ++i) { + item = &btdm_queue_table[i]; + if (item->handle == NULL) { + memcpy(item, queue, sizeof(btdm_queue_item_t)); + ret = true; + break; + } + } + xSemaphoreGive(btdm_queue_table_mux); + return ret; +} + +bool IRAM_ATTR btdm_queue_generic_deregister(btdm_queue_item_t *queue) +{ + if (!btdm_queue_table_mux || !queue) { + return false; + } + + bool ret = false; + btdm_queue_item_t *item; + xSemaphoreTake(btdm_queue_table_mux, portMAX_DELAY); + for (int i = 0; i < BTDM_MAX_QUEUE_NUM; ++i) { + item = &btdm_queue_table[i]; + if (item->handle == queue->handle) { + memcpy(queue, item, sizeof(btdm_queue_item_t)); + memset(item, 0, sizeof(btdm_queue_item_t)); + ret = true; + break; + } + } + xSemaphoreGive(btdm_queue_table_mux); + return ret; +} + +#endif /* CONFIG_SPIRAM_USE_MALLOC */ + static void IRAM_ATTR interrupt_disable(void) { portENTER_CRITICAL(&global_int_mux); @@ -176,12 +235,63 @@ static void IRAM_ATTR task_yield_from_isr(void) static void *IRAM_ATTR semphr_create_wrapper(uint32_t max, uint32_t init) { +#if !CONFIG_SPIRAM_USE_MALLOC return (void *)xSemaphoreCreateCounting(max, init); +#else + StaticQueue_t *queue_buffer = NULL; + QueueHandle_t handle = NULL; + + queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue_buffer) { + goto error; + } + + handle = xSemaphoreCreateCountingStatic(max, init, queue_buffer); + if (!handle) { + goto error; + } + + btdm_queue_item_t item = { + .handle = handle, + .storage = NULL, + .buffer = queue_buffer, + }; + + if (!btdm_queue_generic_register(&item)) { + goto error; + } + return handle; + + error: + if (handle) { + vSemaphoreDelete(handle); + } + if (queue_buffer) { + free(queue_buffer); + } + + return NULL; +#endif } static void IRAM_ATTR semphr_delete_wrapper(void *semphr) { +#if !CONFIG_SPIRAM_USE_MALLOC vSemaphoreDelete(semphr); +#else + btdm_queue_item_t item = { + .handle = semphr, + .storage = NULL, + .buffer = NULL, + }; + + if (btdm_queue_generic_deregister(&item)) { + vSemaphoreDelete(item.handle); + free(item.buffer); + } + + return; +#endif } static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw) @@ -210,12 +320,63 @@ static int32_t IRAM_ATTR semphr_give_wrapper(void *semphr) static void *IRAM_ATTR mutex_create_wrapper(void) { +#if CONFIG_SPIRAM_USE_MALLOC + StaticQueue_t *queue_buffer = NULL; + QueueHandle_t handle = NULL; + + queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue_buffer) { + goto error; + } + + handle = xSemaphoreCreateMutexStatic(queue_buffer); + if (!handle) { + goto error; + } + + btdm_queue_item_t item = { + .handle = handle, + .storage = NULL, + .buffer = queue_buffer, + }; + + if (!btdm_queue_generic_register(&item)) { + goto error; + } + return handle; + + error: + if (handle) { + vSemaphoreDelete(handle); + } + if (queue_buffer) { + free(queue_buffer); + } + + return NULL; +#else return (void *)xSemaphoreCreateMutex(); +#endif } static void IRAM_ATTR mutex_delete_wrapper(void *mutex) { +#if !CONFIG_SPIRAM_USE_MALLOC vSemaphoreDelete(mutex); +#else + btdm_queue_item_t item = { + .handle = mutex, + .storage = NULL, + .buffer = NULL, + }; + + if (btdm_queue_generic_deregister(&item)) { + vSemaphoreDelete(item.handle); + free(item.buffer); + } + + return; +#endif } static int32_t IRAM_ATTR mutex_lock_wrapper(void *mutex) @@ -230,12 +391,74 @@ static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex) static void *IRAM_ATTR queue_create_wrapper(uint32_t queue_len, uint32_t item_size) { +#if CONFIG_SPIRAM_USE_MALLOC + StaticQueue_t *queue_buffer = NULL; + uint8_t *queue_storage = NULL; + QueueHandle_t handle = NULL; + + queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue_buffer) { + goto error; + } + + queue_storage = heap_caps_malloc((queue_len*item_size), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue_storage ) { + goto error; + } + + handle = xQueueCreateStatic(queue_len, item_size, queue_storage, queue_buffer); + if (!handle) { + goto error; + } + + btdm_queue_item_t item = { + .handle = handle, + .storage = queue_storage, + .buffer = queue_buffer, + }; + + if (!btdm_queue_generic_register(&item)) { + goto error; + } + + return handle; + + error: + if (handle) { + vQueueDelete(handle); + } + if (queue_storage) { + free(queue_storage); + } + if (queue_buffer) { + free(queue_buffer); + } + + return NULL; +#else return (void *)xQueueCreate(queue_len, item_size); +#endif } static void IRAM_ATTR queue_delete_wrapper(void *queue) { +#if !CONFIG_SPIRAM_USE_MALLOC vQueueDelete(queue); +#else + btdm_queue_item_t item = { + .handle = queue, + .storage = NULL, + .buffer = NULL, + }; + + if (btdm_queue_generic_deregister(&item)) { + vQueueDelete(item.handle); + free(item.storage); + free(item.buffer); + } + + return; +#endif } static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms) @@ -482,6 +705,18 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGI(BTDM_LOG_TAG, "BT controller compile version [%s]\n", btdm_controller_get_compile_version()); +#if CONFIG_SPIRAM_USE_MALLOC + btdm_queue_table_mux = xSemaphoreCreateMutex(); + if (btdm_queue_table == NULL) { +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_delete(s_pm_lock); + s_pm_lock = NULL; +#endif + return ESP_ERR_NO_MEM; + } + memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM); +#endif + btdm_osi_funcs_register(&osi_funcs); btdm_controller_mem_init(); @@ -515,6 +750,12 @@ esp_err_t esp_bt_controller_deinit(void) periph_module_disable(PERIPH_BT_MODULE); +#if CONFIG_SPIRAM_USE_MALLOC + vSemaphoreDelete(btdm_queue_table_mux); + btdm_queue_table_mux = NULL; + memset(btdm_queue_table, 0, sizeof(btdm_queue_item_t) * BTDM_MAX_QUEUE_NUM); +#endif + btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #ifdef CONFIG_PM_ENABLE diff --git a/components/driver/ledc.c b/components/driver/ledc.c index 881f01ba5..0365deb2e 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include +#include #include "esp_intr.h" #include "esp_intr_alloc.h" #include "freertos/FreeRTOS.h" @@ -40,6 +41,9 @@ typedef struct { ledc_fade_mode_t mode; xSemaphoreHandle ledc_fade_sem; xSemaphoreHandle ledc_fade_mux; +#if CONFIG_SPIRAM_USE_MALLOC + StaticQueue_t ledc_fade_sem_storage; +#endif } ledc_fade_t; static ledc_fade_t *s_ledc_fade_rec[LEDC_SPEED_MODE_MAX][LEDC_CHANNEL_MAX]; @@ -485,9 +489,20 @@ static esp_err_t ledc_fade_channel_deinit(ledc_mode_t speed_mode, ledc_channel_t static esp_err_t ledc_fade_channel_init_check(ledc_mode_t speed_mode, ledc_channel_t channel) { if (s_ledc_fade_rec[speed_mode][channel] == NULL) { +#if CONFIG_SPIRAM_USE_MALLOC + s_ledc_fade_rec[speed_mode][channel] = (ledc_fade_t *) heap_caps_calloc(1, sizeof(ledc_fade_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!s_ledc_fade_rec[speed_mode][channel]) { + ledc_fade_channel_deinit(speed_mode, channel); + return ESP_FAIL; + } + + memset(&s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem_storage, 0, sizeof(StaticQueue_t)); + s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem = xSemaphoreCreateBinaryStatic(&s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem_storage); +#else s_ledc_fade_rec[speed_mode][channel] = (ledc_fade_t *) calloc(1, sizeof(ledc_fade_t)); - s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux = xSemaphoreCreateMutex(); s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem = xSemaphoreCreateBinary(); +#endif + s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux = xSemaphoreCreateMutex(); } if (s_ledc_fade_rec[speed_mode][channel] && s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 3c94b0e95..3c1266722 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -62,6 +62,7 @@ config SPIRAM_USE_CAPS_ALLOC bool "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)" config SPIRAM_USE_MALLOC bool "Make RAM allocatable using malloc() as well" + select SUPPORT_STATIC_ALLOCATION endchoice choice SPIRAM_TYPE diff --git a/components/esp32/esp_timer.c b/components/esp32/esp_timer.c index 6987b4c64..67ae2dd72 100644 --- a/components/esp32/esp_timer.c +++ b/components/esp32/esp_timer.c @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "esp_types.h" #include "esp_attr.h" #include "esp_err.h" @@ -82,6 +83,12 @@ static esp_timer_handle_t s_timer_in_callback; static TaskHandle_t s_timer_task; // counting semaphore used to notify the timer task from ISR static SemaphoreHandle_t s_timer_semaphore; + +#if CONFIG_SPIRAM_USE_MALLOC +// memory for s_timer_semaphore +static StaticQueue_t s_timer_semaphore_memory; +#endif + // lock protecting s_timers, s_inactive_timers, s_timer_in_callback static portMUX_TYPE s_timer_lock = portMUX_INITIALIZER_UNLOCKED; @@ -329,7 +336,12 @@ esp_err_t esp_timer_init(void) return ESP_ERR_INVALID_STATE; } +#if CONFIG_SPIRAM_USE_MALLOC + memset(&s_timer_semaphore_memory, 0, sizeof(StaticQueue_t)); + s_timer_semaphore = xSemaphoreCreateCountingStatic(TIMER_EVENT_QUEUE_SIZE, 0, &s_timer_semaphore_memory); +#else s_timer_semaphore = xSemaphoreCreateCounting(TIMER_EVENT_QUEUE_SIZE, 0); +#endif if (!s_timer_semaphore) { return ESP_ERR_NO_MEM; } diff --git a/components/esp32/include/esp_wifi_internal.h b/components/esp32/include/esp_wifi_internal.h index b1984082d..8eb7c0b6b 100755 --- a/components/esp32/include/esp_wifi_internal.h +++ b/components/esp32/include/esp_wifi_internal.h @@ -40,6 +40,11 @@ extern "C" { #endif +typedef struct { + QueueHandle_t handle; /**< FreeRTOS queue handler */ + void *storage; /**< storage for FreeRTOS queue */ +} wifi_static_queue_t; + /** * @brief Initialize Wi-Fi Driver * Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer, diff --git a/components/esp32/lib b/components/esp32/lib index e9e457933..8cd9fd455 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit e9e4579336a539590a88ccac05ab9d0422506c3d +Subproject commit 8cd9fd455e98a5c818f2796b4b83107884b7874c diff --git a/components/esp32/wifi_internal.c b/components/esp32/wifi_internal.c index 350f2cb86..7d7a77209 100644 --- a/components/esp32/wifi_internal.c +++ b/components/esp32/wifi_internal.c @@ -12,9 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include "esp_attr.h" #include "esp_heap_caps.h" #include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "esp_wifi.h" +#include "esp_wifi_internal.h" /* If CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST is enabled. Prefer to allocate a chunk of memory in SPIRAM firstly. @@ -54,3 +59,58 @@ IRAM_ATTR void *wifi_calloc( size_t n, size_t size ) return calloc(n, size); #endif } + +wifi_static_queue_t* wifi_create_queue( int queue_len, int item_size) +{ + wifi_static_queue_t *queue = NULL; + + queue = (wifi_static_queue_t*)heap_caps_malloc(sizeof(wifi_static_queue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue) { + return NULL; + } + +#if CONFIG_SPIRAM_USE_MALLOC + + queue->storage = heap_caps_calloc(1, sizeof(StaticQueue_t) + (queue_len*item_size), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (!queue->storage) { + goto _error; + } + + queue->handle = xQueueCreateStatic( queue_len, item_size, ((uint8_t*)(queue->storage)) + sizeof(StaticQueue_t), (StaticQueue_t*)(queue->storage)); + + if (!queue->handle) { + goto _error; + } + + return queue; + +_error: + if (queue) { + if (queue->storage) { + free(queue->storage); + } + + free(queue); + } + + return NULL; +#else + queue->handle = xQueueCreate( queue_len, item_size); + return queue; +#endif +} + +void wifi_delete_queue(wifi_static_queue_t *queue) +{ + if (queue) { + vQueueDelete(queue->handle); + +#if CONFIG_SPIRAM_USE_MALLOC + if (queue->storage) { + free(queue->storage); + } +#endif + + free(queue); + } +}