refactor(spi_slave): replace dma_ll in slave hal layer (part 2.2)

This commit is contained in:
wanlei 2023-12-13 12:51:58 +08:00 committed by Wan Lei
parent 31f4e9c698
commit 67f798b666
15 changed files with 195 additions and 222 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-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

View File

@ -315,7 +315,7 @@ esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *
#define ADDR_CPU_2_DMA(addr) (addr) #define ADDR_CPU_2_DMA(addr) (addr)
#endif #endif
void SPI_MASTER_ISR_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx) void IRAM_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;

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

@ -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.
@ -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

@ -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

@ -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);
//Fill DMA descriptors spi_ll_dma_tx_enable(hw, 1);
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_infifo_full_clr(hal->hw);
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx);
} }
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 void spi_slave_hal_hw_reset(spi_slave_hal_context_t *hal)
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_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. void spi_slave_hal_hw_fifo_reset(spi_slave_hal_context_t *hal, bool tx_rst, bool rx_rst)
{
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) {
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)