mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 11:17:20 +02:00
spi_slave: fix the issue rx dma get broken by master unexpected transaction
This commit is contained in:
@ -180,6 +180,26 @@ void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *d
|
|||||||
*/
|
*/
|
||||||
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
|
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
|
||||||
|
|
||||||
|
|
||||||
|
/** Temporarily connect CS signal input to high to avoid slave detecting unexpected transactions.
|
||||||
|
*
|
||||||
|
* @note Don't use this in the application.
|
||||||
|
*
|
||||||
|
* @param host The spi host.
|
||||||
|
*/
|
||||||
|
void spicommon_freeze_cs(spi_host_device_t host);
|
||||||
|
|
||||||
|
/** Use this function instead of cs_initial to avoid overwrite the output config
|
||||||
|
* This is used in test by internal gpio matrix connections
|
||||||
|
*
|
||||||
|
* @note Don't use this in the application.
|
||||||
|
*
|
||||||
|
* @param host The spi host.
|
||||||
|
* @param cs_io_num GPIO number of the CS pin.
|
||||||
|
* @param iomux The peripheral is using iomux pins.
|
||||||
|
*/
|
||||||
|
void spicommon_restore_cs(spi_host_device_t host, int cs_io_num, bool iomux);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the IRQ source for a specific SPI host
|
* @brief Get the IRQ source for a specific SPI host
|
||||||
*
|
*
|
||||||
|
@ -371,6 +371,26 @@ void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const
|
|||||||
dmadesc[n - 1].qe.stqe_next = NULL;
|
dmadesc[n - 1].qe.stqe_next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spicommon_freeze_cs(spi_host_device_t host)
|
||||||
|
{
|
||||||
|
gpio_matrix_in(0x38, io_signal[host].spics_in, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IOMUX_IN(uint32_t gpio, uint32_t signal_idx)
|
||||||
|
{
|
||||||
|
GPIO.func_in_sel_cfg[signal_idx].sig_in_sel = 0;
|
||||||
|
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spicommon_restore_cs(spi_host_device_t host, int cs_io_num, bool iomux)
|
||||||
|
{
|
||||||
|
if (iomux) {
|
||||||
|
IOMUX_IN(cs_io_num, io_signal[host].spics_in);
|
||||||
|
} else {
|
||||||
|
gpio_matrix_in(cs_io_num, io_signal[host].spics_in, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Code for workaround for DMA issue in ESP32 v0/v1 silicon
|
Code for workaround for DMA issue in ESP32 v0/v1 silicon
|
||||||
|
@ -50,6 +50,7 @@ static const char *SPI_TAG = "spi_slave";
|
|||||||
#define VALID_HOST(x) (x>SPI_HOST && x<=VSPI_HOST)
|
#define VALID_HOST(x) (x>SPI_HOST && x<=VSPI_HOST)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
int id;
|
||||||
spi_slave_interface_config_t cfg;
|
spi_slave_interface_config_t cfg;
|
||||||
intr_handle_t intr;
|
intr_handle_t intr;
|
||||||
spi_dev_t *hw;
|
spi_dev_t *hw;
|
||||||
@ -92,10 +93,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
|||||||
if (spihost[host] == NULL) goto nomem;
|
if (spihost[host] == NULL) goto nomem;
|
||||||
memset(spihost[host], 0, sizeof(spi_slave_t));
|
memset(spihost[host], 0, sizeof(spi_slave_t));
|
||||||
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
|
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
|
||||||
|
spihost[host]->id = host;
|
||||||
|
|
||||||
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native);
|
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native);
|
||||||
gpio_set_direction(slave_config->spics_io_num, GPIO_MODE_INPUT);
|
gpio_set_direction(slave_config->spics_io_num, GPIO_MODE_INPUT);
|
||||||
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native==false);
|
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native==false);
|
||||||
|
// The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
|
||||||
|
if (dma_chan != 0) spicommon_freeze_cs(host);
|
||||||
spihost[host]->no_gpio_matrix = native;
|
spihost[host]->no_gpio_matrix = native;
|
||||||
spihost[host]->dma_chan = dma_chan;
|
spihost[host]->dma_chan = dma_chan;
|
||||||
if (dma_chan != 0) {
|
if (dma_chan != 0) {
|
||||||
@ -325,6 +329,9 @@ static void IRAM_ATTR spi_intr(void *arg)
|
|||||||
if (!host->hw->slave.trans_done) return;
|
if (!host->hw->slave.trans_done) return;
|
||||||
|
|
||||||
if (host->cur_trans) {
|
if (host->cur_trans) {
|
||||||
|
// When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
|
||||||
|
if (host->dma_chan != 0) spicommon_freeze_cs(host->id);
|
||||||
|
|
||||||
//when data of cur_trans->length are all sent, the slv_rdata_bit
|
//when data of cur_trans->length are all sent, the slv_rdata_bit
|
||||||
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
|
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
|
||||||
//the length sent.
|
//the length sent.
|
||||||
@ -433,6 +440,9 @@ static void IRAM_ATTR spi_intr(void *arg)
|
|||||||
host->hw->user.usr_mosi = (trans->tx_buffer == NULL) ? 0 : 1;
|
host->hw->user.usr_mosi = (trans->tx_buffer == NULL) ? 0 : 1;
|
||||||
host->hw->user.usr_miso = (trans->rx_buffer == NULL) ? 0 : 1;
|
host->hw->user.usr_miso = (trans->rx_buffer == NULL) ? 0 : 1;
|
||||||
|
|
||||||
|
//The slave rx dma get disturbed by unexpected transaction. Only connect the CS when slave is ready.
|
||||||
|
if (host->dma_chan != 0) spicommon_restore_cs(host->id, host->cfg.spics_io_num, host->no_gpio_matrix);
|
||||||
|
|
||||||
//Kick off transfer
|
//Kick off transfer
|
||||||
host->hw->cmd.usr = 1;
|
host->hw->cmd.usr = 1;
|
||||||
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);
|
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);
|
||||||
|
Reference in New Issue
Block a user