diff --git a/components/driver/include/driver/spi_common_internal.h b/components/driver/include/driver/spi_common_internal.h index 82d5b73c9d..f5015bfbf4 100644 --- a/components/driver/include/driver/spi_common_internal.h +++ b/components/driver/include/driver/spi_common_internal.h @@ -65,7 +65,9 @@ typedef struct { spi_bus_config_t bus_cfg; ///< Config used to initialize the bus uint32_t flags; ///< Flags (attributes) of the bus int max_transfer_sz; ///< Maximum length of bytes available to send - int dma_chan; ///< DMA channel used + bool dma_enabled; ///< To enable DMA or not + int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same + int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx. lldesc_t *dmadesc_tx; ///< DMA descriptor array for TX lldesc_t *dmadesc_rx; ///< DMA descriptor array for RX @@ -127,24 +129,30 @@ bool spicommon_periph_free(spi_host_device_t host); bool spicommon_dma_chan_in_use(int dma_chan); /** - * @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA. + * @brief Configure DMA for SPI Slave * - * @param dma_chan channel to return + * @param host_id SPI host ID + * @param dma_chan -1: auto dma allocate mode; 0: non-dma mode; 1 or 2: assign a specific DMA channel; + * @param[out] out_actual_tx_dma_chan Actual TX DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before) + * @param[out] out_actual_rx_dma_chan Actual RX DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before) * - * @note This public API is deprecated. - * - * @return True if success; false otherwise. + * @return + * - ESP_OK: On success + * - ESP_ERR_NO_MEM: No enough memory + * - ESP_ERR_INVALID_STATE: Driver invalid state, check the log message for details */ -bool spicommon_dma_chan_free(int dma_chan); +esp_err_t spicommon_slave_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan); /** - * @brief Try to claim a SPI DMA channel and connect it with SPI peripherals + * @brief Free DMA for SPI Slave * - * @param host_id SPI host ID - * @param dma_chan -1: auto dma allocate mode; 0: non-dma mode; 1 or 2: assign a specific DMA channel; - * @param[out] out_actual_dma_chan Actual DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before) + * @param host_id SPI host ID + * @param dma_chan Actual used DMA channel + * + * @return + * - ESP_OK: On success */ -esp_err_t spicommon_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t *out_actual_dma_chan); +esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id, int dma_chan); /** * @brief Connect a SPI peripheral to GPIO pins @@ -158,7 +166,6 @@ esp_err_t spicommon_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t * * @param host SPI peripheral to be routed * @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins - * @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA. * @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions: * - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode * - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode @@ -180,7 +187,7 @@ esp_err_t spicommon_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t * - ESP_ERR_INVALID_ARG if parameter is invalid * - ESP_OK on success */ -esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t *flags_o); +esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t *flags_o); /** * @brief Free the IO used by a SPI peripheral diff --git a/components/driver/include/driver/spi_slave_hd.h b/components/driver/include/driver/spi_slave_hd.h index 639f7b3287..55990f88ed 100644 --- a/components/driver/include/driver/spi_slave_hd.h +++ b/components/driver/include/driver/spi_slave_hd.h @@ -86,7 +86,7 @@ typedef struct { uint32_t address_bits; ///< address field bits, multiples of 8 and at least 8. uint32_t dummy_bits; ///< dummy field bits, multiples of 8 and at least 8. uint32_t queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_hd_queue_trans but not yet finished using spi_slave_hd_get_trans_result) at the same time - uint32_t dma_chan; ///< DMA channel used. -1: auto dma allocate mode; 0: non-dma mode; 1 or 2: assign a specific DMA channel; + int dma_chan; ///< DMA channel used. -1: auto dma allocate mode; 0: non-dma mode; 1 or 2: assign a specific DMA channel; spi_slave_hd_callback_config_t cb_config; ///< Callback configuration } spi_slave_hd_slot_config_t; diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index 2f64299b2c..a1ae2f02db 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -38,6 +38,7 @@ //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. #if SOC_GDMA_SUPPORTED +#include "esp_private/gdma.h" #include "hal/gdma_ll.h" #include "soc/gdma_channel.h" #include "soc/spi_caps.h" @@ -70,43 +71,52 @@ typedef struct spi_device_t spi_device_t; #define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1)) - typedef struct { int host_id; spi_destroy_func_t destroy_func; void* destroy_arg; spi_bus_attr_t bus_attr; +#if SOC_GDMA_SUPPORTED + gdma_channel_handle_t tx_channel; + gdma_channel_handle_t rx_channel; +#endif } spicommon_bus_context_t; #define MAIN_BUS_DEFAULT() { \ .host_id = 0, \ .bus_attr = { \ - .dma_chan = 0, \ + .tx_dma_chan = 0, \ + .rx_dma_chan = 0, \ .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, \ .dma_desc_num= 0, \ }, \ } //Periph 1 is 'claimed' by SPI flash code. -static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false), -#if SOC_SPI_PERIPH_NUM >= 4 +static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), +#if (SOC_SPI_PERIPH_NUM >= 3) +ATOMIC_VAR_INIT(false), +#endif +#if (SOC_SPI_PERIPH_NUM >= 4) ATOMIC_VAR_INIT(false), #endif }; static const char* spi_claiming_func[3] = {NULL, NULL, NULL}; +#if !SOC_GDMA_SUPPORTED static uint8_t spi_dma_chan_enabled = 0; static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED; +#endif static spicommon_bus_context_t s_mainbus = MAIN_BUS_DEFAULT(); static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus}; -#if CONFIG_IDF_TARGET_ESP32 || SOC_GDMA_SUPPORTED +#if CONFIG_IDF_TARGET_ESP32 //ESP32S2 does not support DMA channel auto-allocation //Each bit stands for 1 dma channel, used for auto-alloc dma channel static uint32_t spi_dma_channel_code; #endif - +//----------------------------------------------------------alloc spi periph-------------------------------------------------------// //Returns true if this peripheral is successfully claimed, false if otherwise. bool spicommon_periph_claim(spi_host_device_t host, const char* source) { @@ -145,6 +155,8 @@ int spicommon_irqdma_source_for_host(spi_host_device_t host) return spi_periph_signal[host].irq_dma; } +//----------------------------------------------------------esp32/s2 dma periph-------------------------------------------------------// +#if !SOC_GDMA_SUPPORTED static inline periph_module_t get_dma_periph(int dma_chan) { #if CONFIG_IDF_TARGET_ESP32S2 @@ -158,10 +170,6 @@ static inline periph_module_t get_dma_periph(int dma_chan) } #elif CONFIG_IDF_TARGET_ESP32 return PERIPH_SPI_DMA_MODULE; -#elif SOC_GDMA_SUPPORTED - return PERIPH_GDMA_MODULE; -#else - return 0; #endif } @@ -183,14 +191,152 @@ static bool spicommon_dma_chan_claim(int dma_chan) return ret; } -bool spicommon_dma_chan_in_use(int dma_chan) +static void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan) { - assert(dma_chan ==1 || dma_chan == 2); - return spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan); +#if CONFIG_IDF_TARGET_ESP32 + DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2)); +#elif CONFIG_IDF_TARGET_ESP32S2 + //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them. +#endif } -bool spicommon_dma_chan_free(int dma_chan) +#endif //#if !SOC_GDMA_SUPPORTED + +bool spicommon_dma_chan_in_use(int dma_chan) { +#if !SOC_GDMA_SUPPORTED + assert(dma_chan ==1 || dma_chan == 2); + return spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan); +#endif + return true; +} + +//----------------------------------------------------------alloc dma periph-------------------------------------------------------// +static esp_err_t spicommon_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan) +{ + uint32_t actual_tx_dma_chan = 0; + uint32_t actual_rx_dma_chan = 0; + esp_err_t ret = ESP_OK; + +#if !SOC_GDMA_SUPPORTED +//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + if (dma_chan < 0) { +#if CONFIG_IDF_TARGET_ESP32 + for (int i = 0; i < SOC_SPI_DMA_CHAN_NUM; i++) { + bool is_used = BIT(i) & spi_dma_channel_code; + if (!is_used) { + spi_dma_channel_code |= BIT(i); + actual_tx_dma_chan = i+1; + actual_rx_dma_chan = i+1; + break; + } + } + if (!actual_tx_dma_chan) { + SPI_CHECK(false, "no available dma channel", ESP_ERR_INVALID_STATE); + } +#elif CONFIG_IDF_TARGET_ESP32S2 + //On ESP32S2, each SPI controller has its own DMA channel. So DMA channel auto-allocation is not supported + SPI_CHECK(false, "ESP32S2 does not support auto-alloc dma channel", ESP_ERR_INVALID_STATE); +#endif //#if CONFIG_IDF_TARGET_XXX + } else if (dma_chan > 0) { + actual_tx_dma_chan = dma_chan; + actual_rx_dma_chan = dma_chan; + } else { //dma_chan == 0 + // Program won't reach here + abort(); + } + + bool dma_chan_claimed = spicommon_dma_chan_claim(actual_tx_dma_chan); + if (!dma_chan_claimed) { + spicommon_periph_free(host_id); + SPI_CHECK(false, "dma channel already in use", ESP_ERR_INVALID_STATE); + } + + spicommon_connect_spi_and_dma(host_id, actual_tx_dma_chan); + +#else //SOC_GDMA_SUPPORTED + + spicommon_bus_context_t *ctx = bus_ctx[host_id]; + + if (dma_chan < 0) { + gdma_channel_alloc_config_t tx_alloc_config = { + .flags.reserve_sibling = 1, + .direction = GDMA_CHANNEL_DIRECTION_TX, + }; + ret = gdma_new_channel(&tx_alloc_config, &ctx->tx_channel); + if (ret != ESP_OK) { + return ret; + } + + gdma_channel_alloc_config_t rx_alloc_config = { + .direction = GDMA_CHANNEL_DIRECTION_RX, + .sibling_chan = ctx->tx_channel, + }; + ret = gdma_new_channel(&rx_alloc_config, &ctx->rx_channel); + if (ret != ESP_OK) { + return ret; + } + + if (host_id == SPI1_HOST) { + SPI_CHECK(false, "SPI1 does not support DMA mode", ESP_ERR_INVALID_STATE); + } +#if (SOC_SPI_PERIPH_NUM >= 2) + else if (host_id == SPI2_HOST) { + gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2)); + gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2)); + } +#endif +#if (SOC_SPI_PERIPH_NUM >= 3) + else { + //host_id == SPI3_HOST + gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3)); + gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3)); + } +#endif + + gdma_get_channel_id(ctx->tx_channel, (int *)&actual_tx_dma_chan); + gdma_get_channel_id(ctx->rx_channel, (int *)&actual_rx_dma_chan); + + } else if (dma_chan > 0) { + SPI_CHECK(false, "specifying a DMA channel is not supported, please use dma auto-alloc mode", ESP_ERR_INVALID_STATE); + } else { //dma_chan == 0 + // Program won't reach here + } +#endif + + *out_actual_tx_dma_chan = actual_tx_dma_chan; + *out_actual_rx_dma_chan = actual_rx_dma_chan; + return ret; +} + +esp_err_t spicommon_slave_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan) +{ + esp_err_t ret = ESP_OK; + spicommon_bus_context_t *ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t)); + if (!ctx) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + bus_ctx[host_id] = ctx; + ctx->host_id = host_id; + + + ret = spicommon_alloc_dma(host_id, dma_chan, out_actual_tx_dma_chan, out_actual_rx_dma_chan); + if (ret != ESP_OK) { + goto cleanup; + } + return ret; + +cleanup: + free(ctx); + ctx = NULL; + return ret; +} + +//----------------------------------------------------------free dma periph-------------------------------------------------------// +static esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id, int dma_chan) +{ +#if !SOC_GDMA_SUPPORTED assert( dma_chan == 1 || dma_chan == 2 ); assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) ); @@ -199,80 +345,32 @@ bool spicommon_dma_chan_free(int dma_chan) periph_module_disable(get_dma_periph(dma_chan)); portEXIT_CRITICAL(&spi_dma_spinlock); - return true; -} - -static void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan) -{ -#if CONFIG_IDF_TARGET_ESP32 - DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2)); -#elif CONFIG_IDF_TARGET_ESP32S2 - //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them. -#elif SOC_GDMA_SUPPORTED - int gdma_chan, periph_id; - if (dma_chan == 1) { - gdma_chan = SOC_GDMA_SPI2_DMA_CHANNEL; - periph_id = SOC_GDMA_TRIG_PERIPH_SPI2; -#ifdef SOC_GDMA_TRIG_PERIPH_SPI3 - } else if (dma_chan == 2) { - gdma_chan = SOC_GDMA_SPI3_DMA_CHANNEL; - periph_id = SOC_GDMA_TRIG_PERIPH_SPI3; -#endif - } else { - abort(); +#else //SOC_GDMA_SUPPORTED + spicommon_bus_context_t *ctx = bus_ctx[host_id]; + if (ctx->rx_channel) { + gdma_disconnect(ctx->rx_channel); + gdma_del_channel(ctx->rx_channel); } - - spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id); - spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id); - spi_dma_set_rx_channel_priority(gdma_chan, 1); - spi_dma_set_tx_channel_priority(gdma_chan, 1); -#endif //#elif SOC_GDMA_SUPPORTED -} - -esp_err_t spicommon_alloc_dma(spi_host_device_t host_id, int dma_chan, uint32_t *out_actual_dma_chan) -{ - uint32_t actual_dma_chan = 0; - -#if !SOC_GDMA_SUPPORTED - if (dma_chan < 0) { -#if CONFIG_IDF_TARGET_ESP32 - for (int i = 0; i < SOC_SPI_DMA_CHAN_NUM; i++) { - bool is_used = BIT(i) & spi_dma_channel_code; - if (!is_used) { - spi_dma_channel_code |= BIT(i); - actual_dma_chan = i+1; - break; - } - } - if (!actual_dma_chan) { - SPI_CHECK(false, "no available dma channel", ESP_ERR_INVALID_STATE); - } -#elif CONFIG_IDF_TARGET_ESP32S2 - //On ESP32S2, each SPI controller has its own DMA channel. So DMA channel auto-allocation is not supported - SPI_CHECK(false, "ESP32S2 does not support auto-alloc dma channel", ESP_ERR_INVALID_STATE); -#endif //#if CONFIG_IDF_TARGET_XXX - } else if (dma_chan > 0) { - actual_dma_chan = dma_chan; - } else { //dma_chan == 0 - // Program won't reach here + if (ctx->tx_channel) { + gdma_disconnect(ctx->tx_channel); + gdma_del_channel(ctx->tx_channel); } - - bool dma_chan_claimed = spicommon_dma_chan_claim(actual_dma_chan); - if (!dma_chan_claimed) { - spicommon_periph_free(host_id); - SPI_CHECK(false, "dma channel already in use", ESP_ERR_INVALID_STATE); - } - - spicommon_connect_spi_and_dma(host_id, actual_dma_chan); - -#elif SOC_GDMA_SUPPORTED - #endif - *out_actual_dma_chan = actual_dma_chan; return ESP_OK; } +esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id, int dma_chan) +{ + esp_err_t ret = spicommon_dma_chan_free(host_id, dma_chan); + + free(bus_ctx[host_id]); + bus_ctx[host_id] = NULL; + + return ret; +} + +//----------------------------------------------------------IO general-------------------------------------------------------// static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config) { if (bus_config->sclk_io_num>=0 && @@ -304,7 +402,7 @@ Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pi bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value, it should be able to be initialized. */ -esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t* flags_o) +esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o) { uint32_t temp_flag = 0; @@ -535,12 +633,14 @@ static inline bool is_valid_host(spi_host_device_t host) return host >= SPI1_HOST && host <= SPI3_HOST; } +//----------------------------------------------------------master bus init-------------------------------------------------------// esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, int dma_chan) { esp_err_t err = ESP_OK; spicommon_bus_context_t *ctx = NULL; spi_bus_attr_t *bus_attr = NULL; - uint32_t actual_dma_chan = 0; + uint32_t actual_tx_dma_chan = 0; + uint32_t actual_rx_dma_chan = 0; SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG); SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE); @@ -549,7 +649,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * #elif CONFIG_IDF_TARGET_ESP32S2 SPI_CHECK( dma_chan == 0 || dma_chan == host_id, "invalid dma channel", ESP_ERR_INVALID_ARG ); #elif SOC_GDMA_SUPPORTED - SPI_CHECK( dma_chan == -1, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG ); + SPI_CHECK( dma_chan == 0 || dma_chan == -1, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG ); #endif SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG); #ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM @@ -565,16 +665,20 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * err = ESP_ERR_NO_MEM; goto cleanup; } + bus_ctx[host_id] = ctx; ctx->host_id = host_id; bus_attr = &ctx->bus_attr; bus_attr->bus_cfg = *bus_config; if (dma_chan != 0) { - err = spicommon_alloc_dma(host_id, dma_chan, &actual_dma_chan); + bus_attr->dma_enabled = 1; + + err = spicommon_alloc_dma(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan); if (err != ESP_OK) { - return err; + goto cleanup; } - bus_attr->dma_chan = actual_dma_chan; + bus_attr->tx_dma_chan = actual_tx_dma_chan; + bus_attr->rx_dma_chan = actual_rx_dma_chan; int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz); if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given @@ -588,6 +692,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * } bus_attr->dma_desc_num = dma_desc_ct; } else { + bus_attr->dma_enabled = 0; bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE; bus_attr->dma_desc_num = 0; } @@ -609,12 +714,11 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * } #endif //CONFIG_PM_ENABLE - err = spicommon_bus_initialize_io(host_id, bus_config, actual_dma_chan, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags); + err = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags); if (err != ESP_OK) { goto cleanup; } - bus_ctx[host_id] = ctx; return ESP_OK; cleanup: @@ -627,12 +731,15 @@ cleanup: } free(bus_attr->dmadesc_tx); free(bus_attr->dmadesc_rx); - } - free(ctx); - if (actual_dma_chan) { - spicommon_dma_chan_free(actual_dma_chan); + + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + if (bus_attr->dma_enabled) { + spicommon_dma_chan_free(host_id, actual_tx_dma_chan); + } } spicommon_periph_free(host_id); + free(bus_ctx[host_id]); + bus_ctx[host_id] = NULL; return err; } @@ -663,8 +770,10 @@ esp_err_t spi_bus_free(spi_host_device_t host_id) free(bus_attr->dmadesc_rx); free(bus_attr->dmadesc_tx); - if (bus_attr->dma_chan > 0) { - spicommon_dma_chan_free (bus_attr->dma_chan); + + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + if (bus_attr->dma_enabled > 0) { + spicommon_dma_chan_free (host_id, bus_attr->tx_dma_chan); } spicommon_periph_free(host_id); diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 00325c24d9..e1d9eb3243 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -231,17 +231,18 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id) } //assign the SPI, RX DMA and TX DMA peripheral registers beginning address - spi_hal_dma_config_t hal_dma_config = { + spi_hal_config_t hal_config = { //On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. Pass the registers of SPI peripheral to control it. .dma_in = SPI_LL_GET_HW(host_id), .dma_out = SPI_LL_GET_HW(host_id), + .dma_enabled = bus_attr->dma_enabled, .dmadesc_tx = bus_attr->dmadesc_tx, .dmadesc_rx = bus_attr->dmadesc_rx, - .dmadesc_n = bus_attr->dma_desc_num + .tx_dma_chan = bus_attr->tx_dma_chan, + .rx_dma_chan = bus_attr->rx_dma_chan, + .dmadesc_n = bus_attr->dma_desc_num, }; - - spi_hal_init(&host->hal, host_id, &hal_dma_config); - host->hal.dma_enabled = (bus_attr->dma_chan != 0); + spi_hal_init(&host->hal, host_id, &hal_config); if (host_id != SPI1_HOST) { //SPI1 attributes are already initialized at start up. @@ -606,8 +607,9 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg) //Okay, transaction is done. const int cs = host->cur_cs; //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. - if (bus_attr->dma_chan) { - spicommon_dmaworkaround_idle(bus_attr->dma_chan); + if (bus_attr->dma_enabled) { + //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same + spicommon_dmaworkaround_idle(bus_attr->tx_dma_chan); } //cur_cs is changed to DEV_NUM_MAX here @@ -658,9 +660,10 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg) if (trans_found) { spi_trans_priv_t *const cur_trans_buf = &host->cur_trans_buf; - if (bus_attr->dma_chan != 0 && (cur_trans_buf->buffer_to_rcv || cur_trans_buf->buffer_to_send)) { + if (bus_attr->dma_enabled && (cur_trans_buf->buffer_to_rcv || cur_trans_buf->buffer_to_send)) { //mark channel as active, so that the DMA will not be reset by the slave - spicommon_dmaworkaround_transfer_active(bus_attr->dma_chan); + //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same + spicommon_dmaworkaround_transfer_active(bus_attr->tx_dma_chan); } spi_new_trans(device_to_send, cur_trans_buf); } @@ -693,7 +696,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG); SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "incompatible iface params", ESP_ERR_INVALID_ARG); #ifdef CONFIG_IDF_TARGET_ESP32 - SPI_CHECK(!is_half_duplex || bus_attr->dma_chan == 0 || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG ); + SPI_CHECK(!is_half_duplex || !bus_attr->dma_enabled || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG ); #elif CONFIG_IDF_TARGET_ESP32S3 SPI_CHECK(!is_half_duplex || !tx_enabled || !rx_enabled, "SPI half duplex mode is not supported when both MOSI and MISO phases are enabled.", ESP_ERR_INVALID_ARG); #endif @@ -788,7 +791,7 @@ esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE ); spi_trans_priv_t trans_buf; - ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_chan!=0)); + ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled)); if (ret != ESP_OK) return ret; #ifdef CONFIG_PM_ENABLE @@ -877,8 +880,9 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_acquire_bus(spi_device_t *device, TickT //configure the device ahead so that we don't need to do it again in the following transactions spi_setup_device(host->device[device->id]); //the DMA is also occupied by the device, all the slave devices that using DMA should wait until bus released. - if (host->bus_attr->dma_chan != 0) { - spicommon_dmaworkaround_transfer_active(host->bus_attr->dma_chan); + if (host->bus_attr->dma_enabled) { + //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same + spicommon_dmaworkaround_transfer_active(host->bus_attr->tx_dma_chan); } return ESP_OK; } @@ -893,8 +897,9 @@ void SPI_MASTER_ISR_ATTR spi_device_release_bus(spi_device_t *dev) assert(0); } - if (host->bus_attr->dma_chan != 0) { - spicommon_dmaworkaround_idle(host->bus_attr->dma_chan); + if (host->bus_attr->dma_enabled) { + //This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same + spicommon_dmaworkaround_idle(host->bus_attr->tx_dma_chan); } //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. @@ -928,7 +933,7 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl } if (ret != ESP_OK) return ret; - ret = setup_priv_desc(trans_desc, &host->cur_trans_buf, (host->bus_attr->dma_chan!=0)); + ret = setup_priv_desc(trans_desc, &host->cur_trans_buf, (host->bus_attr->dma_enabled)); if (ret!=ESP_OK) return ret; //Polling, no interrupt is used. diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index d91b3b3137..e7765e2920 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -67,7 +67,9 @@ typedef struct { int max_transfer_sz; QueueHandle_t trans_queue; QueueHandle_t ret_queue; - int dma_chan; + bool dma_enabled; + uint32_t tx_dma_chan; + uint32_t rx_dma_chan; #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif @@ -111,7 +113,8 @@ static inline void restore_cs(spi_slave_t *host) esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan) { bool spi_chan_claimed; - uint32_t actual_dma_chan = 0; + uint32_t actual_tx_dma_chan = 0; + uint32_t actual_rx_dma_chan = 0; esp_err_t ret = ESP_OK; esp_err_t err; //We only support HSPI/VSPI, period. @@ -121,7 +124,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b #elif CONFIG_IDF_TARGET_ESP32S2 SPI_CHECK( dma_chan == 0 || dma_chan == host, "invalid dma channel", ESP_ERR_INVALID_ARG ); #elif SOC_GDMA_SUPPORTED - SPI_CHECK( dma_chan == -1, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG ); + SPI_CHECK( dma_chan == 0 || dma_chan == -1, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG ); #endif SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG); #ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM @@ -132,14 +135,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b spi_chan_claimed=spicommon_periph_claim(host, "spi slave"); SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE); - bool use_dma = (dma_chan != 0); - if (use_dma) { - err = spicommon_alloc_dma(host, dma_chan, &actual_dma_chan); - if (err != ESP_OK) { - return err; - } - } - spihost[host] = malloc(sizeof(spi_slave_t)); if (spihost[host] == NULL) { ret = ESP_ERR_NO_MEM; @@ -149,7 +144,16 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t)); spihost[host]->id = host; - err = spicommon_bus_initialize_io(host, bus_config, actual_dma_chan, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags); + bool use_dma = (dma_chan != 0); + spihost[host]->dma_enabled = use_dma; + if (use_dma) { + ret = spicommon_slave_alloc_dma(host, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan); + if (ret != ESP_OK) { + goto cleanup; + } + } + + err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags); if (err!=ESP_OK) { ret = err; goto cleanup; @@ -162,7 +166,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b if (use_dma) freeze_cs(spihost[host]); int dma_desc_ct = 0; - spihost[host]->dma_chan = actual_dma_chan; + spihost[host]->tx_dma_chan = actual_tx_dma_chan; + spihost[host]->rx_dma_chan = actual_rx_dma_chan; if (use_dma) { //See how many dma descriptors we need and allocate them dma_desc_ct = (bus_config->max_transfer_sz + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN; @@ -220,6 +225,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b hal->tx_lsbfirst = (slave_config->flags & SPI_SLAVE_TXBIT_LSBFIRST) ? 1 : 0; hal->mode = slave_config->mode; hal->use_dma = use_dma; + hal->tx_dma_chan = actual_tx_dma_chan; + hal->rx_dma_chan = actual_rx_dma_chan; spi_slave_hal_setup_device(hal); @@ -239,10 +246,15 @@ cleanup: #endif } spi_slave_hal_deinit(&spihost[host]->hal); + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + if (spihost[host]->dma_enabled) { + spicommon_slave_free_dma(host, actual_tx_dma_chan); + } + free(spihost[host]); spihost[host] = NULL; spicommon_periph_free(host); - if (actual_dma_chan != 0) spicommon_dma_chan_free(actual_dma_chan); + return ret; } @@ -252,8 +264,9 @@ esp_err_t spi_slave_free(spi_host_device_t host) SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG); if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue); if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue); - if ( spihost[host]->dma_chan > 0 ) { - spicommon_dma_chan_free ( spihost[host]->dma_chan ); + if (spihost[host]->dma_enabled) { + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + spicommon_slave_free_dma(host, spihost[host]->tx_dma_chan); } free(spihost[host]->hal.dmadesc_tx); free(spihost[host]->hal.dmadesc_rx); @@ -274,9 +287,9 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi BaseType_t r; SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG); SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG); - SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer), + SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer), "txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG); - SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || + SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->rx_buffer==NULL || (esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) && (trans_desc->length%4==0)), "rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG); @@ -332,7 +345,7 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) assert(spi_slave_hal_usr_is_done(hal)); - bool use_dma = host->dma_chan != 0; + bool use_dma = host->dma_enabled; if (host->cur_trans) { // When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready. if (use_dma) freeze_cs(host); @@ -341,7 +354,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) host->cur_trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal); if (spi_slave_hal_dma_need_reset(hal)) { - spicommon_dmaworkaround_req_reset(host->dma_chan, spi_slave_restart_after_dmareset, host); + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + spicommon_dmaworkaround_req_reset(host->tx_dma_chan, spi_slave_restart_after_dmareset, host); } if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans); //Okay, transaction is done. @@ -350,7 +364,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) host->cur_trans = NULL; } if (use_dma) { - spicommon_dmaworkaround_idle(host->dma_chan); + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + spicommon_dmaworkaround_idle(host->tx_dma_chan); if (spicommon_dmaworkaround_reset_in_progress()) { //We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr. esp_intr_disable(host->intr); @@ -375,7 +390,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) hal->tx_buffer = trans->tx_buffer; if (use_dma) { - spicommon_dmaworkaround_transfer_active(host->dma_chan); + //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + spicommon_dmaworkaround_transfer_active(host->tx_dma_chan); } spi_slave_hal_prepare_data(hal); diff --git a/components/driver/spi_slave_hd.c b/components/driver/spi_slave_hd.c index 86a872320f..fbb521c199 100644 --- a/components/driver/spi_slave_hd.c +++ b/components/driver/spi_slave_hd.c @@ -28,7 +28,9 @@ #define SPIHD_CHECK(cond,warn,ret) do{if(!(cond)){ESP_LOGE(TAG, warn); return ret;}} while(0) typedef struct { - int dma_chan; + bool dma_enabled; + uint32_t tx_dma_chan; + uint32_t rx_dma_chan; int max_transfer_sz; uint32_t flags; portMUX_TYPE int_spinlock; @@ -66,14 +68,15 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b { bool spi_chan_claimed; bool append_mode = (config->flags & SPI_SLAVE_HD_APPEND_MODE); - uint32_t actual_dma_chan = 0; + uint32_t actual_tx_dma_chan = 0; + uint32_t actual_rx_dma_chan = 0; esp_err_t ret = ESP_OK; SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG); #if CONFIG_IDF_TARGET_ESP32S2 SPIHD_CHECK(config->dma_chan == 0 || config->dma_chan == host_id, "invalid dma channel", ESP_ERR_INVALID_ARG); #elif SOC_GDMA_SUPPORTED - SPI_CHECK(dma_chan == -1, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG); + SPIHD_CHECK(config->dma_chan == 0 || config->dma_chan == -1, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG); #endif #if !CONFIG_IDF_TARGET_ESP32S2 //Append mode is only supported on ESP32S2 now @@ -83,13 +86,6 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b spi_chan_claimed = spicommon_periph_claim(host_id, "slave_hd"); SPIHD_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE); - if (config->dma_chan != 0) { - ret = spicommon_alloc_dma(host_id, config->dma_chan, &actual_dma_chan); - if (ret != ESP_OK) { - return ret; - } - } - spi_slave_hd_slot_t* host = malloc(sizeof(spi_slave_hd_slot_t)); if (host == NULL) { ret = ESP_ERR_NO_MEM; @@ -97,12 +93,20 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b } spihost[host_id] = host; memset(host, 0, sizeof(spi_slave_hd_slot_t)); - - host->dma_chan = actual_dma_chan; host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + host->dma_enabled = (config->dma_chan != 0); - ret = spicommon_bus_initialize_io(host_id, bus_config, actual_dma_chan, - SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags); + if (host->dma_enabled) { + ret = spicommon_slave_alloc_dma(host_id, config->dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan); + if (ret != ESP_OK) { + goto cleanup; + } + } + + host->tx_dma_chan = actual_tx_dma_chan; + host->rx_dma_chan = actual_rx_dma_chan; + + ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags); if (ret != ESP_OK) { goto cleanup; } @@ -115,14 +119,16 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b .host_id = host_id, .dma_in = SPI_LL_GET_HW(host_id), .dma_out = SPI_LL_GET_HW(host_id), - .dma_chan = actual_dma_chan, + .dma_enabled = host->dma_enabled, + .tx_dma_chan = host->tx_dma_chan, + .rx_dma_chan = host->rx_dma_chan, .append_mode = append_mode, .mode = config->mode, .tx_lsbfirst = (config->flags & SPI_SLAVE_HD_RXBIT_LSBFIRST), .rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST), }; - if (actual_dma_chan != 0) { + if (host->dma_enabled) { //Malloc for all the DMA descriptors uint32_t total_desc_size = spi_slave_hd_hal_get_total_desc_size(&host->hal, bus_config->max_transfer_sz); host->hal.dmadesc_tx = heap_caps_malloc(total_desc_size, MALLOC_CAP_DMA); @@ -245,8 +251,9 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id) } spicommon_periph_free(host_id); - if (host->dma_chan) { - spicommon_dma_chan_free(host->dma_chan); + if (host->dma_enabled) { + //On ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same + spicommon_slave_free_dma(host_id, host->tx_dma_chan); } free(host); spihost[host_id] = NULL; diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index d8081ef667..99a0967625 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -946,9 +946,10 @@ static inline void spi_ll_enable_int(spi_dev_t *hw) /** * Reset RX DMA which stores the data received from a peripheral into RAM. * - * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel */ -static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in) +static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel) { //Reset RX DMA peripheral dma_in->dma_conf.in_rst = 1; @@ -958,10 +959,11 @@ static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in) /** * Start RX DMA. * - * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. - * @param addr Address of the beginning DMA descriptor. + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel + * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr) +static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr) { dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; dma_in->dma_in_link.start = 1; @@ -971,9 +973,10 @@ static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr) * Enable DMA RX channel burst for data * * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_in, bool enable) +static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_in, uint32_t channel, bool enable) { //This is not supported in esp32 } @@ -982,9 +985,10 @@ static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_in, bool e * Enable DMA RX channel burst for descriptor * * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, bool enable) +static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, uint32_t channel, bool enable) { dma_in->dma_conf.indscr_burst_en = enable; } @@ -993,8 +997,9 @@ static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, bool e * Reset TX DMA 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 */ -static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out) +static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel) { //Reset TX DMA peripheral dma_out->dma_conf.out_rst = 1; @@ -1005,9 +1010,10 @@ static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out) * Start TX DMA. * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr) +static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr) { dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; dma_out->dma_out_link.start = 1; @@ -1017,9 +1023,10 @@ static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr) * Enable DMA TX channel burst for data * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.out_data_burst_en = enable; } @@ -1028,9 +1035,10 @@ static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, bool * Enable DMA TX channel burst for descriptor * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.outdscr_burst_en = enable; } @@ -1039,9 +1047,10 @@ static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, bool * Configuration of OUT EOF flag generation way * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable 1: when dma pop all data from fifo 0:when ahb push all data to fifo. */ -static inline void spi_dma_ll_set_out_eof_generation(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_set_out_eof_generation(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.out_eof_mode = enable; } @@ -1050,9 +1059,10 @@ static inline void spi_dma_ll_set_out_eof_generation(spi_dma_dev_t *dma_out, boo * Enable automatic outlink-writeback * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { //does not configure it in ESP32 } diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index 022cc3f316..6a1090a34c 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -1080,10 +1080,10 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t* hw) /** * Reset RX DMA which stores the data received from a peripheral into RAM. * - * @param hw Beginning address of the peripheral registers. - * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel */ -static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in) +static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel) { //Reset RX DMA peripheral dma_in->dma_in_link.dma_rx_ena = 0; @@ -1096,10 +1096,11 @@ static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in) /** * Start RX DMA. * - * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. - * @param addr Address of the beginning DMA descriptor. + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel + * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr) +static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr) { dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; dma_in->dma_in_link.start = 1; @@ -1109,9 +1110,10 @@ static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr) * Enable DMA RX channel burst for data * * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_in, bool enable) +static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_in, uint32_t channel, bool enable) { //This is not supported in esp32s2 } @@ -1119,10 +1121,11 @@ static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_in, bool e /** * Enable DMA TX channel burst for descriptor * - * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, bool enable) +static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, uint32_t channel, bool enable) { dma_in->dma_conf.indscr_burst_en = enable; } @@ -1130,10 +1133,10 @@ static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, bool e /** * Reset TX DMA which transmits the data from RAM to a peripheral. * - * @param hw Beginning address of the peripheral registers. * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel */ -static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out) +static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel) { //Reset TX DMA peripheral dma_out->dma_conf.out_rst = 1; @@ -1144,9 +1147,10 @@ static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out) * Start TX DMA. * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. - * @param addr Address of the beginning DMA descriptor. + * @param channel DMA channel + * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr) +static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr) { dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; dma_out->dma_out_link.start = 1; @@ -1156,9 +1160,10 @@ static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr) * Enable DMA TX channel burst for data * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.out_data_burst_en = enable; } @@ -1167,9 +1172,10 @@ static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, bool * Enable DMA TX channel burst for descriptor * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.outdscr_burst_en = enable; } @@ -1178,9 +1184,10 @@ static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, bool * Configuration of OUT EOF flag generation way * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable 1: when dma pop all data from fifo 0:when ahb push all data to fifo. */ -static inline void spi_dma_ll_set_out_eof_generation(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_set_out_eof_generation(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.out_eof_mode = enable; } @@ -1189,19 +1196,20 @@ static inline void spi_dma_ll_set_out_eof_generation(spi_dma_dev_t *dma_out, boo * Enable automatic outlink-writeback * * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @param channel DMA channel * @param enable True to enable, false to disable */ -static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, bool enable) +static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, uint32_t channel, bool enable) { dma_out->dma_conf.out_auto_wrback = enable; } -static inline void spi_dma_ll_rx_restart(spi_dma_dev_t *dma_in) +static inline void spi_dma_ll_rx_restart(spi_dma_dev_t *dma_in, uint32_t channel) { dma_in->dma_in_link.restart = 1; } -static inline void spi_dma_ll_tx_restart(spi_dma_dev_t *dma_out) +static inline void spi_dma_ll_tx_restart(spi_dma_dev_t *dma_out, uint32_t channel) { dma_out->dma_out_link.restart = 1; } diff --git a/components/hal/include/hal/spi_hal.h b/components/hal/include/hal/spi_hal.h index bba02465ef..ec23ee0d1a 100644 --- a/components/hal/include/hal/spi_hal.h +++ b/components/hal/include/hal/spi_hal.h @@ -72,6 +72,7 @@ typedef struct { typedef struct { 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; ///< Whether the DMA is enabled, do not update after initialization lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. * The amount should be larger than dmadesc_n. The driver should ensure that * the data to be sent is shorter than the descriptors can hold. @@ -80,8 +81,10 @@ typedef struct { * The amount should be larger than dmadesc_n. The driver should ensure that * the data to be sent is shorter than the descriptors can hold. */ + uint32_t tx_dma_chan; ///< TX DMA channel + uint32_t rx_dma_chan; ///< RX DMA channel int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use. -} spi_hal_dma_config_t; +} spi_hal_config_t; /** * Transaction configuration structure, this should be assigned by driver each time. @@ -104,12 +107,24 @@ typedef struct { * Context that should be maintained by both the driver and the HAL. */ typedef struct { + /* These two need to be malloced by the driver first */ + lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA. + * The amount should be larger than dmadesc_n. The driver should ensure that + * the data to be sent is shorter than the descriptors can hold. + */ + lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA. + * The amount should be larger than dmadesc_n. The driver should ensure that + * the data to be sent is shorter than the descriptors can hold. + */ + /* Configured by driver at initialization, don't touch */ 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 (DMA -> RAM). spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA). bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization - spi_hal_dma_config_t dma_config; ///< DMA configuration + uint32_t tx_dma_chan; ///< TX DMA channel + uint32_t rx_dma_chan; ///< RX DMA channel + int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use. /* Internal parameters, don't touch */ spi_hal_trans_config_t trans_config; ///< Transaction configuration @@ -144,10 +159,11 @@ typedef struct { /** * Init the peripheral and the context. * - * @param hal Context of the HAL layer. - * @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3). + * @param hal Context of the HAL layer. + * @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3). + * @param hal_config Configuration of the hal defined by the upper layer. */ -void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_dma_config_t *hal_dma_config); +void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *hal_config); /** * Deinit the peripheral (and the context if needed). diff --git a/components/hal/include/hal/spi_slave_hal.h b/components/hal/include/hal/spi_slave_hal.h index b6d2ad5b35..ba03c28b7f 100644 --- a/components/hal/include/hal/spi_slave_hal.h +++ b/components/hal/include/hal/spi_slave_hal.h @@ -55,7 +55,9 @@ typedef struct { * The amount should be larger than dmadesc_n. The driver should ensure that * 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 diff --git a/components/hal/include/hal/spi_slave_hd_hal.h b/components/hal/include/hal/spi_slave_hd_hal.h index 5c8458c9e9..de38ee42fa 100644 --- a/components/hal/include/hal/spi_slave_hd_hal.h +++ b/components/hal/include/hal/spi_slave_hd_hal.h @@ -70,7 +70,9 @@ typedef struct { 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 - uint32_t dma_chan; ///< The dma channel used. + 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 uint32_t spics_io_num; ///< CS GPIO pin for this device uint8_t mode; ///< SPI mode (0-3) @@ -94,7 +96,9 @@ typedef struct { 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 + 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 uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``. spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up). diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index c76529d7cf..b5b6e2168a 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -22,12 +22,12 @@ #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); +#define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); +#define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); +#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); #endif static const char SPI_HAL_TAG[] = "spi_hal"; @@ -39,19 +39,25 @@ static const char SPI_HAL_TAG[] = "spi_hal"; static void s_spi_hal_dma_init_config(const spi_hal_context_t *hal) { - spi_dma_ll_rx_enable_burst_data(hal->dma_in, 1); - spi_dma_ll_tx_enable_burst_data(hal->dma_out, 1); - spi_dma_ll_rx_enable_burst_desc(hal->dma_in, 1); - spi_dma_ll_tx_enable_burst_desc(hal->dma_out, 1); + spi_dma_ll_rx_enable_burst_data(hal->dma_in, hal->rx_dma_chan, 1); + spi_dma_ll_tx_enable_burst_data(hal->dma_out, hal->tx_dma_chan, 1); + spi_dma_ll_rx_enable_burst_desc(hal->dma_in, hal->rx_dma_chan, 1); + spi_dma_ll_tx_enable_burst_desc(hal->dma_out, hal->tx_dma_chan ,1); } -void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_dma_config_t *dma_config) +void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *config) { memset(hal, 0, sizeof(spi_hal_context_t)); spi_dev_t *hw = SPI_LL_GET_HW(host_id); hal->hw = hw; - hal->dma_in = dma_config->dma_in; - hal->dma_out = dma_config->dma_out; + hal->dma_in = config->dma_in; + hal->dma_out = config->dma_out; + hal->dma_enabled = config->dma_enabled; + hal->dmadesc_tx = config->dmadesc_tx; + hal->dmadesc_rx = config->dmadesc_rx; + hal->tx_dma_chan = config->tx_dma_chan; + hal->rx_dma_chan = config->rx_dma_chan; + hal->dmadesc_n = config->dmadesc_n; spi_ll_master_init(hw); s_spi_hal_dma_init_config(hal); @@ -63,9 +69,6 @@ void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_dma_co spi_ll_enable_int(hw); spi_ll_set_int_stat(hw); spi_ll_set_mosi_delay(hw, 0, 0); - - //Save the dma configuration in ``spi_hal_context_t`` - memcpy(&hal->dma_config, dma_config, sizeof(spi_hal_dma_config_t)); } void spi_hal_deinit(spi_hal_context_t *hal) diff --git a/components/hal/spi_hal_iram.c b/components/hal/spi_hal_iram.c index 821c26e543..dcbbe4753c 100644 --- a/components/hal/spi_hal_iram.c +++ b/components/hal/spi_hal_iram.c @@ -23,15 +23,15 @@ #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL) -#define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL); -#define spi_dma_ll_rx_start(dev, addr) do {\ - gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL);\ +#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, addr) do {\ - gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL);\ +#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) #endif @@ -143,12 +143,12 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de if (!hal->dma_enabled) { //No need to setup anything; we'll copy the result out of the work registers directly later. } else { - lldesc_setup_link(hal->dma_config.dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); + lldesc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true); - spi_dma_ll_rx_reset(hal->dma_in); + spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan); spi_ll_dma_rx_fifo_reset(hal->dma_in); spi_ll_dma_rx_enable(hal->hw, 1); - spi_dma_ll_rx_start(hal->dma_in, hal->dma_config.dmadesc_rx); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, hal->dmadesc_rx); } } @@ -157,7 +157,7 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de //DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon if (hal->dma_enabled && !dev->half_duplex) { spi_ll_dma_rx_enable(hal->hw, 1); - spi_dma_ll_rx_start(hal->dma_in, 0); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, 0); } } #endif @@ -167,12 +167,12 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de //Need to copy data to registers manually spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen); } else { - lldesc_setup_link(hal->dma_config.dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); + lldesc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false); - spi_dma_ll_tx_reset(hal->dma_out); + spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan); spi_ll_dma_tx_fifo_reset(hal->dma_in); spi_ll_dma_tx_enable(hal->hw, 1); - spi_dma_ll_tx_start(hal->dma_out, hal->dma_config.dmadesc_tx); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, hal->dmadesc_tx); } } diff --git a/components/hal/spi_slave_hal.c b/components/hal/spi_slave_hal.c index 1b4beddf36..04982f1a7e 100644 --- a/components/hal/spi_slave_hal.c +++ b/components/hal/spi_slave_hal.c @@ -7,20 +7,20 @@ #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); +#define spi_dma_ll_rx_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); +#define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); +#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); #endif static void s_spi_slave_hal_dma_init_config(const spi_slave_hal_context_t *hal) { - spi_dma_ll_rx_enable_burst_data(hal->dma_in, 1); - spi_dma_ll_tx_enable_burst_data(hal->dma_out, 1); - spi_dma_ll_rx_enable_burst_desc(hal->dma_in, 1); - spi_dma_ll_tx_enable_burst_desc(hal->dma_out, 1); + spi_dma_ll_rx_enable_burst_data(hal->dma_in, hal->rx_dma_chan, 1); + spi_dma_ll_tx_enable_burst_data(hal->dma_out, hal->tx_dma_chan, 1); + spi_dma_ll_rx_enable_burst_desc(hal->dma_in, hal->rx_dma_chan, 1); + spi_dma_ll_tx_enable_burst_desc(hal->dma_out, hal->tx_dma_chan, 1); } void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config) diff --git a/components/hal/spi_slave_hal_iram.c b/components/hal/spi_slave_hal_iram.c index dbfe9f070e..5fb3f4dd1a 100644 --- a/components/hal/spi_slave_hal_iram.c +++ b/components/hal/spi_slave_hal_iram.c @@ -7,15 +7,15 @@ #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL) -#define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL); -#define spi_dma_ll_rx_start(dev, addr) do {\ - gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ +#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, addr) do {\ - gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ +#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) #endif @@ -39,24 +39,24 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) lldesc_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); + 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->dmadesc_rx[0]); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->dmadesc_rx[0]); } if (hal->tx_buffer) { lldesc_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); + 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->dmadesc_tx[0])); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (&hal->dmadesc_tx[0])); } } else { //No DMA. Turn off SPI and copy data to transmit buffers. diff --git a/components/hal/spi_slave_hd_hal.c b/components/hal/spi_slave_hd_hal.c index 3727bb15eb..fe1054441c 100644 --- a/components/hal/spi_slave_hd_hal.c +++ b/components/hal/spi_slave_hd_hal.c @@ -29,31 +29,31 @@ #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL) -#define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL); -#define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_rx_start(dev, addr) do {\ - gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ +#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_enable_burst_data(dev, chan, enable) gdma_ll_rx_enable_data_burst(&GDMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_data(dev, chan, enable) gdma_ll_tx_enable_data_burst(&GDMA, chan, enable); +#define spi_dma_ll_rx_enable_burst_desc(dev, chan, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, chan, enable); +#define spi_dma_ll_tx_enable_burst_desc(dev, chan, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, chan, enable); +#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_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, addr) do {\ - gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ +#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) #endif static void s_spi_slave_hd_hal_dma_init_config(const spi_slave_hd_hal_context_t *hal) { - spi_dma_ll_rx_enable_burst_data(hal->dma_in, 1); - spi_dma_ll_tx_enable_burst_data(hal->dma_out, 1); - spi_dma_ll_rx_enable_burst_desc(hal->dma_in, 1); - spi_dma_ll_tx_enable_burst_desc(hal->dma_out, 1); - spi_dma_ll_enable_out_auto_wrback(hal->dma_out, 1); + spi_dma_ll_rx_enable_burst_data(hal->dma_in, hal->rx_dma_chan, 1); + spi_dma_ll_tx_enable_burst_data(hal->dma_out, hal->tx_dma_chan, 1); + spi_dma_ll_rx_enable_burst_desc(hal->dma_in, hal->rx_dma_chan, 1); + spi_dma_ll_tx_enable_burst_desc(hal->dma_out, hal->tx_dma_chan, 1); + spi_dma_ll_enable_out_auto_wrback(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) @@ -62,6 +62,9 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h 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->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->rx_cur_desc = hal->dmadesc_rx; hal->tx_cur_desc = hal->dmadesc_tx; @@ -75,7 +78,7 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h spi_ll_set_dummy(hw, hal_config->dummy_bits); spi_ll_set_rx_lsbfirst(hw, hal_config->rx_lsbfirst); spi_ll_set_tx_lsbfirst(hw, hal_config->tx_lsbfirst); - spi_ll_slave_set_mode(hw, hal_config->mode, (hal_config->dma_chan != 0)); + spi_ll_slave_set_mode(hw, hal_config->mode, (hal_config->dma_enabled)); spi_ll_disable_intr(hw, UINT32_MAX); spi_ll_clear_intr(hw, UINT32_MAX); @@ -134,14 +137,14 @@ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, s lldesc_setup_link(&hal->dmadesc_rx->desc, out_buf, len, true); spi_ll_dma_rx_fifo_reset(hal->dev); - spi_dma_ll_rx_reset(hal->dma_in); + 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_clear_intr(hal->dev, SPI_LL_INTR_CMD7); spi_ll_slave_set_rx_bitlen(hal->dev, len * 8); spi_ll_dma_rx_enable(hal->dev, 1); - spi_dma_ll_rx_start(hal->dma_in, &hal->dmadesc_rx->desc); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->dmadesc_rx->desc); } void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len) @@ -149,13 +152,13 @@ void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size lldesc_setup_link(&hal->dmadesc_tx->desc, data, len, false); spi_ll_dma_tx_fifo_reset(hal->dev); - spi_dma_ll_tx_reset(hal->dma_out); + 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_clear_intr(hal->dev, SPI_LL_INTR_CMD8); spi_ll_dma_tx_enable(hal->dev, 1); - spi_dma_ll_tx_start(hal->dma_out, &hal->dmadesc_tx->desc); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, &hal->dmadesc_tx->desc); } static spi_ll_intr_t get_event_intr(spi_slave_hd_hal_context_t *hal, spi_event_t ev) @@ -333,18 +336,18 @@ esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t hal->tx_dma_head = hal->tx_cur_desc; hal->tx_dma_tail = hal->tx_cur_desc; - spi_dma_ll_tx_reset(hal->dma_out); + spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan); spi_ll_outfifo_empty_clr(hal->dev); spi_ll_clear_intr(hal->dev, SPI_LL_INTR_OUT_EOF); spi_ll_dma_tx_enable(hal->dev, 1); - spi_dma_ll_tx_start(hal->dma_out, &hal->tx_dma_head->desc); + spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, &hal->tx_dma_head->desc); } else { //there is already a link STAILQ_NEXT(&hal->tx_dma_tail->desc, qe) = &hal->tx_cur_desc->desc; hal->tx_dma_tail = hal->tx_cur_desc; - spi_dma_ll_tx_restart(hal->dma_out); + 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 @@ -376,18 +379,18 @@ esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t hal->rx_dma_head = hal->rx_cur_desc; hal->rx_dma_tail = hal->rx_cur_desc; - spi_dma_ll_rx_reset(hal->dma_in); + spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan); 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_dma_ll_rx_start(hal->dma_in, &hal->rx_dma_head->desc); + spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->rx_dma_head->desc); } else { //there is already a link STAILQ_NEXT(&hal->rx_dma_tail->desc, qe) = &hal->rx_cur_desc->desc; hal->rx_dma_tail = hal->rx_cur_desc; - spi_dma_ll_rx_restart(hal->dma_in); + 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 diff --git a/components/soc/esp32c3/include/soc/spi_caps.h b/components/soc/esp32c3/include/soc/spi_caps.h index c3578456d8..fefb464f6f 100644 --- a/components/soc/esp32c3/include/soc/spi_caps.h +++ b/components/soc/esp32c3/include/soc/spi_caps.h @@ -14,7 +14,7 @@ #pragma once -#define SOC_SPI_PERIPH_NUM 4 +#define SOC_SPI_PERIPH_NUM 2 #define SOC_SPI_DMA_CHAN_NUM 3 #define SOC_SPI_PERIPH_CS_NUM(i) 3