diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index b7f8581fda5..11fabd18795 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -15,6 +15,7 @@ #include "esp_heap_caps.h" #include "esp_memory_utils.h" #include "esp_macros.h" +#include "freertos/FreeRTOS.h" #include "driver/spi_master.h" #include "driver/gpio.h" #include "esp_private/gpio.h" @@ -29,12 +30,9 @@ #include "esp_private/sleep_retention.h" #include "hal/spi_hal.h" #if SOC_GDMA_SUPPORTED -#include "hal/gdma_ll.h" -#endif -#include "freertos/FreeRTOS.h" -#if CONFIG_IDF_TARGET_ESP32 -#include "soc/dport_reg.h" +#include "hal/gdma_ll.h" // for GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE #endif + #if CONFIG_SPIRAM #include "esp_private/mspi_mem_barrier.h" #endif @@ -198,15 +196,6 @@ static bool claim_dma_chan(int dma_chan, uint32_t *out_actual_dma_chan) return ret; } -static void 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. -#endif -} - static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t dma_burst_size, spi_dma_ctx_t *dma_ctx) { assert(is_valid_host(host_id)); @@ -248,7 +237,7 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch if (!success) { SPI_CHECK(false, "no available dma channel", ESP_ERR_NOT_FOUND); } - connect_spi_and_dma(host_id, actual_dma_chan); + spi_ll_dma_connect_host(host_id, actual_dma_chan); spi_dma_enable_burst(dma_ctx->tx_dma_chan, true, true); spi_dma_enable_burst(dma_ctx->rx_dma_chan, true, true); @@ -526,6 +515,7 @@ esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id) assert(spi_dma_chan_enabled & BIT(dma_chan)); portENTER_CRITICAL(&spi_dma_spinlock); + spi_ll_dma_disconnect_host(host_id); spi_dma_chan_enabled &= ~BIT(dma_chan); _spicommon_dma_rcc_clock_ctrl(dma_chan, false); portEXIT_CRITICAL(&spi_dma_spinlock); diff --git a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c index 57f9dc11624..fc61427f334 100644 --- a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c +++ b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c @@ -803,6 +803,39 @@ TEST_CASE("SPI Master no response when switch from host1 (SPI2) to host2 (SPI3)" TEST_ESP_OK(spi_bus_free(host)); } +#if !SOC_GDMA_SUPPORTED +TEST_CASE("SPI DMA data error when switch between SPI2 and SPI3", "[spi]") +{ + spi_device_handle_t dev_handle; + spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + buscfg.miso_io_num = buscfg.mosi_io_num; + spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); + uint8_t send[13] = "hello spi x\n"; + uint8_t recv[16]; // esp32 dma rx need requirse 4 byte aligned length + spi_transaction_t trans_cfg = { + .length = 8 * sizeof(send), + .tx_buffer = send, + .rx_buffer = recv, + }; + + for (int periph = SPI2_HOST; periph < SPI_HOST_MAX; periph ++) { + printf("Test GPSPI%d\n", periph + 1); + TEST_ESP_OK(spi_bus_initialize(periph, &buscfg, SPI_DMA_CH_AUTO)); + TEST_ESP_OK(spi_bus_add_device(periph, &devcfg, &dev_handle)); + + for (uint8_t cnt = 0; cnt < 2; cnt ++) { + memset(recv, 0, sizeof(recv)); + send[10] = cnt + 'A'; + TEST_ESP_OK(spi_device_transmit(dev_handle, &trans_cfg)); + printf("%s", recv); + spitest_cmp_or_dump(trans_cfg.tx_buffer, trans_cfg.rx_buffer, sizeof(send)); + } + TEST_ESP_OK(spi_bus_remove_device(dev_handle)); + TEST_ESP_OK(spi_bus_free(periph)); + } +} +#endif + DRAM_ATTR static uint32_t data_dram[80] = {0}; //force to place in code area. static const uint8_t data_drom[320 + 3] = { diff --git a/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h index e3f2fa9ab37..ebf5e02c8ad 100644 --- a/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32/include/hal/spi_ll.h @@ -1136,6 +1136,27 @@ static inline void spi_ll_dma_reset_register(spi_host_device_t host_id) spi_ll_dma_reset_register(__VA_ARGS__); \ } while(0) +/** + * Connect DMA channel for SPI + * + * @param host_id SPI host ID + * @param dma_chan DMA channel ID + */ +static inline void spi_ll_dma_connect_host(spi_host_device_t host_id, int dma_chan) +{ + DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host_id * 2)); +} + +/** + * Disconnect DMA channel for SPI + * + * @param host_id SPI host ID + */ +static inline void spi_ll_dma_disconnect_host(spi_host_device_t host_id) +{ + DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, 0, (host_id * 2)); +} + /** * Reset RX DMA which stores the data received from a peripheral into RAM. * diff --git a/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h b/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h index 4f461a24e4d..1642912c7cc 100644 --- a/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h +++ b/components/esp_hal_gpspi/esp32s2/include/hal/spi_ll.h @@ -1318,6 +1318,27 @@ static inline void spi_ll_dma_reset_register(spi_host_device_t host_id) spi_ll_dma_reset_register(__VA_ARGS__); \ } while(0) +/** + * Connect DMA channel for SPI + * + * @param host_id SPI host ID + * @param dma_chan DMA channel ID + */ +static inline void spi_ll_dma_connect_host(spi_host_device_t host_id, int dma_chan) +{ + //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them. +} + +/** + * Disconnect DMA channel for SPI + * + * @param host_id SPI host ID + */ +static inline void spi_ll_dma_disconnect_host(spi_host_device_t host_id) +{ + //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to disconnect them. +} + //---------------------------------------------------RX-------------------------------------------------// /** * Reset RX DMA which stores the data received from a peripheral into RAM.