Merge branch 'refactor/spi_slave_hal_iram_dma_replace' into 'master'

refactor(spi_slave): spi slave and slave HD hal iram dma_ll replace

Closes IDF-6152 and IDF-9656

See merge request espressif/esp-idf!27877
This commit is contained in:
Wan Lei 2024-04-30 20:16:18 +08:00
commit cceec04195
31 changed files with 483 additions and 512 deletions

View File

@ -55,6 +55,7 @@ menu "ESP-Driver:SPI Configurations"
default y default y
select PERIPH_CTRL_FUNC_IN_IRAM select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_SLAVE_FUNC_IN_IRAM select HAL_SPI_SLAVE_FUNC_IN_IRAM
select GDMA_CTRL_FUNC_IN_IRAM if SOC_GDMA_SUPPORTED
help help
Place the SPI slave ISR in to IRAM to avoid possible cache miss. Place the SPI slave ISR in to IRAM to avoid possible cache miss.

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -167,6 +167,25 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
*/ */
esp_err_t spi_bus_free(spi_host_device_t host_id); esp_err_t spi_bus_free(spi_host_device_t host_id);
/**
* @brief Helper function for malloc DMA capable memory for SPI driver
*
* @note This API will take care of the cache and hardware alignment internally.
* To free/release memory allocated by this helper function, simply calling `free()`
*
* @param[in] size Size in bytes, the amount of memory to allocate
* @param[out] out_ptr Pointer to the memory if allocated successfully
* @param[in] extra_heap_caps Extra heap caps based on MALLOC_CAP_DMA
* @param[out] actual_size Optional, Actual size for allocation in bytes, when the size you specified doesn't meet the internal alignment requirements,
* This value might be bigger than the size you specified. Set NULL if don't care this value.
*
* @return
* - ESP_ERR_INVALID_ARG Invalid argument
* - ESP_ERR_NO_MEM No enough memory for allocation
* - ESP_OK on success
*/
esp_err_t spi_bus_dma_memory_malloc(size_t size, void **out_ptr, uint32_t extra_heap_caps, size_t *actual_size);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -25,18 +25,6 @@ extern "C"
{ {
#endif #endif
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
#define SPI_MASTER_ISR_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ISR_ATTR
#endif
#ifdef CONFIG_SPI_MASTER_IN_IRAM
#define SPI_MASTER_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ATTR
#endif
//NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol //NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol
#if SOC_GPSPI_SUPPORTED && defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) #if SOC_GPSPI_SUPPORTED && defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
#define DMA_DESC_MEM_ALIGN_SIZE 8 #define DMA_DESC_MEM_ALIGN_SIZE 8
@ -46,6 +34,15 @@ typedef dma_descriptor_align8_t spi_dma_desc_t;
typedef dma_descriptor_align4_t spi_dma_desc_t; typedef dma_descriptor_align4_t spi_dma_desc_t;
#endif #endif
#if SOC_NON_CACHEABLE_OFFSET
#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
/// Attributes of an SPI bus /// Attributes of an SPI bus
typedef struct { typedef struct {
spi_bus_config_t bus_cfg; ///< Config used to initialize the bus spi_bus_config_t bus_cfg; ///< Config used to initialize the bus

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -36,6 +36,13 @@ typedef struct {
*/ */
void spi_dma_enable_burst(spi_dma_chan_handle_t chan_handle, bool data_burst, bool desc_burst); void spi_dma_enable_burst(spi_dma_chan_handle_t chan_handle, bool data_burst, bool desc_burst);
/**
* Re-trigger a HW pre-load to pick up appended linked descriptor
*
* @param chan_handle Context of the spi_dma channel.
*/
void spi_dma_append(spi_dma_chan_handle_t chan_handle);
/** /**
* Reset dma channel for spi_dma * Reset dma channel for spi_dma
* *
@ -51,6 +58,13 @@ void spi_dma_reset(spi_dma_chan_handle_t chan_handle);
*/ */
void spi_dma_start(spi_dma_chan_handle_t chan_handle, void *addr); void spi_dma_start(spi_dma_chan_handle_t chan_handle, void *addr);
/**
* Get EOF descriptor for a dma channel
*
* @param chan_handle Context of the spi_dma channel.
*/
uint32_t spi_dma_get_eof_desc(spi_dma_chan_handle_t chan_handle);
#endif //!SOC_GDMA_SUPPORTED #endif //!SOC_GDMA_SUPPORTED
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -5,3 +5,6 @@ entries:
if SOC_GDMA_SUPPORTED != y && (SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y): if SOC_GDMA_SUPPORTED != y && (SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y):
spi_dma: spi_dma_reset (noflash) spi_dma: spi_dma_reset (noflash)
spi_dma: spi_dma_start (noflash) spi_dma: spi_dma_start (noflash)
if SOC_SPI_SUPPORT_SLAVE_HD_VER2 = y:
spi_dma: spi_dma_get_eof_desc (noflash)

View File

@ -14,7 +14,6 @@
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "soc/spi_periph.h" #include "soc/spi_periph.h"
#include "soc/ext_mem_defs.h"
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_private/gpio.h" #include "esp_private/gpio.h"
@ -22,14 +21,12 @@
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_common_internal.h"
#include "esp_private/spi_share_hw_ctrl.h" #include "esp_private/spi_share_hw_ctrl.h"
#include "esp_private/esp_cache_private.h" #include "esp_private/esp_cache_private.h"
#include "esp_dma_utils.h"
#include "hal/spi_hal.h" #include "hal/spi_hal.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
#include "soc/dport_reg.h" #include "soc/dport_reg.h"
#endif #endif
#if SOC_GDMA_SUPPORTED
#include "esp_private/gdma.h"
#endif
static const char *SPI_TAG = "spi"; static const char *SPI_TAG = "spi";
@ -289,8 +286,12 @@ esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *
dma_desc_ct = 1; //default to 4k when max is not given dma_desc_ct = 1; //default to 4k when max is not given
} }
dma_ctx->dmadesc_tx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA); esp_dma_mem_info_t dma_mem_info = {
dma_ctx->dmadesc_rx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA); .dma_alignment_bytes = DMA_DESC_MEM_ALIGN_SIZE,
};
esp_dma_capable_malloc(sizeof(spi_dma_desc_t) * dma_desc_ct, &dma_mem_info, (void*)&dma_ctx->dmadesc_tx, NULL);
esp_dma_capable_malloc(sizeof(spi_dma_desc_t) * dma_desc_ct, &dma_mem_info, (void*)&dma_ctx->dmadesc_rx, NULL);
if (dma_ctx->dmadesc_tx == NULL || dma_ctx->dmadesc_rx == NULL) { if (dma_ctx->dmadesc_tx == NULL || dma_ctx->dmadesc_rx == NULL) {
if (dma_ctx->dmadesc_tx) { if (dma_ctx->dmadesc_tx) {
free(dma_ctx->dmadesc_tx); free(dma_ctx->dmadesc_tx);
@ -307,15 +308,7 @@ esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *
return ESP_OK; return ESP_OK;
} }
#if SOC_NON_CACHEABLE_OFFSET void IRAM_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
void SPI_MASTER_ISR_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{ {
dmadesc = ADDR_DMA_2_CPU(dmadesc); dmadesc = ADDR_DMA_2_CPU(dmadesc);
int n = 0; int n = 0;
@ -889,6 +882,15 @@ cleanup:
return err; return err;
} }
esp_err_t spi_bus_dma_memory_malloc(size_t size, void **out_ptr, uint32_t extra_heap_caps, size_t *actual_size)
{
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = extra_heap_caps,
.dma_alignment_bytes = DMA_DESC_MEM_ALIGN_SIZE,
};
return esp_dma_capable_malloc(size, &dma_mem_info, out_ptr, actual_size);
}
const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id) const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id)
{ {
if (bus_ctx[host_id] == NULL) { if (bus_ctx[host_id] == NULL) {

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -21,8 +21,30 @@ void spi_dma_enable_burst(spi_dma_chan_handle_t chan_handle, bool data_burst, bo
} }
} }
#if SOC_SPI_SUPPORT_SLAVE_HD_VER2
void spi_dma_append(spi_dma_chan_handle_t chan_handle)
{
spi_dma_dev_t *spi_dma = SPI_LL_GET_HW(chan_handle.host_id);
if (chan_handle.dir == DMA_CHANNEL_DIRECTION_TX) {
spi_dma_ll_tx_restart(spi_dma, chan_handle.chan_id);
} else {
spi_dma_ll_rx_restart(spi_dma, chan_handle.chan_id);
}
}
/************************************* IRAM CONTEXT **************************************/ /************************************* IRAM CONTEXT **************************************/
uint32_t spi_dma_get_eof_desc(spi_dma_chan_handle_t chan_handle)
{
spi_dma_dev_t *spi_dma = SPI_LL_GET_HW(chan_handle.host_id);
return (chan_handle.dir == DMA_CHANNEL_DIRECTION_TX) ?
spi_dma_ll_get_out_eof_desc_addr(spi_dma, chan_handle.chan_id) :
spi_dma_ll_get_in_suc_eof_desc_addr(spi_dma, chan_handle.chan_id);
}
#endif //SOC_SPI_SUPPORT_SLAVE_HD_VER2
void spi_dma_reset(spi_dma_chan_handle_t chan_handle) void spi_dma_reset(spi_dma_chan_handle_t chan_handle)
{ {
spi_dma_dev_t *spi_dma = SPI_LL_GET_HW(chan_handle.host_id); spi_dma_dev_t *spi_dma = SPI_LL_GET_HW(chan_handle.host_id);

View File

@ -133,6 +133,27 @@ We have two bits to control the interrupt:
#include "esp_cache.h" #include "esp_cache.h"
#endif #endif
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
#define SPI_MASTER_ISR_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ISR_ATTR
#endif
#ifdef CONFIG_SPI_MASTER_IN_IRAM
#define SPI_MASTER_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ATTR
#endif
#if SOC_PERIPH_CLK_CTRL_SHARED
#define SPI_MASTER_PERI_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define SPI_MASTER_PERI_CLOCK_ATOMIC()
#endif
static const char *SPI_TAG = "spi_master";
#define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE_ISR(a, ret_val, SPI_TAG, str)
typedef struct spi_device_t spi_device_t; typedef struct spi_device_t spi_device_t;
/// struct to hold private transaction data (like tx and rx buffer for DMA). /// struct to hold private transaction data (like tx and rx buffer for DMA).
@ -210,15 +231,6 @@ struct spi_device_t {
static spi_host_t* bus_driver_ctx[SOC_SPI_PERIPH_NUM] = {}; static spi_host_t* bus_driver_ctx[SOC_SPI_PERIPH_NUM] = {};
static const char *SPI_TAG = "spi_master";
#define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE_ISR(a, ret_val, SPI_TAG, str)
#if SOC_PERIPH_CLK_CTRL_SHARED
#define SPI_MASTER_PERI_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define SPI_MASTER_PERI_CLOCK_ATOMIC()
#endif
static void spi_intr(void *arg); static void spi_intr(void *arg);
static void spi_bus_intr_enable(void *host); static void spi_bus_intr_enable(void *host);
static void spi_bus_intr_disable(void *host); static void spi_bus_intr_disable(void *host);

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -181,14 +181,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
hal->dmadesc_tx = spihost[host]->dma_ctx->dmadesc_tx; hal->dmadesc_tx = spihost[host]->dma_ctx->dmadesc_tx;
hal->dmadesc_rx = spihost[host]->dma_ctx->dmadesc_rx; hal->dmadesc_rx = spihost[host]->dma_ctx->dmadesc_rx;
hal->dmadesc_n = spihost[host]->dma_ctx->dma_desc_num; hal->dmadesc_n = spihost[host]->dma_ctx->dma_desc_num;
#if SOC_GDMA_SUPPORTED
//temporary used for gdma_ll alias in hal layer
gdma_get_channel_id(spihost[host]->dma_ctx->tx_dma_chan, (int *)&hal->tx_dma_chan);
gdma_get_channel_id(spihost[host]->dma_ctx->rx_dma_chan, (int *)&hal->rx_dma_chan);
#else
hal->tx_dma_chan = spihost[host]->dma_ctx->tx_dma_chan.chan_id;
hal->rx_dma_chan = spihost[host]->dma_ctx->rx_dma_chan.chan_id;
#endif
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t alignment; size_t alignment;
@ -266,8 +258,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address //assign the SPI, RX DMA and TX DMA peripheral registers beginning address
spi_slave_hal_config_t hal_config = { spi_slave_hal_config_t hal_config = {
.host_id = host, .host_id = host,
.dma_in = SPI_LL_GET_HW(host),
.dma_out = SPI_LL_GET_HW(host)
}; };
spi_slave_hal_init(hal, &hal_config); spi_slave_hal_init(hal, &hal_config);
@ -279,31 +269,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
return ESP_OK; return ESP_OK;
cleanup: cleanup:
if (spihost[host]) { spi_slave_free(host);
if (spihost[host]->trans_queue) {
vQueueDelete(spihost[host]->trans_queue);
}
if (spihost[host]->ret_queue) {
vQueueDelete(spihost[host]->ret_queue);
}
#ifdef CONFIG_PM_ENABLE
if (spihost[host]->pm_lock) {
esp_pm_lock_release(spihost[host]->pm_lock);
esp_pm_lock_delete(spihost[host]->pm_lock);
}
#endif
}
spi_slave_hal_deinit(&spihost[host]->hal);
if (spihost[host]->dma_enabled) {
free(spihost[host]->dma_ctx->dmadesc_tx);
free(spihost[host]->dma_ctx->dmadesc_rx);
spicommon_dma_chan_free(spihost[host]->dma_ctx);
}
free(spihost[host]);
spihost[host] = NULL;
spicommon_periph_free(host);
return ret; return ret;
} }
@ -325,8 +291,10 @@ esp_err_t spi_slave_free(spi_host_device_t host)
spicommon_bus_free_io_cfg(&spihost[host]->bus_config); spicommon_bus_free_io_cfg(&spihost[host]->bus_config);
esp_intr_free(spihost[host]->intr); esp_intr_free(spihost[host]->intr);
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
if (spihost[host]->pm_lock) {
esp_pm_lock_release(spihost[host]->pm_lock); esp_pm_lock_release(spihost[host]->pm_lock);
esp_pm_lock_delete(spihost[host]->pm_lock); esp_pm_lock_delete(spihost[host]->pm_lock);
}
#endif //CONFIG_PM_ENABLE #endif //CONFIG_PM_ENABLE
free(spihost[host]); free(spihost[host]);
spihost[host] = NULL; spihost[host] = NULL;
@ -553,6 +521,49 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_tr
return ESP_OK; return ESP_OK;
} }
#if SOC_GDMA_SUPPORTED // AHB_DMA_V1 and AXI_DMA
// dma is provided by gdma driver on these targets
#define spi_dma_reset gdma_reset
#define spi_dma_start(chan, addr) gdma_start(chan, (intptr_t)(addr))
#endif
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->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->bitlen + 7) / 8, false);
spi_dma_reset(dma_ctx->tx_dma_chan);
spi_slave_hal_hw_prepare_tx(hal->hw);
spi_dma_start(dma_ctx->tx_dma_chan, dma_ctx->dmadesc_tx);
}
}
static void SPI_SLAVE_ISR_ATTR s_spi_slave_prepare_data(spi_slave_t *host)
{
spi_slave_hal_context_t *hal = &host->hal;
if (host->dma_enabled) {
s_spi_slave_dma_prepare_data(host->dma_ctx, &host->hal);
} else {
//No DMA. Copy data to transmit buffers.
spi_slave_hal_push_tx_buffer(hal);
spi_slave_hal_hw_fifo_reset(hal, true, false);
}
spi_slave_hal_set_trans_bitlen(hal);
#ifdef CONFIG_IDF_TARGET_ESP32
//SPI Slave mode on ESP32 requires MOSI/MISO enable
spi_slave_hal_enable_data_line(hal);
#endif
}
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
static void SPI_SLAVE_ISR_ATTR spi_slave_restart_after_dmareset(void *arg) static void SPI_SLAVE_ISR_ATTR spi_slave_restart_after_dmareset(void *arg)
{ {
@ -654,7 +665,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
} }
#endif //#if CONFIG_IDF_TARGET_ESP32 #endif //#if CONFIG_IDF_TARGET_ESP32
spi_slave_hal_prepare_data(hal); spi_slave_hal_hw_reset(hal);
s_spi_slave_prepare_data(host);
//The slave rx dma get disturbed by unexpected transaction. Only connect the CS when slave is ready. //The slave rx dma get disturbed by unexpected transaction. Only connect the CS when slave is ready.
if (use_dma) { if (use_dma) {

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -65,11 +65,18 @@ static spi_slave_hd_slot_t *spihost[SOC_SPI_PERIPH_NUM];
static const char TAG[] = "slave_hd"; static const char TAG[] = "slave_hd";
#if SOC_GDMA_SUPPORTED #if SOC_GDMA_SUPPORTED
static bool spi_gdma_tx_channel_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); // for which dma is provided by gdma driver
#define spi_dma_reset gdma_reset
#define spi_dma_start(chan, addr) gdma_start(chan, (intptr_t)(addr))
#define spi_dma_append gdma_append
static bool s_spi_slave_hd_append_gdma_isr(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
#else
// by spi_dma, mainly esp32s2
static void s_spi_slave_hd_append_legacy_isr(void *arg);
#endif // SOC_GDMA_SUPPORTED #endif // SOC_GDMA_SUPPORTED
static void spi_slave_hd_intr_append(void *arg); static void s_spi_slave_hd_segment_isr(void *arg);
static void spi_slave_hd_intr_segment(void *arg);
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config, const spi_slave_hd_slot_config_t *config) esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config, const spi_slave_hd_slot_config_t *config)
{ {
@ -102,6 +109,16 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto cleanup; goto cleanup;
} }
#if SOC_GDMA_SUPPORTED
gdma_strategy_config_t dma_strategy = {
.auto_update_desc = true,
.eof_till_data_popped = true,
};
gdma_apply_strategy(host->dma_ctx->tx_dma_chan, &dma_strategy);
#else
spi_dma_ll_enable_out_auto_wrback(SPI_LL_GET_HW(host->dma_ctx->tx_dma_chan.host_id), host->dma_ctx->tx_dma_chan.chan_id, 1);
spi_dma_ll_set_out_eof_generation(SPI_LL_GET_HW(host->dma_ctx->tx_dma_chan.host_id), host->dma_ctx->tx_dma_chan.chan_id, 1);
#endif
ret = spicommon_dma_desc_alloc(host->dma_ctx, bus_config->max_transfer_sz, &host->max_transfer_sz); ret = spicommon_dma_desc_alloc(host->dma_ctx, bus_config->max_transfer_sz, &host->max_transfer_sz);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto cleanup; goto cleanup;
@ -141,8 +158,6 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
spi_slave_hd_hal_config_t hal_config = { spi_slave_hd_hal_config_t hal_config = {
.host_id = host_id, .host_id = host_id,
.dma_in = SPI_LL_GET_HW(host_id),
.dma_out = SPI_LL_GET_HW(host_id),
.dma_enabled = host->dma_enabled, .dma_enabled = host->dma_enabled,
.append_mode = append_mode, .append_mode = append_mode,
.mode = config->mode, .mode = config->mode,
@ -150,15 +165,6 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
.rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST), .rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST),
}; };
#if SOC_GDMA_SUPPORTED
//temporary used for gdma_ll alias in hal layer
gdma_get_channel_id(host->dma_ctx->tx_dma_chan, (int *)&hal_config.tx_dma_chan);
gdma_get_channel_id(host->dma_ctx->rx_dma_chan, (int *)&hal_config.rx_dma_chan);
#else
hal_config.tx_dma_chan = host->dma_ctx->tx_dma_chan.chan_id;
hal_config.rx_dma_chan = host->dma_ctx->rx_dma_chan.chan_id;
#endif
//Init the hal according to the hal_config set above //Init the hal according to the hal_config set above
spi_slave_hd_hal_init(&host->hal, &hal_config); spi_slave_hd_hal_init(&host->hal, &hal_config);
@ -192,34 +198,28 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
//Alloc intr //Alloc intr
if (!host->append_mode) { if (!host->append_mode) {
//Seg mode ret = esp_intr_alloc(spicommon_irqsource_for_host(host_id), 0, s_spi_slave_hd_segment_isr,
ret = esp_intr_alloc(spicommon_irqsource_for_host(host_id), 0, spi_slave_hd_intr_segment,
(void *)host, &host->intr); (void *)host, &host->intr);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto cleanup; goto cleanup;
} }
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), 0, spi_slave_hd_intr_segment, ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), 0, s_spi_slave_hd_segment_isr,
(void *)host, &host->intr_dma); (void *)host, &host->intr_dma);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto cleanup; goto cleanup;
} }
} else { } else {
//Append mode //Append mode
//On ESP32S2, `cmd7` and `cmd8` interrupts registered as spi rx & tx interrupt are from SPI DMA interrupt source.
//although the `cmd7` and `cmd8` interrupt on spi are registered independently here
ret = esp_intr_alloc(spicommon_irqsource_for_host(host_id), 0, spi_slave_hd_intr_append,
(void *)host, &host->intr);
if (ret != ESP_OK) {
goto cleanup;
}
#if SOC_GDMA_SUPPORTED #if SOC_GDMA_SUPPORTED
// config gmda and ISR callback for gdma supported chip // config gmda event callback for gdma supported chip
gdma_tx_event_callbacks_t tx_cbs = { gdma_rx_event_callbacks_t txrx_cbs = {
.on_trans_eof = spi_gdma_tx_channel_callback .on_recv_eof = s_spi_slave_hd_append_gdma_isr,
}; };
gdma_register_tx_event_callbacks(host->dma_ctx->tx_dma_chan, &tx_cbs, host); gdma_register_tx_event_callbacks(host->dma_ctx->tx_dma_chan, (gdma_tx_event_callbacks_t *)&txrx_cbs, host);
gdma_register_rx_event_callbacks(host->dma_ctx->rx_dma_chan, &txrx_cbs, host);
#else #else
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), 0, spi_slave_hd_intr_append, //On ESP32S2, `cmd7` and `cmd8` are designed as all `spi_dma` events, so use `dma_src` only
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), 0, s_spi_slave_hd_append_legacy_isr,
(void *)host, &host->intr_dma); (void *)host, &host->intr_dma);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto cleanup; goto cleanup;
@ -321,8 +321,7 @@ static inline IRAM_ATTR BaseType_t intr_check_clear_callback(spi_slave_hd_slot_t
} }
return cb_awoken; return cb_awoken;
} }
static IRAM_ATTR void s_spi_slave_hd_segment_isr(void *arg)
static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
{ {
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t *)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_callback_config_t *callback = &host->callback;
@ -396,7 +395,10 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
if (!host->tx_curr_trans.trans) { if (!host->tx_curr_trans.trans) {
ret = xQueueReceiveFromISR(host->tx_trans_queue, &host->tx_curr_trans, &awoken); ret = xQueueReceiveFromISR(host->tx_trans_queue, &host->tx_curr_trans, &awoken);
if (ret == pdTRUE) { if (ret == pdTRUE) {
spi_slave_hd_hal_txdma(hal, host->tx_curr_trans.aligned_buffer, host->tx_curr_trans.trans->len); spicommon_dma_desc_setup_link(hal->dmadesc_tx->desc, 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);
tx_sent = true; tx_sent = true;
if (callback->cb_send_dma_ready) { if (callback->cb_send_dma_ready) {
spi_slave_hd_event_t ev = { spi_slave_hd_event_t ev = {
@ -412,7 +414,10 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
if (!host->rx_curr_trans.trans) { if (!host->rx_curr_trans.trans) {
ret = xQueueReceiveFromISR(host->rx_trans_queue, &host->rx_curr_trans, &awoken); ret = xQueueReceiveFromISR(host->rx_trans_queue, &host->rx_curr_trans, &awoken);
if (ret == pdTRUE) { if (ret == pdTRUE) {
spi_slave_hd_hal_rxdma(hal, host->rx_curr_trans.aligned_buffer, host->rx_curr_trans.trans->len); spicommon_dma_desc_setup_link(hal->dmadesc_rx->desc, 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);
rx_sent = true; rx_sent = true;
if (callback->cb_recv_dma_ready) { if (callback->cb_recv_dma_ready) {
spi_slave_hd_event_t ev = { spi_slave_hd_event_t ev = {
@ -528,31 +533,35 @@ static IRAM_ATTR void spi_slave_hd_append_rx_isr(void *arg)
} }
#if SOC_GDMA_SUPPORTED #if SOC_GDMA_SUPPORTED
// 'spi_gdma_tx_channel_callback' used as spi tx interrupt of append mode on gdma supported target static IRAM_ATTR bool s_spi_slave_hd_append_gdma_isr(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
static IRAM_ATTR bool spi_gdma_tx_channel_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{ {
assert(event_data); 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) {
spi_slave_hd_append_tx_isr(user_data); spi_slave_hd_append_tx_isr(user_data);
} else {
spi_slave_hd_append_rx_isr(user_data);
}
return true; return true;
} }
#endif // SOC_GDMA_SUPPORTED
// SPI slave hd append isr entrance #else
static IRAM_ATTR void spi_slave_hd_intr_append(void *arg) static IRAM_ATTR void s_spi_slave_hd_append_legacy_isr(void *arg)
{ {
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t *)arg; spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t *)arg;
spi_slave_hd_hal_context_t *hal = &host->hal; spi_slave_hd_hal_context_t *hal = &host->hal;
bool rx_done = false; bool rx_done = false;
bool tx_done = false; bool tx_done = false;
// Append Mode
portENTER_CRITICAL_ISR(&host->int_spinlock); portENTER_CRITICAL_ISR(&host->int_spinlock);
if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_RECV)) { 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);
rx_done = true; rx_done = true;
} }
if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_SEND)) { if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_SEND)) {
// NOTE: on gdma supported chips, this flag should NOT checked out, handle entrance is only `spi_gdma_tx_channel_callback`, hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan);
// otherwise, here should be target limited.
tx_done = true; tx_done = true;
} }
portEXIT_CRITICAL_ISR(&host->int_spinlock); portEXIT_CRITICAL_ISR(&host->int_spinlock);
@ -564,6 +573,7 @@ static IRAM_ATTR void spi_slave_hd_intr_append(void *arg)
spi_slave_hd_append_tx_isr(arg); spi_slave_hd_append_tx_isr(arg);
} }
} }
#endif // SOC_GDMA_SUPPORTED
static void s_spi_slave_hd_destroy_priv_trans(spi_host_device_t host, spi_slave_hd_trans_priv_t *priv_trans, spi_slave_chan_t chan) static void s_spi_slave_hd_destroy_priv_trans(spi_host_device_t host, spi_slave_hd_trans_priv_t *priv_trans, spi_slave_chan_t chan)
{ {
@ -626,6 +636,88 @@ static esp_err_t get_ret_queue_result(spi_host_device_t host_id, spi_slave_chan_
return ESP_OK; return ESP_OK;
} }
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;
//Check if there are enough available DMA descriptors for software to use
int num_required = (len + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC;
int not_recycled_desc_num = hal->tx_used_desc_cnt - hal->tx_recycled_desc_cnt;
int available_desc_num = hal->dma_desc_num - not_recycled_desc_num;
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;
if (!hal->tx_dma_started) {
hal->tx_dma_started = true;
//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);
} 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;
spi_dma_append(host->dma_ctx->tx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
for (int i = 0; i < num_required; i++) {
hal->tx_used_desc_cnt++;
hal->tx_cur_desc++;
if (hal->tx_cur_desc == hal->dmadesc_tx + hal->dma_desc_num) {
hal->tx_cur_desc = hal->dmadesc_tx;
}
}
return ESP_OK;
}
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;
//Check if there are enough available dma descriptors for software to use
int num_required = (len + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC;
int not_recycled_desc_num = hal->rx_used_desc_cnt - hal->rx_recycled_desc_cnt;
int available_desc_num = hal->dma_desc_num - not_recycled_desc_num;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
spicommon_dma_desc_setup_link(hal->rx_cur_desc->desc, data, len, false);
hal->rx_cur_desc->arg = arg;
if (!hal->rx_dma_started) {
hal->rx_dma_started = true;
//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);
} 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;
spi_dma_append(host->dma_ctx->rx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
for (int i = 0; i < num_required; i++) {
hal->rx_used_desc_cnt++;
hal->rx_cur_desc++;
if (hal->rx_cur_desc == hal->dmadesc_rx + hal->dma_desc_num) {
hal->rx_cur_desc = hal->dmadesc_rx;
}
}
return ESP_OK;
}
//---------------------------------------------------------Segment Mode Transaction APIs-----------------------------------------------------------// //---------------------------------------------------------Segment Mode Transaction APIs-----------------------------------------------------------//
esp_err_t spi_slave_hd_queue_trans(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t *trans, TickType_t timeout) esp_err_t spi_slave_hd_queue_trans(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t *trans, TickType_t timeout)
{ {
@ -682,7 +774,6 @@ esp_err_t spi_slave_hd_append_trans(spi_host_device_t host_id, spi_slave_chan_t
{ {
esp_err_t err; esp_err_t err;
spi_slave_hd_slot_t *host = spihost[host_id]; spi_slave_hd_slot_t *host = spihost[host_id];
spi_slave_hd_hal_context_t *hal = &host->hal;
SPIHD_CHECK(trans->len <= SPI_MAX_DMA_LEN, "Currently we only support transaction with data length within 4092 bytes", ESP_ERR_INVALID_ARG); SPIHD_CHECK(trans->len <= SPI_MAX_DMA_LEN, "Currently we only support transaction with data length within 4092 bytes", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(host->append_mode == 1, "This API should be used for SPI Slave HD Append Mode", ESP_ERR_INVALID_STATE); SPIHD_CHECK(host->append_mode == 1, "This API should be used for SPI Slave HD Append Mode", ESP_ERR_INVALID_STATE);
@ -698,13 +789,13 @@ esp_err_t spi_slave_hd_append_trans(spi_host_device_t host_id, spi_slave_chan_t
if (ret == pdFALSE) { if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
} }
err = spi_slave_hd_hal_txdma_append(hal, hd_priv_trans.aligned_buffer, trans->len, trans); err = s_spi_slave_hd_append_txdma(host, hd_priv_trans.aligned_buffer, trans->len, trans);
} else { } else {
BaseType_t ret = xSemaphoreTake(host->rx_cnting_sem, timeout); BaseType_t ret = xSemaphoreTake(host->rx_cnting_sem, timeout);
if (ret == pdFALSE) { if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
} }
err = spi_slave_hd_hal_rxdma_append(hal, hd_priv_trans.aligned_buffer, trans->len, trans); err = s_spi_slave_hd_append_rxdma(host, hd_priv_trans.aligned_buffer, trans->len, trans);
} }
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Wait until the DMA finishes its transaction"); ESP_LOGE(TAG, "Wait until the DMA finishes its transaction");

View File

@ -404,7 +404,7 @@ esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strateg
gdma_group_t *group = pair->group; gdma_group_t *group = pair->group;
gdma_hal_context_t *hal = &group->hal; gdma_hal_context_t *hal = &group->hal;
gdma_hal_set_strategy(hal, pair->pair_id, dma_chan->direction, config->owner_check, config->auto_update_desc); gdma_hal_set_strategy(hal, pair->pair_id, dma_chan->direction, config->owner_check, config->auto_update_desc, config->eof_till_data_popped);
return ESP_OK; return ESP_OK;
} }

View File

@ -122,6 +122,7 @@ typedef struct {
typedef struct { typedef struct {
bool owner_check; /*!< If set / clear, DMA channel enables / disables checking owner validity */ bool owner_check; /*!< If set / clear, DMA channel enables / disables checking owner validity */
bool auto_update_desc; /*!< If set / clear, DMA channel enables / disables hardware to update descriptor automatically (TX channel only) */ bool auto_update_desc; /*!< If set / clear, DMA channel enables / disables hardware to update descriptor automatically (TX channel only) */
bool eof_till_data_popped; /*!< If set / clear, DMA channel out_eof event is triggered on out / in DMA hardware fifo */
} gdma_strategy_config_t; } gdma_strategy_config_t;
/** @cond */ /** @cond */

View File

@ -313,7 +313,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU TX FIFO * Reset SPI CPU TX FIFO
* *
* On ESP32C3, this function is not seperated * On ESP32C3, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -326,7 +326,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU RX FIFO * Reset SPI CPU RX FIFO
* *
* On ESP32C3, this function is not seperated * On ESP32C3, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -711,7 +711,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n Main divider. * @param n Main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -722,10 +722,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -805,7 +805,7 @@ typeof(GPSPI2.clock) reg;
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.

View File

@ -315,7 +315,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU TX FIFO * Reset SPI CPU TX FIFO
* *
* On ESP32C3, this function is not seperated * On ESP32C3, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -328,7 +328,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU RX FIFO * Reset SPI CPU RX FIFO
* *
* On ESP32C3, this function is not seperated * On ESP32C3, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -713,7 +713,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n Main divider. * @param n Main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -724,10 +724,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -807,7 +807,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.

View File

@ -307,7 +307,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU TX FIFO * Reset SPI CPU TX FIFO
* *
* On ESP32C6, this function is not seperated * On ESP32C6, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -320,7 +320,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU RX FIFO * Reset SPI CPU RX FIFO
* *
* On ESP32C6, this function is not seperated * On ESP32C6, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -705,7 +705,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n Main divider. * @param n Main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -716,10 +716,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -799,7 +799,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.

View File

@ -306,7 +306,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU TX FIFO * Reset SPI CPU TX FIFO
* *
* On ESP32H2, this function is not seperated * On ESP32H2, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -319,7 +319,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU RX FIFO * Reset SPI CPU RX FIFO
* *
* On ESP32H2, this function is not seperated * On ESP32H2, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -704,7 +704,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n Main divider. * @param n Main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -715,10 +715,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -798,7 +798,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.

View File

@ -358,7 +358,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU TX FIFO * Reset SPI CPU TX FIFO
* *
* On P4, this function is not seperated * On P4, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -371,7 +371,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU RX FIFO * Reset SPI CPU RX FIFO
* *
* On P4, this function is not seperated * On P4, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -760,7 +760,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n Main divider. * @param n Main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -771,10 +771,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -854,7 +854,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.

View File

@ -337,7 +337,7 @@ static inline void spi_ll_cpu_rx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI DMA TX FIFO * Reset SPI DMA TX FIFO
* *
* On ESP32S2, this function is not seperated * On ESP32S2, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -350,7 +350,7 @@ static inline void spi_ll_dma_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI DMA RX FIFO * Reset SPI DMA RX FIFO
* *
* On ESP32S2, this function is not seperated * On ESP32S2, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -701,7 +701,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n main divider. * @param n main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -712,10 +712,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -795,7 +795,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.
@ -1079,10 +1079,10 @@ static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw)
item(SPI_LL_INTR_WRBUF, slave.int_wr_buf_done_en, slv_wrbuf_dlen.wr_buf_done, slv_wrbuf_dlen.wr_buf_done=0) \ item(SPI_LL_INTR_WRBUF, slave.int_wr_buf_done_en, slv_wrbuf_dlen.wr_buf_done, slv_wrbuf_dlen.wr_buf_done=0) \
item(SPI_LL_INTR_RDDMA, slave.int_rd_dma_done_en, slv_rd_byte.rd_dma_done, slv_rd_byte.rd_dma_done=0) \ item(SPI_LL_INTR_RDDMA, slave.int_rd_dma_done_en, slv_rd_byte.rd_dma_done, slv_rd_byte.rd_dma_done=0) \
item(SPI_LL_INTR_WRDMA, slave.int_wr_dma_done_en, slave1.wr_dma_done, slave1.wr_dma_done=0) \ item(SPI_LL_INTR_WRDMA, slave.int_wr_dma_done_en, slave1.wr_dma_done, slave1.wr_dma_done=0) \
item(SPI_LL_INTR_SEG_DONE, slave.int_dma_seg_trans_en, hold.dma_seg_trans_done, hold.dma_seg_trans_done=0) \
item(SPI_LL_INTR_IN_SUC_EOF, dma_int_ena.in_suc_eof, dma_int_raw.in_suc_eof, dma_int_clr.in_suc_eof=1) \ item(SPI_LL_INTR_IN_SUC_EOF, dma_int_ena.in_suc_eof, dma_int_raw.in_suc_eof, dma_int_clr.in_suc_eof=1) \
item(SPI_LL_INTR_OUT_EOF, dma_int_ena.out_eof, dma_int_raw.out_eof, dma_int_clr.out_eof=1) \ item(SPI_LL_INTR_OUT_EOF, dma_int_ena.out_eof, dma_int_raw.out_eof, dma_int_clr.out_eof=1) \
item(SPI_LL_INTR_OUT_TOTAL_EOF, dma_int_ena.out_total_eof, dma_int_raw.out_total_eof, dma_int_clr.out_total_eof=1) \ item(SPI_LL_INTR_OUT_TOTAL_EOF, dma_int_ena.out_total_eof, dma_int_raw.out_total_eof, dma_int_clr.out_total_eof=1) \
item(SPI_LL_INTR_SEG_DONE, slave.int_dma_seg_trans_en, hold.dma_seg_trans_done, hold.dma_seg_trans_done=0) \
item(SPI_LL_INTR_IN_FULL, dma_int_ena.infifo_full_err, dma_int_raw.infifo_full_err, dma_int_clr.infifo_full_err=1) \ item(SPI_LL_INTR_IN_FULL, dma_int_ena.infifo_full_err, dma_int_raw.infifo_full_err, dma_int_clr.infifo_full_err=1) \
item(SPI_LL_INTR_OUT_EMPTY, dma_int_ena.outfifo_empty_err, dma_int_raw.outfifo_empty_err, dma_int_clr.outfifo_empty_err=1) \ item(SPI_LL_INTR_OUT_EMPTY, dma_int_ena.outfifo_empty_err, dma_int_raw.outfifo_empty_err, dma_int_clr.outfifo_empty_err=1) \
item(SPI_LL_INTR_CMD7, dma_int_ena.cmd7, dma_int_raw.cmd7, dma_int_clr.cmd7=1) \ item(SPI_LL_INTR_CMD7, dma_int_ena.cmd7, dma_int_raw.cmd7, dma_int_clr.cmd7=1) \
@ -1428,7 +1428,7 @@ static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, uin
} }
/** /**
* Get the last outlink descriptor address when DMA produces out_eof intrrupt * Get the last outlink descriptor address when DMA produces out_eof interrupt
* *
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.

View File

@ -322,7 +322,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU TX FIFO * Reset SPI CPU TX FIFO
* *
* On ESP32S3, this function is not seperated * On ESP32S3, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -335,7 +335,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw)
/** /**
* Reset SPI CPU RX FIFO * Reset SPI CPU RX FIFO
* *
* On ESP32S3, this function is not seperated * On ESP32S3, this function is not separated
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
@ -732,7 +732,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
* Get the frequency of given dividers. Don't use in app. * Get the frequency of given dividers. Don't use in app.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param pre Pre devider. * @param pre Pre divider.
* @param n Main divider. * @param n Main divider.
* *
* @return Frequency of given dividers. * @return Frequency of given dividers.
@ -743,10 +743,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
} }
/** /**
* Calculate the nearest frequency avaliable for master. * Calculate the nearest frequency available for master.
* *
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* @param out_reg Output address to store the calculated clock configurations for the return frequency. * @param out_reg Output address to store the calculated clock configurations for the return frequency.
* *
@ -826,7 +826,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param fapb APB clock of the system. * @param fapb APB clock of the system.
* @param hz Frequncy desired. * @param hz Frequency desired.
* @param duty_cycle Duty cycle desired. * @param duty_cycle Duty cycle desired.
* *
* @return Actual frequency that is used. * @return Actual frequency that is used.

View File

@ -102,14 +102,16 @@ void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_c
} }
#endif #endif
void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back) void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped)
{ {
if (dir == GDMA_CHANNEL_DIRECTION_RX) { if (dir == GDMA_CHANNEL_DIRECTION_RX) {
gdma_ll_rx_enable_owner_check(hal->dev, chan_id, en_owner_check); gdma_ll_rx_enable_owner_check(hal->dev, chan_id, en_owner_check);
// RX direction always has the descriptor write-back feature enabled // RX direction always has the descriptor write-back feature enabled
// RX direction don't need config eof_mode
} else { } else {
gdma_ll_tx_enable_owner_check(hal->dev, chan_id, en_owner_check); gdma_ll_tx_enable_owner_check(hal->dev, chan_id, en_owner_check);
gdma_ll_tx_enable_auto_write_back(hal->dev, chan_id, en_desc_write_back); gdma_ll_tx_enable_auto_write_back(hal->dev, chan_id, en_desc_write_back);
gdma_ll_tx_set_eof_mode(hal->dev, chan_id, eof_till_popped);
} }
} }

View File

@ -91,14 +91,16 @@ void gdma_ahb_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe
} }
} }
void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back) void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped)
{ {
if (dir == GDMA_CHANNEL_DIRECTION_RX) { if (dir == GDMA_CHANNEL_DIRECTION_RX) {
ahb_dma_ll_rx_enable_owner_check(hal->ahb_dma_dev, chan_id, en_owner_check); ahb_dma_ll_rx_enable_owner_check(hal->ahb_dma_dev, chan_id, en_owner_check);
// RX direction always has the descriptor write-back feature enabled // RX direction always has the descriptor write-back feature enabled
// RX direction don't need config eof_mode
} else { } else {
ahb_dma_ll_tx_enable_owner_check(hal->ahb_dma_dev, chan_id, en_owner_check); ahb_dma_ll_tx_enable_owner_check(hal->ahb_dma_dev, chan_id, en_owner_check);
ahb_dma_ll_tx_enable_auto_write_back(hal->ahb_dma_dev, chan_id, en_desc_write_back); ahb_dma_ll_tx_enable_auto_write_back(hal->ahb_dma_dev, chan_id, en_desc_write_back);
ahb_dma_ll_tx_set_eof_mode(hal->ahb_dma_dev, chan_id, eof_till_popped);
} }
} }

View File

@ -91,14 +91,16 @@ void gdma_axi_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe
} }
} }
void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back) void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped)
{ {
if (dir == GDMA_CHANNEL_DIRECTION_RX) { if (dir == GDMA_CHANNEL_DIRECTION_RX) {
axi_dma_ll_rx_enable_owner_check(hal->axi_dma_dev, chan_id, en_owner_check); axi_dma_ll_rx_enable_owner_check(hal->axi_dma_dev, chan_id, en_owner_check);
// RX direction always has the descriptor write-back feature enabled // RX direction always has the descriptor write-back feature enabled
// RX direction don't need config eof_mode
} else { } else {
axi_dma_ll_tx_enable_owner_check(hal->axi_dma_dev, chan_id, en_owner_check); axi_dma_ll_tx_enable_owner_check(hal->axi_dma_dev, chan_id, en_owner_check);
axi_dma_ll_tx_enable_auto_write_back(hal->axi_dma_dev, chan_id, en_desc_write_back); axi_dma_ll_tx_enable_auto_write_back(hal->axi_dma_dev, chan_id, en_desc_write_back);
axi_dma_ll_tx_set_eof_mode(hal->axi_dma_dev, chan_id, eof_till_popped);
} }
} }

View File

@ -60,9 +60,9 @@ void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_chann
} }
} }
void gdma_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back) void gdma_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped)
{ {
hal->set_strategy(hal, chan_id, dir, en_owner_check, en_desc_write_back); hal->set_strategy(hal, chan_id, dir, en_owner_check, en_desc_write_back, eof_till_popped);
} }
void gdma_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis) void gdma_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis)

View File

@ -81,7 +81,7 @@ struct gdma_hal_context_t {
void (*disconnect_peri)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Disconnect the channel from a peripheral void (*disconnect_peri)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Disconnect the channel from a peripheral
void (*enable_burst)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); /// Enable burst mode void (*enable_burst)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); /// Enable burst mode
void (*set_ext_mem_align)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); /// Set the alignment of the external memory void (*set_ext_mem_align)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); /// Set the alignment of the external memory
void (*set_strategy)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); /// Set some misc strategy of the channel behaviour void (*set_strategy)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped); /// Set some misc strategy of the channel behaviour
uint32_t (*get_intr_status_reg)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); // Get the interrupt status register address uint32_t (*get_intr_status_reg)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); // Get the interrupt status register address
void (*enable_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); /// Enable the channel interrupt void (*enable_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); /// Enable the channel interrupt
void (*clear_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask); /// Clear the channel interrupt void (*clear_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask); /// Clear the channel interrupt
@ -117,7 +117,7 @@ void gdma_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_di
void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align);
void gdma_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); void gdma_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped);
void gdma_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); void gdma_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis);

View File

@ -30,7 +30,7 @@ void gdma_ahb_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe
void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align);
void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped);
void gdma_ahb_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); void gdma_ahb_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis);

View File

@ -30,7 +30,7 @@ void gdma_axi_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe
void gdma_axi_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); void gdma_axi_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align);
void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back, bool eof_till_popped);
void gdma_axi_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); void gdma_axi_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis);

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -52,8 +52,6 @@ typedef dma_descriptor_align8_t spi_dma_desc_t;
typedef struct { typedef struct {
/* configured by driver at initialization, don't touch */ /* configured by driver at initialization, don't touch */
spi_dev_t *hw; ///< Beginning address of the peripheral registers. spi_dev_t *hw; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
/* should be configured by driver at initialization */ /* should be configured by driver at initialization */
spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA. spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that * The amount should be larger than dmadesc_n. The driver should ensure that
@ -64,8 +62,6 @@ typedef struct {
* the data to be sent is shorter than the descriptors can hold. * the data to be sent is shorter than the descriptors can hold.
*/ */
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use. int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
/* /*
* configurations to be filled after ``spi_slave_hal_init``. Updated to * configurations to be filled after ``spi_slave_hal_init``. Updated to
@ -92,8 +88,6 @@ typedef struct {
typedef struct { typedef struct {
uint32_t host_id; ///< SPI controller ID uint32_t host_id; ///< SPI controller ID
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
} spi_slave_hal_config_t; } spi_slave_hal_config_t;
/** /**
@ -119,11 +113,53 @@ void spi_slave_hal_deinit(spi_slave_hal_context_t *hal);
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal); void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal);
/** /**
* Prepare the data for the current transaction. * Prepare rx hardware for a new DMA trans
*
* @param hw Beginning address of the peripheral registers.
*/
void spi_slave_hal_hw_prepare_rx(spi_dev_t *hw);
/**
* Prepare tx hardware for a new DMA trans
*
* @param hw Beginning address of the peripheral registers.
*/
void spi_slave_hal_hw_prepare_tx(spi_dev_t *hw);
/**
* Rest peripheral registers to default value
* *
* @param hal Context of the HAL layer. * @param hal Context of the HAL layer.
*/ */
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal); void spi_slave_hal_hw_reset(spi_slave_hal_context_t *hal);
/**
* Rest hw fifo in peripheral, for a CPU controlled trans
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_hw_fifo_reset(spi_slave_hal_context_t *hal, bool tx_rst, bool rx_rst);
/**
* Push data needed to be transmit into hw fifo
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_push_tx_buffer(spi_slave_hal_context_t *hal);
/**
* Config transaction bit length for slave
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_set_trans_bitlen(spi_slave_hal_context_t *hal);
/**
* Enable/Disable miso/mosi signals in peripheral
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_enable_data_line(spi_slave_hal_context_t *hal);
/** /**
* Trigger start a user-defined transaction. * Trigger start a user-defined transaction.
@ -140,7 +176,7 @@ void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal);
bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal); bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal);
/** /**
* Post transaction operations, fetch data from the buffer and recored the length. * Post transaction operations, fetch data from the buffer and recorded the length.
* *
* @param hal Context of the HAL layer. * @param hal Context of the HAL layer.
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -84,11 +84,7 @@ typedef struct {
/// Configuration of the HAL /// Configuration of the HAL
typedef struct { typedef struct {
uint32_t host_id; ///< Host ID of the spi peripheral uint32_t host_id; ///< Host ID of the spi peripheral
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
bool dma_enabled; ///< DMA enabled or not bool dma_enabled; ///< DMA enabled or not
uint32_t tx_dma_chan; ///< TX DMA channel used.
uint32_t rx_dma_chan; ///< RX DMA channel used.
bool append_mode; ///< True for DMA append mode, false for segment mode bool append_mode; ///< True for DMA append mode, false for segment mode
uint32_t spics_io_num; ///< CS GPIO pin for this device uint32_t spics_io_num; ///< CS GPIO pin for this device
uint8_t mode; ///< SPI mode (0-3) uint8_t mode; ///< SPI mode (0-3)
@ -110,13 +106,10 @@ typedef struct {
/* address of the hardware */ /* address of the hardware */
spi_dev_t *dev; ///< Beginning address of the peripheral registers. spi_dev_t *dev; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
bool dma_enabled; ///< DMA enabled or not bool dma_enabled; ///< DMA enabled or not
uint32_t tx_dma_chan; ///< TX DMA channel used.
uint32_t rx_dma_chan; ///< RX DMA channel used.
bool append_mode; ///< True for DMA append mode, false for segment mode 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 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_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_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 spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware
@ -165,7 +158,7 @@ bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_eve
bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev); bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
/** /**
* @brief Enable to invole the ISR of corresponding event. * @brief Enable to involve the ISR of corresponding event.
* *
* @note The function, compared with :cpp:func:`spi_slave_hd_hal_enable_event_intr`, contains a * @note The function, compared with :cpp:func:`spi_slave_hd_hal_enable_event_intr`, contains a
* workaround to force trigger the interrupt, even if the interrupt source cannot be initialized * workaround to force trigger the interrupt, even if the interrupt source cannot be initialized
@ -194,7 +187,7 @@ void spi_slave_hd_hal_enable_event_intr(spi_slave_hd_hal_context_t* hal, spi_eve
* @param[out] out_buf Buffer to receive the data * @param[out] out_buf Buffer to receive the data
* @param len Maximul length to receive * @param len Maximul length to receive
*/ */
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len); void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal);
/** /**
* @brief Get the length of total received data * @brief Get the length of total received data
@ -204,6 +197,13 @@ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, s
*/ */
int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal); 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
*
* @param hal Context of the HAL layer
*/
void spi_slave_hd_hal_hw_prepare_rx(spi_slave_hd_hal_context_t *hal);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// TX DMA // TX DMA
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -214,7 +214,14 @@ int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal);
* @param data Buffer of data to send * @param data Buffer of data to send
* @param len Size of the buffer, also the maximum length to send * @param len Size of the buffer, also the maximum length to send
*/ */
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len); void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal);
/**
* @brief Prepare hardware for a new dma tx trans
*
* @param hal Context of the HAL layer
*/
void spi_slave_hd_hal_hw_prepare_tx(spi_slave_hd_hal_context_t *hal);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Shared buffer // Shared buffer
@ -223,7 +230,7 @@ void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size
* @brief Read from the shared register buffer * @brief Read from the shared register buffer
* *
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param addr Address of the shared regsiter to read * @param addr Address of the shared register to read
* @param out_data Buffer to store the read data * @param out_data Buffer to store the read data
* @param len Length to read from the shared buffer * @param len Length to read from the shared buffer
*/ */
@ -294,7 +301,7 @@ bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, voi
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param data Buffer of the transaction data * @param data Buffer of the transaction data
* @param len Length of the data * @param len Length of the data
* @param arg Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_tx_finished_trans`` when transaction is finished * @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 * @return
* - ESP_OK: on success * - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: Function called in invalid state. * - ESP_ERR_INVALID_STATE: Function called in invalid state.
@ -307,7 +314,7 @@ esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t
* @param hal Context of the HAL layer * @param hal Context of the HAL layer
* @param data Buffer of the transaction data * @param data Buffer of the transaction data
* @param len Length of the data * @param len Length of the data
* @param arg Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_rx_finished_trans`` when transaction is finished * @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 * @return
* - ESP_OK: on success * - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: Function called in invalid state. * - ESP_ERR_INVALID_STATE: Function called in invalid state.

View File

@ -4,10 +4,7 @@
void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config) void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config)
{ {
spi_dev_t *hw = SPI_LL_GET_HW(hal_config->host_id); hal->hw = SPI_LL_GET_HW(hal_config->host_id);
hal->hw = hw;
hal->dma_in = hal_config->dma_in;
hal->dma_out = hal_config->dma_out;
spi_ll_slave_init(hal->hw); spi_ll_slave_init(hal->hw);

View File

@ -1,39 +1,7 @@
#include "hal/spi_slave_hal.h" #include "hal/spi_slave_hal.h"
#include "hal/spi_ll.h" #include "hal/spi_ll.h"
#include "soc/ext_mem_defs.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
#if SOC_GDMA_SUPPORTED
#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1)
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan);
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
gdma_ll_rx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_rx_start(&GDMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_tx_start(&GDMA, chan);\
} while (0)
#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer
#include "hal/axi_dma_ll.h"
#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan);
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_rx_start(&AXI_DMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_tx_start(&AXI_DMA, chan);\
} while (0)
#endif
#endif //SOC_GDMA_SUPPORTED
bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal) bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal)
{ {
return spi_ll_usr_is_done(hal->hw); return spi_ll_usr_is_done(hal->hw);
@ -45,89 +13,48 @@ void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal)
spi_ll_user_start(hal->hw); spi_ll_user_start(hal->hw);
} }
#if SOC_NON_CACHEABLE_OFFSET void spi_slave_hal_hw_prepare_rx(spi_dev_t *hw)
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
static void s_spi_slave_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{ {
dmadesc = ADDR_DMA_2_CPU(dmadesc); spi_ll_dma_rx_fifo_reset(hw);
int n = 0; spi_ll_infifo_full_clr(hw);
while (len) { spi_ll_dma_rx_enable(hw, 1);
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++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
} }
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) void spi_slave_hal_hw_prepare_tx(spi_dev_t *hw)
{ {
if (hal->use_dma) { spi_ll_dma_tx_fifo_reset(hw);
spi_ll_outfifo_empty_clr(hw);
spi_ll_dma_tx_enable(hw, 1);
}
//Fill DMA descriptors void spi_slave_hal_hw_reset(spi_slave_hal_context_t *hal)
if (hal->rx_buffer) { {
s_spi_slave_hal_dma_desc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true);
//reset dma inlink, this should be reset before spi related reset
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
spi_ll_dma_rx_fifo_reset(hal->dma_in);
spi_ll_slave_reset(hal->hw); spi_ll_slave_reset(hal->hw);
spi_ll_infifo_full_clr(hal->hw); }
spi_ll_dma_rx_enable(hal->hw, 1); void spi_slave_hal_hw_fifo_reset(spi_slave_hal_context_t *hal, bool tx_rst, bool rx_rst)
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx); {
} tx_rst ? spi_ll_cpu_tx_fifo_reset(hal->hw) : 0;
rx_rst ? spi_ll_cpu_rx_fifo_reset(hal->hw) : 0;
}
void spi_slave_hal_push_tx_buffer(spi_slave_hal_context_t *hal)
{
if (hal->tx_buffer) { if (hal->tx_buffer) {
s_spi_slave_hal_dma_desc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false);
//reset dma outlink, this should be reset before spi related reset
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
spi_ll_dma_tx_fifo_reset(hal->dma_out);
spi_ll_slave_reset(hal->hw);
spi_ll_outfifo_empty_clr(hal->hw);
spi_ll_dma_tx_enable(hal->hw, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->dmadesc_tx);
}
} else {
//No DMA. Turn off SPI and copy data to transmit buffers.
if (hal->tx_buffer) {
spi_ll_slave_reset(hal->hw);
spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen); spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen);
} }
}
spi_ll_cpu_tx_fifo_reset(hal->hw); void spi_slave_hal_set_trans_bitlen(spi_slave_hal_context_t *hal)
} {
spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen); spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen);
spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen); spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen);
}
#ifdef CONFIG_IDF_TARGET_ESP32 void spi_slave_hal_enable_data_line(spi_slave_hal_context_t *hal)
//SPI Slave mode on ESP32 requires MOSI/MISO enable {
spi_ll_enable_mosi(hal->hw, (hal->rx_buffer == NULL) ? 0 : 1); spi_ll_enable_mosi(hal->hw, (hal->rx_buffer != NULL));
spi_ll_enable_miso(hal->hw, (hal->tx_buffer == NULL) ? 0 : 1); spi_ll_enable_miso(hal->hw, (hal->tx_buffer != NULL));
#endif
} }
void spi_slave_hal_store_result(spi_slave_hal_context_t *hal) void spi_slave_hal_store_result(spi_slave_hal_context_t *hal)

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -14,79 +14,21 @@
#include "soc/spi_periph.h" #include "soc/spi_periph.h"
#include "soc/lldesc.h" #include "soc/lldesc.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/ext_mem_defs.h"
#include "hal/spi_slave_hd_hal.h" #include "hal/spi_slave_hd_hal.h"
#include "hal/assert.h" #include "hal/assert.h"
//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
#if SOC_GDMA_SUPPORTED
#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1)
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#define spi_dma_ll_tx_restart(dev, chan) gdma_ll_tx_restart(&GDMA, chan)
#define spi_dma_ll_rx_restart(dev, chan) gdma_ll_rx_restart(&GDMA, chan)
#define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan)
#define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, chan, enable)
#define spi_dma_ll_set_out_eof_generation(dev, chan, enable) gdma_ll_tx_set_eof_mode(&GDMA, chan, enable)
#define spi_dma_ll_get_out_eof_desc_addr(dev, chan) gdma_ll_tx_get_eof_desc_addr(&GDMA, chan)
#define spi_dma_ll_get_in_suc_eof_desc_addr(dev, chan) gdma_ll_rx_get_success_eof_desc_addr(&GDMA, chan)
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
gdma_ll_rx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_rx_start(&GDMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_tx_start(&GDMA, chan);\
} while (0)
#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
#include "hal/axi_dma_ll.h"
#define spi_dma_ll_tx_restart(dev, chan) axi_dma_ll_tx_restart(&AXI_DMA, chan)
#define spi_dma_ll_rx_restart(dev, chan) axi_dma_ll_rx_restart(&AXI_DMA, chan)
#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_enable_out_auto_wrback(dev, chan, enable) axi_dma_ll_tx_enable_auto_write_back(&AXI_DMA, chan, enable)
#define spi_dma_ll_set_out_eof_generation(dev, chan, enable) axi_dma_ll_tx_set_eof_mode(&AXI_DMA, chan, enable)
#define spi_dma_ll_get_out_eof_desc_addr(dev, chan) axi_dma_ll_tx_get_eof_desc_addr(&AXI_DMA, chan)
#define spi_dma_ll_get_in_suc_eof_desc_addr(dev, chan) axi_dma_ll_rx_get_success_eof_desc_addr(&AXI_DMA, chan)
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_rx_start(&AXI_DMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_tx_start(&AXI_DMA, chan);\
} while (0)
#endif
#endif //SOC_GDMA_SUPPORTED
static void s_spi_slave_hd_hal_dma_init_config(const spi_slave_hd_hal_context_t *hal)
{
spi_dma_ll_enable_out_auto_wrback(hal->dma_out, hal->tx_dma_chan, 1);
spi_dma_ll_set_out_eof_generation(hal->dma_out, hal->tx_dma_chan, 1);
}
void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config) void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config)
{ {
spi_dev_t *hw = SPI_LL_GET_HW(hal_config->host_id); spi_dev_t *hw = SPI_LL_GET_HW(hal_config->host_id);
hal->dev = hw; hal->dev = hw;
hal->dma_in = hal_config->dma_in;
hal->dma_out = hal_config->dma_out;
hal->dma_enabled = hal_config->dma_enabled; hal->dma_enabled = hal_config->dma_enabled;
hal->tx_dma_chan = hal_config->tx_dma_chan;
hal->rx_dma_chan = hal_config->rx_dma_chan;
hal->append_mode = hal_config->append_mode; hal->append_mode = hal_config->append_mode;
hal->tx_cur_desc = hal->dmadesc_tx; hal->tx_cur_desc = hal->dmadesc_tx;
hal->rx_cur_desc = hal->dmadesc_rx; hal->rx_cur_desc = hal->dmadesc_rx;
hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num -1; hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num -1;
hal->rx_dma_head = hal->dmadesc_rx + hal->dma_desc_num -1; hal->rx_dma_head = hal->dmadesc_rx + hal->dma_desc_num -1;
//Configure slave
if (hal_config->dma_enabled) {
s_spi_slave_hd_hal_dma_init_config(hal);
}
spi_ll_slave_hd_init(hw); spi_ll_slave_hd_init(hw);
spi_ll_set_addr_bitlen(hw, hal_config->address_bits); spi_ll_set_addr_bitlen(hw, hal_config->address_bits);
spi_ll_set_command_bitlen(hw, hal_config->command_bits); spi_ll_set_command_bitlen(hw, hal_config->command_bits);
@ -115,11 +57,8 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
spi_ll_set_intr(hw, SPI_LL_INTR_TRANS_DONE); spi_ll_set_intr(hw, SPI_LL_INTR_TRANS_DONE);
} }
} else { } else {
#if SOC_GDMA_SUPPORTED #if !SOC_GDMA_SUPPORTED
spi_ll_enable_intr(hw, SPI_LL_INTR_CMD7); spi_ll_enable_intr(hw, SPI_LL_INTR_CMD7 | SPI_LL_INTR_CMD8);
#else
spi_ll_clear_intr(hw, SPI_LL_INTR_OUT_EOF | SPI_LL_INTR_CMD7);
spi_ll_enable_intr(hw, SPI_LL_INTR_OUT_EOF | SPI_LL_INTR_CMD7);
#endif //SOC_GDMA_SUPPORTED #endif //SOC_GDMA_SUPPORTED
} }
@ -132,42 +71,14 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
} }
#if SOC_NON_CACHEABLE_OFFSET #if SOC_NON_CACHEABLE_OFFSET
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + 0x40000000)) #include "hal/cache_ll.h"
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - 0x40000000)) #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 #else
#define ADDR_DMA_2_CPU(addr) (addr) #define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr) #define ADDR_CPU_2_DMA(addr) (addr)
#endif #endif
static void s_spi_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{
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);
dmadesc[n].dw0.length = (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 = 1;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
}
static int s_desc_get_received_len_addr(spi_dma_desc_t* head, spi_dma_desc_t** out_next, void **out_buff_head) 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); spi_dma_desc_t* desc_cpu = ADDR_DMA_2_CPU(head);
@ -188,41 +99,38 @@ static int s_desc_get_received_len_addr(spi_dma_desc_t* head, spi_dma_desc_t** o
return len; return len;
} }
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len) void spi_slave_hd_hal_hw_prepare_rx(spi_slave_hd_hal_context_t *hal)
{ {
s_spi_hal_dma_desc_setup_link(hal->dmadesc_rx->desc, out_buf, len, true);
spi_ll_dma_rx_fifo_reset(hal->dev); spi_ll_dma_rx_fifo_reset(hal->dev);
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
spi_ll_slave_reset(hal->dev);
spi_ll_infifo_full_clr(hal->dev); spi_ll_infifo_full_clr(hal->dev);
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD7);
spi_ll_dma_rx_enable(hal->dev, 1); spi_ll_dma_rx_enable(hal->dev, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx->desc);
} }
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len) void spi_slave_hd_hal_hw_prepare_tx(spi_slave_hd_hal_context_t *hal)
{ {
s_spi_hal_dma_desc_setup_link(hal->dmadesc_tx->desc, data, len, false);
spi_ll_dma_tx_fifo_reset(hal->dev); spi_ll_dma_tx_fifo_reset(hal->dev);
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
spi_ll_slave_reset(hal->dev);
spi_ll_outfifo_empty_clr(hal->dev); spi_ll_outfifo_empty_clr(hal->dev);
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8);
spi_ll_dma_tx_enable(hal->dev, 1); spi_ll_dma_tx_enable(hal->dev, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->dmadesc_tx->desc); }
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal)
{
spi_ll_slave_reset(hal->dev);
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD7);
spi_slave_hd_hal_hw_prepare_rx(hal);
}
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal)
{
spi_ll_slave_reset(hal->dev);
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8);
spi_slave_hd_hal_hw_prepare_tx(hal);
} }
static spi_ll_intr_t get_event_intr(spi_slave_hd_hal_context_t *hal, spi_event_t ev) static spi_ll_intr_t get_event_intr(spi_slave_hd_hal_context_t *hal, spi_event_t ev)
{ {
spi_ll_intr_t intr = 0; spi_ll_intr_t intr = 0;
#if CONFIG_IDF_TARGET_ESP32S2 if (ev & SPI_EV_SEND) intr |= SPI_LL_INTR_CMD8;
if ((ev & SPI_EV_SEND) && hal->append_mode) intr |= SPI_LL_INTR_OUT_EOF;
#endif
if ((ev & SPI_EV_SEND) && !hal->append_mode) intr |= SPI_LL_INTR_CMD8;
if (ev & SPI_EV_RECV) intr |= SPI_LL_INTR_CMD7; if (ev & SPI_EV_RECV) intr |= SPI_LL_INTR_CMD7;
if (ev & SPI_EV_BUF_TX) intr |= SPI_LL_INTR_RDBUF; if (ev & SPI_EV_BUF_TX) intr |= SPI_LL_INTR_RDBUF;
if (ev & SPI_EV_BUF_RX) intr |= SPI_LL_INTR_WRBUF; if (ev & SPI_EV_BUF_RX) intr |= SPI_LL_INTR_WRBUF;
@ -315,8 +223,7 @@ int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal)
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr) bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, void **real_buff_addr)
{ {
uint32_t desc_now = spi_dma_ll_get_out_eof_desc_addr(hal->dma_out, hal->tx_dma_chan); if ((uint32_t)hal->tx_dma_head->desc == hal->current_eof_addr) {
if ((uint32_t)hal->tx_dma_head->desc == desc_now) {
return false; return false;
} }
@ -333,8 +240,7 @@ bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, voi
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) 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)
{ {
uint32_t desc_now = spi_dma_ll_get_in_suc_eof_desc_addr(hal->dma_in, hal->rx_dma_chan); if ((uint32_t)hal->rx_dma_head->desc == hal->current_eof_addr) {
if ((uint32_t)hal->rx_dma_head->desc == desc_now) {
return false; return false;
} }
@ -348,85 +254,3 @@ bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, voi
hal->rx_recycled_desc_cnt++; hal->rx_recycled_desc_cnt++;
return true; return true;
} }
esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg)
{
//Check if there are enough available DMA descriptors for software to use
int num_required = (len + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC;
int not_recycled_desc_num = hal->tx_used_desc_cnt - hal->tx_recycled_desc_cnt;
int available_desc_num = hal->dma_desc_num - not_recycled_desc_num;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
s_spi_hal_dma_desc_setup_link(hal->tx_cur_desc->desc, data, len, false);
hal->tx_cur_desc->arg = arg;
if (!hal->tx_dma_started) {
hal->tx_dma_started = true;
//start a link
hal->tx_dma_tail = hal->tx_cur_desc;
spi_ll_dma_tx_fifo_reset(hal->dma_out);
spi_ll_outfifo_empty_clr(hal->dev);
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
spi_ll_dma_tx_enable(hal->dev, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->tx_cur_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;
spi_dma_ll_tx_restart(hal->dma_out, hal->tx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
for (int i = 0; i < num_required; i++) {
hal->tx_used_desc_cnt++;
hal->tx_cur_desc++;
if (hal->tx_cur_desc == hal->dmadesc_tx + hal->dma_desc_num) {
hal->tx_cur_desc = hal->dmadesc_tx;
}
}
return ESP_OK;
}
esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg)
{
//Check if there are enough available dma descriptors for software to use
int num_required = (len + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC;
int not_recycled_desc_num = hal->rx_used_desc_cnt - hal->rx_recycled_desc_cnt;
int available_desc_num = hal->dma_desc_num - not_recycled_desc_num;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
s_spi_hal_dma_desc_setup_link(hal->rx_cur_desc->desc, data, len, false);
hal->rx_cur_desc->arg = arg;
if (!hal->rx_dma_started) {
hal->rx_dma_started = true;
//start a link
hal->rx_dma_tail = hal->rx_cur_desc;
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
spi_ll_dma_rx_fifo_reset(hal->dma_in);
spi_ll_infifo_full_clr(hal->dev);
spi_ll_dma_rx_enable(hal->dev, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->rx_cur_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;
spi_dma_ll_rx_restart(hal->dma_in, hal->rx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
for (int i = 0; i < num_required; i++) {
hal->rx_used_desc_cnt++;
hal->rx_cur_desc++;
if (hal->rx_cur_desc == hal->dmadesc_rx + hal->dma_desc_num) {
hal->rx_cur_desc = hal->dmadesc_rx;
}
}
return ESP_OK;
}