Merge branch 'feat/add_spi_output_v5.0' into 'release/v5.0'

Feat/add spi output (v5.0)

See merge request espressif/esp-idf!36952
This commit is contained in:
Island 2025-02-17 11:04:29 +08:00
commit 10bebf8139
5 changed files with 313 additions and 0 deletions

View File

@ -50,6 +50,7 @@ if(CONFIG_BT_ENABLED)
common/btc/profile/esp/blufi/include
common/btc/profile/esp/include
common/hci_log/include
common/ble_log/include
)
@ -78,6 +79,10 @@ if(CONFIG_BT_ENABLED)
"porting/mem/bt_osi_mem.c"
)
if(CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED)
list(APPEND srcs "common/ble_log/ble_log_spi_out.c")
endif()
# Host Bluedroid
if(CONFIG_BT_BLUEDROID_ENABLED)

View File

@ -0,0 +1,220 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ble_log/ble_log_spi_out.h"
// Private defines
#define SPI_OUT_BUS SPI2_HOST
// Private typedefs
typedef struct spi_out_trans
{
spi_transaction_t trans;
struct spi_out_trans *next;
} spi_out_trans_t;
// Private variables
static spi_device_handle_t spi_handle = NULL;
static spi_out_trans_t *trans_head = NULL;
static SemaphoreHandle_t mutex_handle = NULL;
static bool spi_out_inited = false;
// Private function declarations
static void spi_out_init_trans(void);
static void spi_out_deinit_trans(void);
static void spi_out_recycle_trans(uint32_t ms_to_wait);
static void spi_out_append_trans(void);
// Private functions
static void spi_out_init_trans(void)
{
for (int i = 0; i < CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_QUEUE_SIZE; i++)
{
// Allocate memory for SPI transaction
uint8_t *buf = (uint8_t *)heap_caps_malloc(CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_TRANS_BUF_SIZE, MALLOC_CAP_DMA);
assert(buf);
// Initialize new trans
spi_out_trans_t *new_trans = (spi_out_trans_t *)malloc(sizeof(spi_out_trans_t));
assert(new_trans);
memset(new_trans, 0, sizeof(spi_out_trans_t));
new_trans->trans.tx_buffer = buf;
new_trans->trans.length = 0;
// Append new trans to free trans list
new_trans->next = trans_head;
trans_head = new_trans;
}
return;
}
static void spi_out_deinit_trans(void)
{
// Wait up to QUEUE_SIZE * 100 ms for all transactions to complete and be recycled
spi_out_recycle_trans(100);
// Release memory
spi_out_trans_t *next;
while (trans_head != NULL)
{
next = trans_head->next;
free((uint8_t *)trans_head->trans.tx_buffer);
free(trans_head);
trans_head = next;
}
trans_head = NULL;
return;
}
IRAM_ATTR static void spi_out_recycle_trans(uint32_t ms_to_wait)
{
// Try to recycle transaction
spi_transaction_t *ret_trans;
spi_out_trans_t *recycled_trans;
while (ESP_OK == spi_device_get_trans_result(spi_handle, &ret_trans, pdMS_TO_TICKS(ms_to_wait)))
{
recycled_trans = __containerof(ret_trans, spi_out_trans_t, trans);
recycled_trans->next = trans_head;
trans_head = recycled_trans;
trans_head->trans.length = 0;
}
}
IRAM_ATTR static void spi_out_append_trans(void)
{
// Transaction head shall not be NULL for appending
assert(trans_head);
// Detach transaction head
spi_out_trans_t *trans_to_append = trans_head;
trans_head = trans_head->next;
trans_to_append->next = NULL;
// CRITICAL: Length unit conversion from bytes to bits
trans_to_append->trans.length *= 8;
assert(ESP_OK == spi_device_queue_trans(spi_handle, &trans_to_append->trans, 0));
// Try to recycle trans
spi_out_recycle_trans(0);
}
// Public functions
void ble_log_spi_out_init(void)
{
// Avoid double init
if (spi_out_inited)
{
return;
}
// Initialize SPI
spi_bus_config_t bus_config = {
.miso_io_num = -1,
.mosi_io_num = CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_MOSI_IO_NUM,
.sclk_io_num = CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_SCLK_IO_NUM,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 10240
};
spi_device_interface_config_t dev_config = {
.clock_speed_hz = SPI_MASTER_FREQ_20M,
.mode = 0,
.spics_io_num = CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_CS_IO_NUM,
.queue_size = CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_QUEUE_SIZE
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI_OUT_BUS, &bus_config, SPI_DMA_CH_AUTO));
ESP_ERROR_CHECK(spi_bus_add_device(SPI_OUT_BUS, &dev_config, &spi_handle));
// Initialize transaction link nodes
spi_out_init_trans();
// Initialize mutex
mutex_handle = xSemaphoreCreateMutex();
// Set init flag
spi_out_inited = true;
}
void ble_log_spi_out_deinit(void)
{
// Avoid double deinit
if (!spi_out_inited)
{
return;
}
// Deinitialize transaction link nodes
spi_out_deinit_trans();
// Deinitialize SPI
ESP_ERROR_CHECK(spi_bus_remove_device(spi_handle));
ESP_ERROR_CHECK(spi_bus_free(SPI_OUT_BUS));
spi_handle = NULL;
// Deinitialize mutex
vSemaphoreDelete(mutex_handle);
mutex_handle = NULL;
// Reset init flag
spi_out_inited = false;
}
IRAM_ATTR void ble_log_spi_out_write(uint32_t len, const uint8_t *addr, spi_out_source_t source)
{
// Take semaphore
assert(xSemaphoreTake(mutex_handle, portMAX_DELAY) == pdTRUE);
// Recycle trans if free buffer list is empty
if (!trans_head)
{
spi_out_recycle_trans(0);
}
// Length of 0 means flush out
if (!len)
{
assert(trans_head);
if (trans_head->trans.length)
{
spi_out_append_trans();
}
goto release;
}
// Copy user data to buffer
uint32_t copy_buf_len;
uint32_t data_left_len = len;
uint32_t empty_buf_len = CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_TRANS_BUF_SIZE - trans_head->trans.length;
while (data_left_len)
{
// There shall always be available buffer in free buffer list during write operation
assert(trans_head);
// Copy data to buffer and update length
copy_buf_len = (data_left_len > empty_buf_len) ? empty_buf_len : data_left_len;
memcpy((uint8_t *)trans_head->trans.tx_buffer + trans_head->trans.length, addr + (len - data_left_len), copy_buf_len);
trans_head->trans.length += copy_buf_len;
data_left_len -= copy_buf_len;
// Transaction buffer length shall never exceed buffer size
assert(trans_head->trans.length <= CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_TRANS_BUF_SIZE);
// If buffer is full, append transaction and reset buffer length
if (trans_head->trans.length == CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_TRANS_BUF_SIZE)
{
spi_out_append_trans();
empty_buf_len = CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_TRANS_BUF_SIZE;
}
}
release:
xSemaphoreGive(mutex_handle);
return;
}
IRAM_ATTR void ble_log_spi_out_write_esp(uint32_t len, const uint8_t *addr, bool end)
{
ble_log_spi_out_write(len, addr, esp_controller);
}

View File

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_SPI_OUT_H__
#define __BT_SPI_OUT_H__
#include <string.h>
#include "driver/spi_master.h"
#include "freertos/semphr.h"
// Public typedefs
typedef enum
{
esp_controller = 0,
ceva_controller = 1
} spi_out_source_t;
// Public functions
void ble_log_spi_out_init(void);
void ble_log_spi_out_deinit(void);
void ble_log_spi_out_write(uint32_t len, const uint8_t *addr, spi_out_source_t source);
void ble_log_spi_out_write_esp(uint32_t len, const uint8_t *addr, bool end);
#endif // __BT_SPI_OUT_H__

View File

@ -308,6 +308,49 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY
help
Only operate in dump mode
config BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
bool "Output ble controller logs to SPI bus (Experimental)"
depends on BT_LE_CONTROLLER_LOG_ENABLED
depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY
default n
help
Output ble controller logs to SPI bus
config BT_LE_CONTROLLER_LOG_SPI_OUT_QUEUE_SIZE
int "Number of ble controller log async SPI output queues"
depends on BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
default 4
help
The number of ble controller log async SPI output queues
config BT_LE_CONTROLLER_LOG_SPI_OUT_TRANS_BUF_SIZE
int "Size of ble controller log async SPI output transaction buffer size"
depends on BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
default 512
help
The size of ble controller log async SPI output transaction buffer size
config BT_LE_CONTROLLER_LOG_SPI_OUT_MOSI_IO_NUM
int "GPIO number of SPI MOSI"
depends on BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
default 1
help
GPIO number of SPI MOSI
config BT_LE_CONTROLLER_LOG_SPI_OUT_SCLK_IO_NUM
int "GPIO number of SPI SCLK"
depends on BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
default 6
help
GPIO number of SPI SCLK
config BT_LE_CONTROLLER_LOG_SPI_OUT_CS_IO_NUM
int "GPIO number of SPI CS"
depends on BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
default 7
help
GPIO number of SPI CS
config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE
bool "Store ble controller logs to flash(Experimental)"
depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY

View File

@ -61,6 +61,12 @@
#include "hal/efuse_ll.h"
#include "soc/rtc.h"
#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
#include "ble_log/ble_log_spi_out.h"
#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
/* Macro definition
************************************************************************
*/
@ -208,6 +214,7 @@ enum log_out_mode {
LOG_DUMP_MEMORY,
LOG_ASYNC_OUT,
LOG_STORAGE_TO_FLASH,
LOG_SPI_OUT,
};
bool log_is_inited = false;
@ -216,6 +223,8 @@ uint8_t log_output_mode = LOG_DUMP_MEMORY;
#else
#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE
uint8_t log_output_mode = LOG_STORAGE_TO_FLASH;
#elif CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
uint8_t log_output_mode = LOG_SPI_OUT;
#else
uint8_t log_output_mode = LOG_ASYNC_OUT;
#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE
@ -263,6 +272,13 @@ esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode)
}
#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE
break;
case LOG_SPI_OUT:
task_create = true;
#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
ble_log_spi_out_init();
bt_controller_log_interface = ble_log_spi_out_write_esp;
#endif // CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
break;
default:
assert(0);
}
@ -278,6 +294,9 @@ esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode)
void esp_bt_ontroller_log_deinit(void)
{
ble_log_deinit_async();
#if CONFIG_BT_LE_CONTROLLER_LOG_SPI_OUT_ENABLED
ble_log_spi_out_deinit();
#endif
log_is_inited = false;
}