Merge branch 'refactor/spi_driver_gdma_link_list' into 'master'

refactor(driver_spi): spi driver using dma link list driver

See merge request espressif/esp-idf!51099
This commit is contained in:
Wan Lei
2026-08-10 19:09:58 +08:00
13 changed files with 214 additions and 347 deletions

View File

@@ -14,6 +14,7 @@
#include "hal/spi_types.h"
#include "hal/spi_ll.h"
#include "soc/lldesc.h"
#include "esp_private/spi_common_internal.h"
#include "esp_private/adc_dma.h"

View File

@@ -17,6 +17,7 @@
#include "hal/dma_types.h"
#include "esp_private/spi_dma.h"
#include "esp_private/gdma.h"
#include "esp_private/gdma_link.h"
#include "esp_private/spi_share_hw_ctrl.h"
#if SOC_PAU_SUPPORTED
#include "soc/regdma.h"
@@ -37,14 +38,6 @@ typedef dma_descriptor_align8_t spi_dma_desc_t;
typedef dma_descriptor_align4_t spi_dma_desc_t;
#endif
#if SOC_NON_CACHEABLE_OFFSET_SRAM
#include "hal/cache_ll.h"
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))CACHE_LL_L2MEM_NON_CACHE_ADDR(addr))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))CACHE_LL_L2MEM_CACHE_ADDR(addr))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
// Status of a spi bus
typedef enum {
@@ -82,6 +75,8 @@ typedef struct {
int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx.
spi_dma_desc_t *dmadesc_tx; ///< DMA descriptor array for TX
spi_dma_desc_t *dmadesc_rx; ///< DMA descriptor array for RX
gdma_link_list_handle_t tx_link_handle; ///< DMA tx link list for GDMA and SPIDMA
gdma_link_list_handle_t rx_link_handle; ///< DMA rx link list for GDMA and SPIDMA
} spi_dma_ctx_t;
#if SOC_PAU_SUPPORTED
@@ -145,12 +140,13 @@ esp_err_t spicommon_dma_desc_alloc(spi_host_device_t host_id, int cfg_max_sz, in
/**
* Setupt/Configure dma descriptor link list
*
* @param dmadesc start of dma descriptor memory
* @param dma_ctx DMA context pointer
* @param offset offset of the item in the link list
* @param data start of data buffer to be configured in
* @param len length of data buffer, in byte
* @param is_rx if descriptor is for rx/receive direction
*/
void spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx);
void spicommon_dma_desc_setup_link(const spi_dma_ctx_t *dma_ctx, int offset, const void *data, int len, bool is_rx);
/**
* @brief Setup private buffer for DMA transfer

View File

@@ -5,3 +5,12 @@ entries:
spi_hal_iram (noflash)
if SPI_SLAVE_ISR_IN_IRAM = y:
spi_slave_hal_iram (noflash)
[mapping:gpspi_driver_gdma_link]
archive: libesp_driver_dma.a
entries:
if SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y:
gdma_link: gdma_link_mount_buffers (noflash)
gdma_link: gdma_link_count_buffer_size_till_eof (noflash)
gdma_link: gdma_link_get_buffer (noflash)
gdma_link: gdma_link_get_length (noflash)

View File

@@ -22,8 +22,9 @@
#include "esp_private/spi_common_internal.h"
#include "esp_private/spi_share_hw_ctrl.h"
#include "esp_private/esp_cache_private.h"
#include "esp_private/esp_dma_utils.h"
#include "esp_private/gdma_link.h"
#include "esp_private/sleep_retention.h"
#include "esp_dma_utils.h"
#include "hal/spi_hal.h"
#if SOC_GDMA_SUPPORTED
#include "hal/gdma_ll.h"
@@ -312,7 +313,7 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch
#endif
gdma_transfer_config_t trans_cfg = {
.max_data_burst_size = burst_size,
#if CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE
#if SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH
.access_ext_mem = true, // allow to transfer data from/to external memory directly by DMA
#endif
};
@@ -355,69 +356,79 @@ cleanup:
return ret;
}
esp_err_t spicommon_dma_desc_alloc(spi_host_device_t host_id, int cfg_max_sz, int *actual_max_sz)
static void spicommon_dma_link_free(spi_host_device_t host_id)
{
int dma_desc_ct = (cfg_max_sz + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
if (dma_desc_ct == 0) {
dma_desc_ct = 1; //default to 4k when max is not given
}
spi_dma_ctx_t *dma_ctx = spi_bus_get_dma_ctx(host_id);
if (!dma_ctx) {
return ESP_ERR_INVALID_STATE;
return;
}
dma_ctx->dmadesc_tx = heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, 1, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
dma_ctx->dmadesc_rx = heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, 1, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (dma_ctx->dmadesc_tx == NULL || dma_ctx->dmadesc_rx == NULL) {
if (dma_ctx->dmadesc_tx) {
free(dma_ctx->dmadesc_tx);
dma_ctx->dmadesc_tx = NULL;
}
if (dma_ctx->dmadesc_rx) {
free(dma_ctx->dmadesc_rx);
dma_ctx->dmadesc_rx = NULL;
}
return ESP_ERR_NO_MEM;
if (dma_ctx->tx_link_handle) {
gdma_del_link_list(dma_ctx->tx_link_handle);
dma_ctx->tx_link_handle = NULL;
}
if (dma_ctx->rx_link_handle) {
gdma_del_link_list(dma_ctx->rx_link_handle);
dma_ctx->rx_link_handle = NULL;
}
// cache sync using align_up length thanks to heap alloc already consider the cache alignment requirement
size_t aligned_len = ESP_ALIGN_UP(sizeof(spi_dma_desc_t) * dma_desc_ct, bus_ctx[host_id]->bus_attr.cache_align_int);
// write back and then invalidate the cache, because later we will read/write the link list items by non-cached address
esp_err_t ret = esp_cache_msync(dma_ctx->dmadesc_tx, aligned_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
ESP_RETURN_ON_FALSE_ISR((ret == ESP_OK) || (ret == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_ARG, SPI_TAG, "dma desc sync failed");
ret = esp_cache_msync(dma_ctx->dmadesc_rx, aligned_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
ESP_RETURN_ON_FALSE_ISR((ret == ESP_OK) || (ret == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_ARG, SPI_TAG, "dma desc sync failed");
dma_ctx->dma_desc_num = dma_desc_ct;
*actual_max_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
return ESP_OK;
}
void SPI_COMMON_ISR_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
esp_err_t spicommon_dma_desc_alloc(spi_host_device_t host_id, int cfg_max_sz, int *actual_max_sz)
{
dmadesc = ADDR_DMA_2_CPU(dmadesc);
int n = 0;
while (len) {
int dmachunklen = len;
if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
}
if (is_rx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].dw0.size = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].dw0.size = dmachunklen;
dmadesc[n].dw0.length = dmachunklen;
}
dmadesc[n].buffer = (uint8_t *)data;
dmadesc[n].dw0.suc_eof = 0;
dmadesc[n].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
esp_err_t ret = ESP_OK;
spi_dma_ctx_t *dma_ctx = spi_bus_get_dma_ctx(host_id);
ESP_RETURN_ON_FALSE(dma_ctx, ESP_ERR_INVALID_STATE, SPI_TAG, "dma context not initialized");
size_t tx_buffer_alignment = dma_ctx->dma_align_tx_int ? dma_ctx->dma_align_tx_int : 1;
size_t rx_buffer_alignment = dma_ctx->dma_align_rx_int ? dma_ctx->dma_align_rx_int : 1;
if (dma_ctx->dma_align_tx_ext < BIT(31)) {
tx_buffer_alignment = MAX(tx_buffer_alignment, dma_ctx->dma_align_tx_ext);
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
if (dma_ctx->dma_align_rx_ext < BIT(31)) {
rx_buffer_alignment = MAX(rx_buffer_alignment, dma_ctx->dma_align_rx_ext);
}
size_t tx_item_num = esp_dma_calculate_node_count(cfg_max_sz, tx_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
size_t rx_item_num = esp_dma_calculate_node_count(cfg_max_sz, rx_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
gdma_link_list_config_t link_cfg = {
.num_items = MAX(MAX(tx_item_num, rx_item_num), 1), //default to 1 when 'cfg_max_sz' is not given
.item_alignment = DMA_DESC_MEM_ALIGN_SIZE,
};
ESP_RETURN_ON_ERROR(gdma_new_link_list(&link_cfg, &dma_ctx->tx_link_handle), SPI_TAG, "failed to allocate tx dma link");
ESP_GOTO_ON_ERROR(gdma_new_link_list(&link_cfg, &dma_ctx->rx_link_handle), cleanup, SPI_TAG, "failed to allocate rx dma link");
// save link info
dma_ctx->dma_desc_num = link_cfg.num_items;
dma_ctx->dmadesc_tx = (spi_dma_desc_t *)gdma_link_get_head_addr(dma_ctx->tx_link_handle);
dma_ctx->dmadesc_rx = (spi_dma_desc_t *)gdma_link_get_head_addr(dma_ctx->rx_link_handle);
*actual_max_sz = dma_ctx->dma_desc_num * ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, rx_buffer_alignment);
return ESP_OK;
cleanup:
spicommon_dma_link_free(host_id);
return ret;
}
void SPI_COMMON_ISR_ATTR spicommon_dma_desc_setup_link(const spi_dma_ctx_t *dma_ctx, int offset, const void *data, int len, bool is_rx)
{
size_t buffer_alignment;
if (esp_ptr_internal(data)) {
buffer_alignment = is_rx ? dma_ctx->dma_align_rx_int : dma_ctx->dma_align_tx_int;
} else {
buffer_alignment = is_rx ? dma_ctx->dma_align_rx_ext : dma_ctx->dma_align_tx_ext;
}
gdma_buffer_mount_config_t mount_config = {
.buffer = (void *)data,
.buffer_alignment = buffer_alignment,
.length = is_rx ? ESP_ALIGN_UP(len, 4) : len, // dma rx hardware requires 4 bytes alignment
.flags = {
.mark_eof = true,
.mark_final = GDMA_FINAL_LINK_TO_NULL,
.bypass_buffer_align_check = true, // 'setup_priv_buffer' already do the check
}
};
esp_err_t ret = gdma_link_mount_buffers(is_rx ? dma_ctx->rx_link_handle : dma_ctx->tx_link_handle, offset, &mount_config, 1, NULL);
assert(ret == ESP_OK);
(void)ret;
}
esp_err_t SPI_COMMON_ISR_ATTR spicommon_dma_setup_priv_buffer(spi_host_device_t host_id, uint32_t *buffer, uint32_t len, bool is_tx, bool psram_prefer, bool auto_malloc, uint32_t **ret_buffer)
@@ -508,13 +519,7 @@ esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id)
gdma_del_channel(dma_ctx->tx_dma_chan);
}
#endif
if (dma_ctx->dmadesc_tx) {
free(dma_ctx->dmadesc_tx);
}
if (dma_ctx->dmadesc_rx) {
free(dma_ctx->dmadesc_rx);
}
spicommon_dma_link_free(host_id);
free(dma_ctx);
spi_dma_ctx[host_id] = NULL;
return ESP_OK;

View File

@@ -79,8 +79,8 @@ void SPI_DMA_ISR_ATTR spi_dma_start(spi_dma_chan_handle_t chan_handle, void *add
spi_dma_dev_t *spi_dma = SPI_LL_GET_HW(chan_handle.host_id);
if (chan_handle.dir == DMA_CHANNEL_DIRECTION_TX) {
spi_ll_dma_tx_start(spi_dma, chan_handle.chan_id, (lldesc_t *)addr);
spi_ll_dma_tx_start(spi_dma, chan_handle.chan_id, addr);
} else {
spi_ll_dma_rx_start(spi_dma, chan_handle.chan_id, (lldesc_t *)addr);
spi_ll_dma_rx_start(spi_dma, chan_handle.chan_id, addr);
}
}

View File

@@ -737,7 +737,7 @@ static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal
const spi_dma_ctx_t *dma_ctx = host->dma_ctx;
if (trans->rcv_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
spicommon_dma_desc_setup_link(dma_ctx, 0, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
spi_dma_reset(dma_ctx->rx_dma_chan);
spi_hal_hw_prepare_rx(hal->hw);
@@ -751,7 +751,7 @@ static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal
}
#endif
if (trans->send_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
spicommon_dma_desc_setup_link(dma_ctx, 0, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
spi_dma_reset(dma_ctx->tx_dma_chan);
spi_hal_hw_prepare_tx(hal->hw);

View File

@@ -17,7 +17,6 @@
#include "esp_cache.h"
#include "esp_heap_caps.h"
#include "esp_rom_sys.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "soc/spi_periph.h"
#include "soc/soc_memory_layout.h"
@@ -602,14 +601,14 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_tr
static void SPI_SLAVE_ISR_ATTR s_spi_slave_dma_prepare_data(spi_dma_ctx_t *dma_ctx, spi_slave_hal_context_t *hal)
{
if (hal->rx_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, hal->rx_buffer, (hal->rx_bitlen + 7) / 8, true);
spicommon_dma_desc_setup_link(dma_ctx, 0, hal->rx_buffer, (hal->rx_bitlen + 7) / 8, true);
spi_dma_reset(dma_ctx->rx_dma_chan);
spi_slave_hal_hw_prepare_rx(hal->hw);
spi_dma_start(dma_ctx->rx_dma_chan, dma_ctx->dmadesc_rx);
}
if (hal->tx_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, hal->tx_buffer, (hal->tx_bitlen + 7) / 8, false);
spicommon_dma_desc_setup_link(dma_ctx, 0, hal->tx_buffer, (hal->tx_bitlen + 7) / 8, false);
spi_dma_reset(dma_ctx->tx_dma_chan);
spi_slave_hal_hw_prepare_tx(hal->hw);

View File

@@ -5,6 +5,7 @@
*/
#include <stdatomic.h>
#include <sys/param.h>
#include "esp_compiler.h"
#include "esp_log.h"
#include "esp_check.h"
@@ -41,6 +42,26 @@ typedef struct {
bool dma_hw_error; //true if DMA hardware over/underflow occurred
} spi_slave_hd_trans_priv_t;
typedef struct {
spi_dma_desc_t *desc; // DMA descriptor
void *arg; // Original transaction descriptor
} slave_hd_append_desc_t;
/** append dma pool layout
*
* |**********............-------*******|
* ^ ^ ^ ^
* | | | |
* root done hw_eof free
*/
typedef struct {
slave_hd_append_desc_t *desc_root; ///< Root of the DMA descriptors.
slave_hd_append_desc_t *free_desc; ///< Current DMA descriptor that could be linked (set up).
slave_hd_append_desc_t *done_desc; ///< Head of the finished descriptors which are not dealed by software
uint32_t eof_desc; ///< DMA desc of current end
uint32_t used_desc_cnt; ///< Number of the descriptors that have been setup
} slave_hd_append_context_t;
typedef struct {
spi_host_device_t host_id;
int cs_io_num;
@@ -53,6 +74,8 @@ typedef struct {
spi_slave_hd_callback_config_t callback;
spi_slave_hd_hal_context_t hal;
bool append_mode;
slave_hd_append_context_t append_tx_ctx;
slave_hd_append_context_t append_rx_ctx;
QueueHandle_t tx_trans_queue;
QueueHandle_t tx_ret_queue;
@@ -113,6 +136,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
SPIHD_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
#endif
SPIHD_CHECK(!three_wire_mode || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "mosi pin must be output capable in 3-wire mode", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(!append_mode || bus_config->max_transfer_sz > SPI_MAX_DMA_LEN, "max_transfer_sz must greater than 4092 to using append mode", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(ESP_OK == spicommon_bus_alloc(host_id, "slave_hd"), "host already in use", ESP_ERR_INVALID_STATE);
// spi_slave_hd_slot_t contains atomic variable, memory must be allocated from internal memory
@@ -149,18 +173,24 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
goto cleanup;
}
host->hal.dma_desc_num = host->dma_ctx->dma_desc_num;
host->hal.dmadesc_tx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
host->hal.dmadesc_rx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
if (!(host->hal.dmadesc_tx && host->hal.dmadesc_rx)) {
slave_hd_append_context_t *append_tx = &host->append_tx_ctx;
slave_hd_append_context_t *append_rx = &host->append_rx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
append_tx->desc_root = heap_caps_malloc(sizeof(slave_hd_append_desc_t) * dma_desc_num, MALLOC_CAP_DEFAULT);
append_rx->desc_root = heap_caps_malloc(sizeof(slave_hd_append_desc_t) * dma_desc_num, MALLOC_CAP_DEFAULT);
if (!(append_tx->desc_root && append_rx->desc_root)) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//Pair each desc to each possible trans
for (int i = 0; i < host->hal.dma_desc_num; i ++) {
host->hal.dmadesc_tx[i].desc = &host->dma_ctx->dmadesc_tx[i];
host->hal.dmadesc_rx[i].desc = &host->dma_ctx->dmadesc_rx[i];
for (int i = 0; i < dma_desc_num; i ++) {
append_tx->desc_root[i].desc = &host->dma_ctx->dmadesc_tx[i];
append_rx->desc_root[i].desc = &host->dma_ctx->dmadesc_rx[i];
}
append_tx->free_desc = append_tx->desc_root;
append_rx->free_desc = append_rx->desc_root;
append_tx->done_desc = append_tx->desc_root + dma_desc_num - 1;
append_rx->done_desc = append_rx->desc_root + dma_desc_num - 1;
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, NULL);
if (ret != ESP_OK) {
@@ -350,8 +380,8 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
spicommon_bus_free_io_cfg(host_id);
spicommon_cs_free_io(host->cs_io_num, &host->bus_attr->gpio_reserve);
free(host->hal.dmadesc_tx);
free(host->hal.dmadesc_rx);
free(host->append_tx_ctx.desc_root);
free(host->append_rx_ctx.desc_root);
spicommon_dma_chan_free(host_id);
spicommon_bus_free(host_id);
@@ -488,7 +518,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg)
spicommon_dma_rx_mb(host->host_id, host->rx_curr_trans.aligned_buffer);
spi_slave_hd_rx_dma_error_check(host, host->rx_curr_trans);
bool ret_queue = true;
host->rx_curr_trans.trans->trans_len = spi_slave_hd_hal_rxdma_seg_get_len(hal);
host->rx_curr_trans.trans->trans_len = gdma_link_count_buffer_size_till_eof(host->dma_ctx->rx_link_handle, 0);
if (callback->cb_recv) {
spi_slave_hd_event_t ev = {
.event = SPI_EV_RECV,
@@ -511,7 +541,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg)
if (!host->tx_curr_trans.trans) {
ret = xQueueReceiveFromISR(host->tx_trans_queue, &host->tx_curr_trans, &awoken);
if ((ret == pdTRUE) && host->tx_curr_trans.trans) {
spicommon_dma_desc_setup_link(hal->dmadesc_tx->desc, host->tx_curr_trans.aligned_buffer, host->tx_curr_trans.trans->len, false);
spicommon_dma_desc_setup_link(host->dma_ctx, 0, host->tx_curr_trans.aligned_buffer, host->tx_curr_trans.trans->len, false);
spi_dma_reset(host->dma_ctx->tx_dma_chan);
spi_slave_hd_hal_txdma(hal);
spi_dma_start(host->dma_ctx->tx_dma_chan, host->dma_ctx->dmadesc_tx);
@@ -530,7 +560,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg)
if (!host->rx_curr_trans.trans) {
ret = xQueueReceiveFromISR(host->rx_trans_queue, &host->rx_curr_trans, &awoken);
if ((ret == pdTRUE) && host->rx_curr_trans.trans) {
spicommon_dma_desc_setup_link(hal->dmadesc_rx->desc, host->rx_curr_trans.aligned_buffer, host->rx_curr_trans.trans->len, true);
spicommon_dma_desc_setup_link(host->dma_ctx, 0, host->rx_curr_trans.aligned_buffer, host->rx_curr_trans.trans->len, true);
spi_dma_reset(host->dma_ctx->rx_dma_chan);
spi_slave_hd_hal_rxdma(hal);
spi_dma_start(host->dma_ctx->rx_dma_chan, host->dma_ctx->dmadesc_rx);
@@ -561,23 +591,34 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg)
}
}
static inline SPI_SLAVE_ISR_ATTR void slave_hd_append_desc_walk(slave_hd_append_desc_t *desc_head, uint32_t desc_num, slave_hd_append_desc_t **p_desc, uint32_t steps)
{
steps %= desc_num;
*p_desc += steps;
if (*p_desc >= (desc_head + desc_num)) {
*p_desc -= desc_num;
}
}
static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_tx_isr(void *arg)
{
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg;
spi_slave_hd_callback_config_t *callback = &host->callback;
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_tx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
spi_slave_hd_trans_priv_t ret_priv_trans = {};
while (1) {
bool trans_finish = false;
trans_finish = spi_slave_hd_hal_get_tx_finished_trans(hal, (void **)&ret_priv_trans.trans, &ret_priv_trans.aligned_buffer);
if (!trans_finish) {
break;
}
while ((uint32_t)append->done_desc->desc != append->eof_desc) {
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->done_desc, 1);
int offset = append->done_desc - append->desc_root;
spi_slave_hd_trans_priv_t ret_priv_trans = {
.trans = append->done_desc->arg,
.aligned_buffer = gdma_link_get_buffer(host->dma_ctx->tx_link_handle, offset),
};
portENTER_CRITICAL_ISR(&host->int_spinlock);
hal->tx_used_desc_cnt--;
append->used_desc_cnt--;
portEXIT_CRITICAL_ISR(&host->int_spinlock);
bool ret_queue = true;
@@ -609,22 +650,23 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_rx_isr(void *arg)
{
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg;
spi_slave_hd_callback_config_t *callback = &host->callback;
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_rx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
spi_slave_hd_trans_priv_t ret_priv_trans = {};
size_t trans_len;
while (1) {
bool trans_finish = false;
trans_finish = spi_slave_hd_hal_get_rx_finished_trans(hal, (void **)&ret_priv_trans.trans, &ret_priv_trans.aligned_buffer, &trans_len);
if (!trans_finish) {
break;
}
while ((uint32_t)append->done_desc->desc != append->eof_desc) {
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->done_desc, 1);
int offset = append->done_desc - append->desc_root;
spi_slave_hd_trans_priv_t ret_priv_trans = {
.trans = append->done_desc->arg,
.aligned_buffer = gdma_link_get_buffer(host->dma_ctx->rx_link_handle, offset),
};
ret_priv_trans.trans->trans_len = gdma_link_get_length(host->dma_ctx->rx_link_handle, offset);
portENTER_CRITICAL_ISR(&host->int_spinlock);
hal->rx_used_desc_cnt--;
append->used_desc_cnt--;
portEXIT_CRITICAL_ISR(&host->int_spinlock);
ret_priv_trans.trans->trans_len = trans_len;
bool ret_queue = true;
spicommon_dma_rx_mb(host->host_id, ret_priv_trans.aligned_buffer);
@@ -658,10 +700,11 @@ static SPI_SLAVE_ISR_ATTR bool s_spi_slave_hd_append_gdma_isr(gdma_channel_handl
assert(event_data);
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)user_data;
host->hal.current_eof_addr = event_data->tx_eof_desc_addr;
if (host->dma_ctx->tx_dma_chan == dma_chan) {
host->append_tx_ctx.eof_desc = event_data->tx_eof_desc_addr;
spi_slave_hd_append_tx_isr(user_data);
} else {
host->append_rx_ctx.eof_desc = event_data->rx_eof_desc_addr;
spi_slave_hd_append_rx_isr(user_data);
}
return true;
@@ -677,11 +720,11 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_append_legacy_isr(void *arg)
portENTER_CRITICAL_ISR(&host->int_spinlock);
if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_RECV)) {
hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->rx_dma_chan);
host->append_rx_ctx.eof_desc = spi_dma_get_eof_desc(host->dma_ctx->rx_dma_chan);
rx_done = true;
}
if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_SEND)) {
hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan);
host->append_tx_ctx.eof_desc = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan);
tx_done = true;
}
portEXIT_CRITICAL_ISR(&host->int_spinlock);
@@ -743,40 +786,39 @@ static esp_err_t get_ret_queue_result(spi_host_device_t host_id, spi_slave_chan_
esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, size_t len, void *arg)
{
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_tx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
//Check if there are enough available DMA descriptors for software to use
int num_required = (len + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
int available_desc_num = hal->dma_desc_num - hal->tx_used_desc_cnt;
int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_tx_int : host->dma_ctx->dma_align_tx_ext;
// unsupported buffer which lead invalid buf_align should already checked by 'setup_priv_trans'
int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align));
int available_desc_num = dma_desc_num - append->used_desc_cnt;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
spicommon_dma_desc_setup_link(hal->tx_cur_desc->desc, data, len, false);
hal->tx_cur_desc->arg = arg;
int offset = append->free_desc - append->desc_root;
spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, false);
append->free_desc->arg = arg;
if (!hal->tx_used_desc_cnt) {
if (!append->used_desc_cnt) {
//start a link
hal->tx_dma_tail = hal->tx_cur_desc;
spi_dma_reset(host->dma_ctx->tx_dma_chan);
spi_slave_hd_hal_hw_prepare_tx(hal);
spi_dma_start(host->dma_ctx->tx_dma_chan, hal->tx_cur_desc->desc);
spi_dma_start(host->dma_ctx->tx_dma_chan, append->free_desc->desc);
} else {
//there is already a consecutive link
ADDR_DMA_2_CPU(hal->tx_dma_tail->desc)->next = hal->tx_cur_desc->desc;
hal->tx_dma_tail = hal->tx_cur_desc;
gdma_link_list_handle_t link_handle = host->dma_ctx->tx_link_handle;
gdma_link_concat(link_handle, offset - 1, link_handle, offset);
spi_dma_append(host->dma_ctx->tx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
portENTER_CRITICAL(&host->int_spinlock);
hal->tx_used_desc_cnt += num_required;
append->used_desc_cnt += num_required;
portEXIT_CRITICAL(&host->int_spinlock);
for (int i = 0; i < num_required; i++) {
hal->tx_cur_desc++;
if (hal->tx_cur_desc == hal->dmadesc_tx + hal->dma_desc_num) {
hal->tx_cur_desc = hal->dmadesc_tx;
}
}
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->free_desc, num_required);
return ESP_OK;
}
@@ -784,40 +826,38 @@ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data,
esp_err_t s_spi_slave_hd_append_rxdma(spi_slave_hd_slot_t *host, uint8_t *data, size_t len, void *arg)
{
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_rx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
//Check if there are enough available dma descriptors for software to use
int num_required = (len + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
int available_desc_num = hal->dma_desc_num - hal->rx_used_desc_cnt;
int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_rx_int : host->dma_ctx->dma_align_rx_ext;
int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align));
int available_desc_num = dma_desc_num - append->used_desc_cnt;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
spicommon_dma_desc_setup_link(hal->rx_cur_desc->desc, data, len, true);
hal->rx_cur_desc->arg = arg;
int offset = append->free_desc - append->desc_root;
spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, true);
append->free_desc->arg = arg;
if (!hal->rx_used_desc_cnt) {
if (!append->used_desc_cnt) {
//start a link
hal->rx_dma_tail = hal->rx_cur_desc;
spi_dma_reset(host->dma_ctx->rx_dma_chan);
spi_slave_hd_hal_hw_prepare_rx(hal);
spi_dma_start(host->dma_ctx->rx_dma_chan, hal->rx_cur_desc->desc);
spi_dma_start(host->dma_ctx->rx_dma_chan, append->free_desc->desc);
} else {
//there is already a consecutive link
ADDR_DMA_2_CPU(hal->rx_dma_tail->desc)->next = hal->rx_cur_desc->desc;
hal->rx_dma_tail = hal->rx_cur_desc;
gdma_link_list_handle_t link_handle = host->dma_ctx->rx_link_handle;
gdma_link_concat(link_handle, offset - 1, link_handle, offset);
spi_dma_append(host->dma_ctx->rx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
portENTER_CRITICAL(&host->int_spinlock);
hal->rx_used_desc_cnt += num_required;
append->used_desc_cnt += num_required;
portEXIT_CRITICAL(&host->int_spinlock);
for (int i = 0; i < num_required; i++) {
hal->rx_cur_desc++;
if (hal->rx_cur_desc == hal->dmadesc_rx + hal->dma_desc_num) {
hal->rx_cur_desc = hal->dmadesc_rx;
}
}
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->free_desc, num_required);
return ESP_OK;
}

View File

@@ -10,7 +10,7 @@
#if CONFIG_IDF_TARGET_ESP32
#define IDF_TARGET_MAX_SPI_CLK_FREQ 16*1000*1000
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 15
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 20
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15
#if !CONFIG_FREERTOS_SMP // IDF-5826
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 34 // TODO: IDF-5180
@@ -29,27 +29,27 @@
#elif CONFIG_IDF_TARGET_ESP32S3
#define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 17
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 20
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 32
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 34
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 30
#elif CONFIG_IDF_TARGET_ESP32C2
#define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 23
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 28
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 18
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 47
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 52
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 42
#elif CONFIG_IDF_TARGET_ESP32C3
#define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000
#if !CONFIG_FREERTOS_SMP // IDF-5826
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 17
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 21
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 35
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 37
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 30
#else
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 17
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 21
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 17
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 60
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 60
@@ -57,16 +57,16 @@
#elif CONFIG_IDF_TARGET_ESP32C6
#define IDF_TARGET_MAX_SPI_CLK_FREQ 26666*1000
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 37 //TODO: IDF-9551, check perform
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 19
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 38 //TODO: IDF-9551, check perform
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 22
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 32
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 15
#elif CONFIG_IDF_TARGET_ESP32H2
#define IDF_TARGET_MAX_SPI_CLK_FREQ 24*1000*1000
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 32
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 35
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 25
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 61
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 64
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 54
#elif CONFIG_IDF_TARGET_ESP32P4

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,7 +15,6 @@
#include <string.h>
#include <stdlib.h> //for abs()
#include "esp_types.h"
#include "esp32/rom/lldesc.h"
#include "soc/spi_reg.h"
#include "soc/spi_struct.h"
#include "soc/dport_reg.h"
@@ -1159,7 +1158,7 @@ static inline void spi_ll_dma_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr)
static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, void *addr)
{
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
dma_in->dma_in_link.start = 1;
@@ -1224,7 +1223,7 @@ static inline void spi_ll_dma_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr)
static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, void *addr)
{
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;
dma_out->dma_out_link.start = 1;

View File

@@ -21,7 +21,6 @@
#include "soc/spi_struct.h"
#include "soc/spi_reg.h"
#include "soc/dport_reg.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/assert.h"
#include "hal/misc.h"
@@ -1331,7 +1330,7 @@ static inline void spi_ll_dma_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr)
static inline void spi_ll_dma_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, void *addr)
{
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
dma_in->dma_in_link.start = 1;
@@ -1423,7 +1422,7 @@ static inline void spi_ll_dma_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr)
static inline void spi_ll_dma_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, void *addr)
{
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;
dma_out->dma_out_link.start = 1;

View File

@@ -47,8 +47,6 @@
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/spi_types.h"
#include "hal/dma_types.h"
#include "hal/gdma_types.h"
#if SOC_GPSPI_SUPPORTED
#include "hal/spi_ll.h"
#endif
@@ -59,26 +57,6 @@ extern "C" {
#if SOC_GPSPI_SUPPORTED
//NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol
#if !defined(SOC_GDMA_TRIG_PERIPH_SPI2_BUS)
typedef dma_descriptor_align4_t spi_dma_desc_t;
#else
#if defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
typedef dma_descriptor_align8_t spi_dma_desc_t;
#elif defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB)
typedef dma_descriptor_align4_t spi_dma_desc_t;
#endif
#endif
/**
* @brief Type of dma descriptor with appended members
* this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users.
*/
typedef struct {
spi_dma_desc_t *desc; ///< DMA descriptor
void *arg; ///< This points to the transaction descriptor user passed in
} spi_slave_hd_hal_desc_append_t;
/// Configuration of the HAL
typedef struct {
uint32_t host_id; ///< Host ID of the spi peripheral
@@ -99,24 +77,8 @@ typedef struct {
/// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`.
typedef struct {
/* These two need to be malloced by the driver first */
spi_slave_hd_hal_desc_append_t *dmadesc_tx; ///< Head of the TX DMA descriptors.
spi_slave_hd_hal_desc_append_t *dmadesc_rx; ///< Head of the RX DMA descriptors.
/* address of the hardware */
spi_dev_t *dev; ///< Beginning address of the peripheral registers.
bool dma_enabled; ///< DMA enabled or not
bool append_mode; ///< True for DMA append mode, false for segment mode
uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``.
uint32_t current_eof_addr;
spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *tx_dma_head; ///< Head of the linked TX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware
uint32_t tx_used_desc_cnt; ///< Number of the TX descriptors that have been setup
spi_slave_hd_hal_desc_append_t *rx_cur_desc; ///< Current RX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *rx_dma_head; ///< Head of the linked RX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *rx_dma_tail; ///< Tail of the linked RX DMA descriptors which are not used by hardware
uint32_t rx_used_desc_cnt; ///< Number of the RX descriptors that have been setup
/* Internal status used by the HAL implementation, initialized as 0. */
uint32_t intr_not_triggered;
@@ -193,14 +155,6 @@ void spi_slave_hd_hal_enable_event_intr(spi_slave_hd_hal_context_t* hal, spi_eve
*/
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal);
/**
* @brief Get the length of total received data
*
* @param hal Context of the HAL layer
* @return The received length
*/
int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal);
/**
* @brief Prepare hardware for a new dma rx trans
*
@@ -266,64 +220,6 @@ int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal);
*/
int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal);
////////////////////////////////////////////////////////////////////////////////
// Append Mode
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Return the finished TX transaction
*
* @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer.
* This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour,
* this API will go wrong.
*
* @param hal Context of the HAL layer
* @param out_trans Pointer to the caller-defined transaction
* @param real_buff_addr Actually data buffer head the HW used
* @return 1: Transaction is finished; 0: Transaction is not finished
*/
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr);
/**
* @brief Return the finished RX transaction
*
* @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer.
* This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour,
* this API will go wrong.
*
* @param hal Context of the HAL layer
* @param out_trans Pointer to the caller-defined transaction
* @param real_buff_addr Actually data buffer head the HW used
* @param out_len Actual number of bytes of received data
* @return 1: Transaction is finished; 0: Transaction is not finished
*/
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr, size_t *out_len);
/**
* @brief Load the TX DMA descriptors without stopping the DMA
*
* @param hal Context of the HAL layer
* @param data Buffer of the transaction data
* @param len Length of the data
* @param arg Pointer used by the caller to indicate the transaction. Will be returned by ``spi_slave_hd_hal_get_tx_finished_trans`` when transaction is finished
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: Function called in invalid state.
*/
esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg);
/**
* @brief Load the RX DMA descriptors without stopping the DMA
*
* @param hal Context of the HAL layer
* @param data Buffer of the transaction data
* @param len Length of the data
* @param arg Pointer used by the caller to indicate the transaction. Will be returned by ``spi_slave_hd_hal_get_rx_finished_trans`` when transaction is finished
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: Function called in invalid state.
*/
esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg);
#endif //#if SOC_GPSPI_SUPPORTED
#ifdef __cplusplus

View File

@@ -10,9 +10,7 @@
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "soc/soc.h" //for SOC_NON_CACHEABLE_OFFSET_SRAM
#include "soc/spi_periph.h"
#include "hal/spi_slave_hd_hal.h"
#include "hal/assert.h"
@@ -21,12 +19,6 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
{
spi_dev_t *hw = spi_periph_signal[hal_config->host_id].hw;
hal->dev = hw;
hal->dma_enabled = hal_config->dma_enabled;
hal->append_mode = hal_config->append_mode;
hal->tx_cur_desc = hal->dmadesc_tx;
hal->rx_cur_desc = hal->dmadesc_rx;
hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num - 1;
hal->rx_dma_head = hal->dmadesc_rx + hal->dma_desc_num - 1;
spi_ll_slave_hd_init(hw);
spi_ll_set_addr_bitlen(hw, hal_config->address_bits);
@@ -70,37 +62,6 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
spi_ll_slave_set_seg_mode(hal->dev, true);
}
#if SOC_NON_CACHEABLE_OFFSET_SRAM
#include "hal/cache_ll.h"
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))CACHE_LL_L2MEM_NON_CACHE_ADDR(addr))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))CACHE_LL_L2MEM_CACHE_ADDR(addr))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
static int s_desc_get_received_len_addr(spi_dma_desc_t* head, spi_dma_desc_t** out_next, void **out_buff_head)
{
spi_dma_desc_t* desc_cpu = ADDR_DMA_2_CPU(head);
int len = 0;
if (out_buff_head) {
*out_buff_head = desc_cpu->buffer;
}
while (head) {
len += desc_cpu->dw0.length;
bool eof = desc_cpu->dw0.suc_eof;
desc_cpu = ADDR_DMA_2_CPU(desc_cpu->next);
head = head->next;
if (eof) {
break;
}
}
if (out_next) {
*out_next = head;
}
return len;
}
void spi_slave_hd_hal_hw_prepare_rx(spi_slave_hd_hal_context_t *hal)
{
spi_ll_dma_rx_fifo_reset(hal->dev);
@@ -234,41 +195,3 @@ int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal)
//this is by -byte
return spi_ll_slave_get_rx_byte_len(hal->dev);
}
int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal)
{
spi_dma_desc_t *desc = hal->dmadesc_rx->desc;
return s_desc_get_received_len_addr(desc, NULL, NULL);
}
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr)
{
if ((uint32_t)hal->tx_dma_head->desc == hal->current_eof_addr) {
return false;
}
//find used paired desc-trans by desc addr
hal->tx_dma_head++;
if (hal->tx_dma_head >= hal->dmadesc_tx + hal->dma_desc_num) {
hal->tx_dma_head = hal->dmadesc_tx;
}
*out_trans = hal->tx_dma_head->arg;
s_desc_get_received_len_addr(hal->tx_dma_head->desc, NULL, real_buff_addr);
return true;
}
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr, size_t *out_len)
{
if ((uint32_t)hal->rx_dma_head->desc == hal->current_eof_addr) {
return false;
}
//find used paired desc-trans by desc addr
hal->rx_dma_head++;
if (hal->rx_dma_head >= hal->dmadesc_rx + hal->dma_desc_num) {
hal->rx_dma_head = hal->dmadesc_rx;
}
*out_trans = hal->rx_dma_head->arg;
*out_len = s_desc_get_received_len_addr(hal->rx_dma_head->desc, NULL, real_buff_addr);
return true;
}