fix(driver_spi): fixed spi data error on re-install other host

This commit is contained in:
wanckl
2026-10-08 11:18:52 +08:00
committed by Wan Lei
parent 7f8e4a1ae8
commit 1faeea8d77
4 changed files with 80 additions and 15 deletions
@@ -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);
@@ -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] = {
@@ -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.
*
@@ -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.