From 59e350b195105307583c225a37d8b619ea9bc23d Mon Sep 17 00:00:00 2001 From: Armando Date: Mon, 14 Sep 2020 17:33:10 +0800 Subject: [PATCH] spi: seperate the pointer for the TX and RX DMA --- components/driver/spi_slave.c | 9 +- components/hal/esp32/include/hal/spi_ll.h | 352 ++++++++++++------ components/hal/esp32s2/include/hal/spi_ll.h | 329 +++++++++------- components/hal/include/hal/spi_slave_hal.h | 47 ++- components/hal/include/hal/spi_slave_hd_hal.h | 46 +-- components/hal/spi_hal.c | 15 +- components/hal/spi_hal_iram.c | 7 +- components/hal/spi_slave_hal.c | 17 +- components/hal/spi_slave_hal_iram.c | 28 +- components/hal/spi_slave_hd_hal.c | 25 +- 10 files changed, 579 insertions(+), 296 deletions(-) diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index 2cecf4275d..bdfa95b6ad 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -36,6 +36,7 @@ #include "esp_heap_caps.h" #include "esp_rom_gpio.h" #include "esp_rom_sys.h" +#include "hal/spi_slave_hal.h" static const char *SPI_TAG = "spi_slave"; #define SPI_CHECK(a, str, ret_val) \ @@ -192,7 +193,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b } spi_slave_hal_context_t *hal = &spihost[host]->hal; - spi_slave_hal_init(hal, host); + //assign the SPI, RX DMA and TX DMA peripheral registers beginning address + spi_slave_hal_config_t hal_config = { + .host_id = host, + .dma_in = SPI_LL_GET_HW(host), + .dma_out = SPI_LL_GET_HW(host) + }; + spi_slave_hal_init(hal, &hal_config); if (dma_desc_ct) { hal->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index bfeccf471d..d11db18697 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -34,7 +34,7 @@ extern "C" { #endif /// Registers to reset during initialization. Don't use in app. -#define SPI_LL_RST_MASK (SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST) +#define SPI_LL_DMA_FIFO_RST_MASK (SPI_AHBM_RST | SPI_AHBM_FIFO_RST) /// Interrupt not used. Don't use in app. #define SPI_LL_UNUSED_INT_MASK (SPI_INT_EN | SPI_SLV_WR_STA_DONE | SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE | SPI_SLV_RD_BUF_DONE) /// Swap the bit order to its correct place to send @@ -49,6 +49,9 @@ extern "C" { */ typedef uint32_t spi_ll_clock_val_t; +//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. So set the registers of SPI peripheral to control DMA. +typedef spi_dev_t spi_dma_dev_t; + /** IO modes supported by the master. */ typedef enum { SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases @@ -58,11 +61,6 @@ typedef enum { SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases } spi_ll_io_mode_t; -/// Interrupt type for different working pattern -typedef enum { - SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done -} spi_ll_slave_intr_type; - /*------------------------------------------------------------------------------ * Control @@ -74,11 +72,6 @@ typedef enum { */ static inline void spi_ll_master_init(spi_dev_t *hw) { - //Reset DMA - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; //Reset timing hw->ctrl2.val = 0; @@ -105,10 +98,6 @@ static inline void spi_ll_slave_init(spi_dev_t *hw) hw->user.doutdin = 1; //we only support full duplex hw->user.sio = 0; hw->slave.slave_mode = 1; - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; hw->slave.sync_reset = 1; hw->slave.sync_reset = 0; //use all 64 bytes of the buffer @@ -119,84 +108,6 @@ static inline void spi_ll_slave_init(spi_dev_t *hw) hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK; } -/** - * Reset TX and RX DMAs. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_reset_dma(spi_dev_t *hw) -{ - //Reset DMA peripheral - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; - hw->dma_conf.out_data_burst_en = 1; - hw->dma_conf.indscr_burst_en = 1; - hw->dma_conf.outdscr_burst_en = 1; -} - -/** - * Start RX DMA. - * - * @param hw Beginning address of the peripheral registers. - * @param addr Address of the beginning DMA descriptor. - */ -static inline void spi_ll_rxdma_start(spi_dev_t *hw, lldesc_t *addr) -{ - hw->dma_in_link.addr = (int) addr & 0xFFFFF; - hw->dma_in_link.start = 1; -} - -/** - * Start TX DMA. - * - * @param hw Beginning address of the peripheral registers. - * @param addr Address of the beginning DMA descriptor. - */ -static inline void spi_ll_txdma_start(spi_dev_t *hw, lldesc_t *addr) -{ - hw->dma_out_link.addr = (int) addr & 0xFFFFF; - hw->dma_out_link.start = 1; -} - -/** - * Write to SPI buffer. - * - * @param hw Beginning address of the peripheral registers. - * @param buffer_to_send Data address to copy to the buffer. - * @param bitlen Length to copy, in bits. - */ -static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen) -{ - for (int x = 0; x < bitlen; x += 32) { - //Use memcpy to get around alignment issues for txdata - uint32_t word; - memcpy(&word, &buffer_to_send[x / 8], 4); - hw->data_buf[(x / 32)] = word; - } -} - -/** - * Read from SPI buffer. - * - * @param hw Beginning address of the peripheral registers. - * @param buffer_to_rcv Address to copy buffer data to. - * @param bitlen Length to copy, in bits. - */ -static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen) -{ - for (int x = 0; x < bitlen; x += 32) { - //Do a memcpy to get around possible alignment issues in rx_buffer - uint32_t word = hw->data_buf[x / 32]; - int len = bitlen - x; - if (len > 32) { - len = 32; - } - memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8); - } -} - /** * Check whether user-defined transaction is done. * @@ -232,48 +143,110 @@ static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) } /** - * Disable the trans_done interrupt. + * Reset SPI CPU FIFO * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_disable_int(spi_dev_t *hw) +static inline void spi_ll_cpu_fifo_reset(spi_dev_t *hw) { - hw->slave.trans_inten = 0; + //This is not used in esp32 } /** - * Clear the trans_done interrupt. + * Reset SPI DMA FIFO * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_clear_int_stat(spi_dev_t *hw) +static inline void spi_ll_dma_fifo_reset(spi_dev_t *hw) { - hw->slave.trans_done = 0; + hw->dma_conf.val |= SPI_LL_DMA_FIFO_RST_MASK; + hw->dma_conf.val &= ~SPI_LL_DMA_FIFO_RST_MASK; } /** - * Set the trans_done interrupt. - * + * Clear in fifo full error + * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_set_int_stat(spi_dev_t *hw) +static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) { - hw->slave.trans_done = 1; + //This is not used in esp32 } /** - * Enable the trans_done interrupt. - * + * Clear out fifo empty error + * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_enable_int(spi_dev_t *hw) +static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) { - hw->slave.trans_inten = 1; + //This is not used in esp32 } -static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type) +/*------------------------------------------------------------------------------ + * SPI configuration for DMA + *----------------------------------------------------------------------------*/ + +/** + * Enable/Disable RX DMA (Peripherals->DMA->RAM) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) { - hw->slave.trans_inten = 1; + //This is not used in esp32 +} + +/** + * Enable/Disable TX DMA (RAM->DMA->Peripherals) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) +{ + //This is not used in esp32 +} + +/*------------------------------------------------------------------------------ + * Buffer + *----------------------------------------------------------------------------*/ +/** + * Write to SPI buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_send Data address to copy to the buffer. + * @param bitlen Length to copy, in bits. + */ +static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Use memcpy to get around alignment issues for txdata + uint32_t word; + memcpy(&word, &buffer_to_send[x / 8], 4); + hw->data_buf[(x / 32)] = word; + } +} + +/** + * Read from SPI buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_rcv Address to copy buffer data to. + * @param bitlen Length to copy, in bits. + */ +static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen) +{ + for (int x = 0; x < bitlen; x += 32) { + //Do a memcpy to get around possible alignment issues in rx_buffer + uint32_t word = hw->data_buf[x / 32]; + int len = bitlen - x; + if (len > 32) { + len = 32; + } + memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8); + } } /*------------------------------------------------------------------------------ @@ -875,6 +848,167 @@ static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw) return hw->slv_rd_bit.slv_rdata_bit; } +/*------------------------------------------------------------------------------ + * Interrupts + *----------------------------------------------------------------------------*/ +/** + * Disable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_disable_int(spi_dev_t *hw) +{ + hw->slave.trans_inten = 0; +} + +/** + * Clear the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_clear_int_stat(spi_dev_t *hw) +{ + hw->slave.trans_done = 0; +} + +/** + * Set the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_set_int_stat(spi_dev_t *hw) +{ + hw->slave.trans_done = 1; +} + +/** + * Enable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_enable_int(spi_dev_t *hw) +{ + hw->slave.trans_inten = 1; +} + +/*------------------------------------------------------------------------------ + * DMA: + * RX DMA (Peripherals->DMA->RAM) + * TX DMA (RAM->DMA->Peripherals) + *----------------------------------------------------------------------------*/ +/** + * 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. + */ +static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in) +{ + //Reset RX DMA peripheral + dma_in->dma_conf.in_rst = 1; + dma_in->dma_conf.in_rst = 0; +} + +/** + * 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. + */ +static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr) +{ + dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; + dma_in->dma_in_link.start = 1; +} + +/** + * 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 enable True to enable, false to disable + */ +static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable) +{ + //This is not supported in esp32 +} + +/** + * 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 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) +{ + dma_in->dma_conf.indscr_burst_en = enable; +} + +/** + * Configuration of RX DMA EOF interrupt generation way + * + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param enable 1: spi_dma_inlink_eof is set when the number of dma pushed data bytes is equal to the value of spi_slv/mst_dma_rd_bytelen[19:0] in spi dma transition. 0: spi_dma_inlink_eof is set by spi_trans_done in non-seg-trans or spi_dma_seg_trans_done in seg-trans. + */ +static inline void spi_dma_ll_set_rx_eof_generation(spi_dma_dev_t *dma_in, bool enable) +{ + //does not available in ESP32 +} + +/** + * 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. + */ +static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out) +{ + //Reset TX DMA peripheral + dma_out->dma_conf.out_rst = 1; + dma_out->dma_conf.out_rst = 0; +} + +/** + * 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. + */ +static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr) +{ + dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; + dma_out->dma_out_link.start = 1; +} + +/** + * 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 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) +{ + dma_out->dma_conf.out_data_burst_en = enable; +} + +/** + * 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 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) +{ + dma_out->dma_conf.outdscr_burst_en = enable; +} + +/** + * Enable automatic outlink-writeback + * + * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @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) +{ + //does not configure it in ESP32 +} #undef SPI_LL_RST_MASK #undef SPI_LL_UNUSED_INT_MASK diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index e4158e7908..6ddd48cb8d 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -35,7 +35,7 @@ extern "C" { #endif /// Registers to reset during initialization. Don't use in app. -#define SPI_LL_RST_MASK (SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST) +#define SPI_LL_DMA_FIFO_RST_MASK (SPI_AHBM_RST | SPI_AHBM_FIFO_RST) /// Interrupt not used. Don't use in app. #define SPI_LL_UNUSED_INT_MASK (SPI_INT_TRANS_DONE_EN | SPI_INT_WR_DMA_DONE_EN | SPI_INT_RD_DMA_DONE_EN | SPI_INT_WR_BUF_DONE_EN | SPI_INT_RD_BUF_DONE_EN) /// Swap the bit order to its correct place to send @@ -50,6 +50,9 @@ extern "C" { */ typedef uint32_t spi_ll_clock_val_t; +//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. So set the registers of SPI peripheral to control DMA. +typedef spi_dev_t spi_dma_dev_t; + /** IO modes supported by the master. */ typedef enum { SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases @@ -59,12 +62,6 @@ typedef enum { SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases } spi_ll_io_mode_t; -/// Interrupt type for different working pattern -typedef enum { - SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done - SPI_LL_INT_TYPE_SEG = 1, ///< Wait for DMA signals -} spi_ll_slave_intr_type; - /// Type definition of all supported interrupts typedef enum { SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done @@ -104,11 +101,6 @@ FLAG_ATTR(spi_ll_trans_len_cond_t) */ static inline void spi_ll_master_init(spi_dev_t *hw) { - //Reset DMA - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; //Reset timing hw->ctrl2.val = 0; @@ -137,52 +129,26 @@ static inline void spi_ll_slave_init(spi_dev_t *hw) hw->user.doutdin = 1; //we only support full duplex hw->user.sio = 0; hw->slave.slave_mode = 1; - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; hw->slave.soft_reset = 1; hw->slave.soft_reset = 0; //use all 64 bytes of the buffer hw->user.usr_miso_highpart = 0; hw->user.usr_mosi_highpart = 0; - //by default seg mode is disabled - hw->dma_conf.dma_continue = 0; //Disable unneeded ints hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK; - hw->dma_int_ena.val = 0; } -static inline void spi_ll_slave_hd_init(spi_dev_t* hw) +static inline void spi_ll_slave_hd_init(spi_dev_t *hw) { hw->clock.val = 0; hw->user.val = 0; hw->ctrl.val = 0; hw->user.sio = 0; - //hw->user.tx_start_bit = 7; hw->slave.soft_reset = 1; hw->slave.soft_reset = 0; - //Reset DMA - hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~(SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST); - - if (hw == &GPSPI2) { - hw->dma_conf.out_data_burst_en = 1; - } else { - hw->dma_conf.out_data_burst_en = 0; - } - hw->dma_conf.outdscr_burst_en = 1; - hw->dma_conf.indscr_burst_en = 1; - - hw->dma_conf.rx_eof_en = 0; - hw->dma_conf.out_eof_mode = 1; - hw->dma_conf.out_auto_wrback = 1; - hw->user.doutdin = 0; //we only support full duplex hw->slave.slave_mode = 1; } @@ -221,103 +187,83 @@ static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) return hw->cmd.val; } -/*------------------------------------------------------------------------------ - * DMA - *----------------------------------------------------------------------------*/ /** - * Reset TX and RX DMAs. + * Reset SPI CPU FIFO * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_reset_dma(spi_dev_t *hw) +static inline void spi_ll_cpu_fifo_reset(spi_dev_t *hw) { - //Reset DMA peripheral - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_out_link.start = 0; - hw->dma_in_link.start = 0; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; - hw->dma_conf.out_data_burst_en = 0; - hw->dma_conf.indscr_burst_en = 1; - hw->dma_conf.outdscr_burst_en = 1; - hw->dma_in_link.dma_rx_ena = 0; - assert(hw->dma_in_link.dma_rx_ena == 0); + //This is not used in esp32s2 } /** - * Start RX DMA. + * Reset SPI DMA FIFO * * @param hw Beginning address of the peripheral registers. - * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_ll_rxdma_start(spi_dev_t *hw, lldesc_t *addr) +static inline void spi_ll_dma_fifo_reset(spi_dev_t *hw) { - hw->dma_in_link.addr = (int) addr & 0xFFFFF; - hw->dma_in_link.start = 1; + hw->dma_conf.val |= SPI_LL_DMA_FIFO_RST_MASK; + hw->dma_conf.val &= ~SPI_LL_DMA_FIFO_RST_MASK; } /** - * Start TX DMA. - * + * Clear in fifo full error + * * @param hw Beginning address of the peripheral registers. - * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_ll_txdma_start(spi_dev_t *hw, lldesc_t *addr) +static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) { - hw->dma_out_link.addr = (int) addr & 0xFFFFF; - hw->dma_out_link.start = 1; -} - -static inline void spi_ll_rxdma_reset(spi_dev_t* hw) -{ - hw->dma_conf.in_rst = 1; - hw->dma_conf.in_rst = 0; hw->dma_conf.infifo_full_clr = 1; hw->dma_conf.infifo_full_clr = 0; } -static inline void spi_ll_txdma_reset(spi_dev_t* hw) +/** + * Clear out fifo empty error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) { - hw->dma_conf.out_rst = 1; - hw->dma_conf.out_rst = 0; hw->dma_conf.outfifo_empty_clr = 1; hw->dma_conf.outfifo_empty_clr = 0; } -static inline void spi_ll_rxdma_restart(spi_dev_t* hw) +/*------------------------------------------------------------------------------ + * SPI configuration for DMA + *----------------------------------------------------------------------------*/ +/** + * Enable/Disable RX DMA (Peripherals->DMA->RAM) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) { - hw->dma_in_link.restart = 1; + //This is not used in esp32s2 } -static inline void spi_ll_txdma_restart(spi_dev_t* hw) +/** + * Enable/Disable TX DMA (RAM->DMA->Peripherals) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) { - hw->dma_out_link.restart = 1; + //This is not used in esp32s2 } -static inline void spi_ll_rxdma_disable(spi_dev_t* hw) +/** + * 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 enable 1: when dma pop all data from fifo 0:when ahb push all data to fifo. + */ +static inline void spi_ll_dma_set_out_eof_generation(spi_dma_dev_t *dma_out, bool enable) { - hw->dma_in_link.dma_rx_ena = 0; -} - -static inline void spi_ll_txdma_disable(spi_dev_t* hw) -{ - hw->dma_out_link.dma_tx_ena = 0; - hw->dma_out_link.stop = 1; -} - -static inline void spi_ll_rxdma_clr_err(spi_dev_t* hw) -{ - hw->dma_conf.infifo_full_clr = 1; - hw->dma_conf.infifo_full_clr = 0; -} - -static inline void spi_ll_txdma_clr_err(spi_dev_t* hw) -{ - hw->dma_int_clr.outfifo_empty_err= 1; -} - -static inline bool spi_ll_txdma_get_empty_err(spi_dev_t* hw) -{ - return hw->dma_int_raw.outfifo_empty_err; + dma_out->dma_conf.out_eof_mode = enable; } /*------------------------------------------------------------------------------ @@ -559,7 +505,7 @@ static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_ } } -static inline void spi_ll_slave_set_seg_mode(spi_dev_t* hw, bool seg_trans) +static inline void spi_ll_slave_set_seg_mode(spi_dev_t *hw, bool seg_trans) { hw->dma_conf.dma_seg_trans_en = seg_trans; hw->dma_conf.rx_eof_en = seg_trans; @@ -784,7 +730,7 @@ static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup) * Enable/disable the segment transfer feature for the slave. * * @param hw Beginning address of the peripheral registers. - * @param en true to enable, false to disable. + * @param en true to enable, false to disable. */ static inline void spi_ll_slave_set_seg_en(spi_dev_t *hw, bool en) { @@ -982,7 +928,7 @@ static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw) item(SPI_LL_INTR_OUT_EOF, dma_int_ena.out_eof, dma_int_raw.out_eof, dma_int_clr.out_eof=1) \ item(SPI_LL_INTR_OUT_TOTAL_EOF, dma_int_ena.out_total_eof, dma_int_raw.out_total_eof, dma_int_clr.out_total_eof=1) \ item(SPI_LL_INTR_SEG_DONE, slave.int_dma_seg_trans_en, hold.dma_seg_trans_done, hold.dma_seg_trans_done=0) \ - item(SPI_LL_INTR_IN_FULL, dma_int_ena.infifo_full_err, dma_int_raw.infifo_full_err, dma_int_clr.infifo_full_err=1) \ + item(SPI_LL_INTR_IN_FULL, dma_int_ena.infifo_full_err, dma_int_raw.infifo_full_err, dma_int_clr.infifo_full_err=1) \ item(SPI_LL_INTR_OUT_EMPTY, dma_int_ena.outfifo_empty_err, dma_int_raw.outfifo_empty_err, dma_int_clr.outfifo_empty_err=1) \ item(SPI_LL_INTR_WR_DONE, dma_int_ena.cmd7, dma_int_raw.cmd7, dma_int_clr.cmd7=1) \ item(SPI_LL_INTR_CMD8, dma_int_ena.cmd8, dma_int_raw.cmd8, dma_int_clr.cmd8=1) \ @@ -1047,7 +993,6 @@ static inline void spi_ll_disable_int(spi_dev_t *hw) static inline void spi_ll_clear_int_stat(spi_dev_t *hw) { hw->slave.trans_done = 0; - hw->dma_int_clr.val = UINT32_MAX; } /** @@ -1070,27 +1015,6 @@ static inline void spi_ll_enable_int(spi_dev_t *hw) hw->slave.int_trans_done_en = 1; } -/** - * Set different interrupt types for the slave. - * - * @param hw Beginning address of the peripheral registers. - * @param int_type Interrupt type - */ -static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type) -{ - switch (int_type) { - case SPI_LL_INT_TYPE_SEG: - hw->dma_int_ena.in_suc_eof = 1; - hw->dma_int_ena.out_total_eof = 1; - hw->slave.int_trans_done_en = 0; - break; - default: - hw->dma_int_ena.in_suc_eof = 0; - hw->dma_int_ena.out_total_eof = 0; - hw->slave.int_trans_done_en = 1; - } -} - /*------------------------------------------------------------------------------ * Slave HD *----------------------------------------------------------------------------*/ @@ -1111,6 +1035,157 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t* hw) { return hw->slave1.last_addr; } + +/*------------------------------------------------------------------------------ + * DMA: + * RX DMA (Peripherals->DMA->RAM) + * TX DMA (RAM->DMA->Peripherals) + *----------------------------------------------------------------------------*/ +/** + * 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. + */ +static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in) +{ + //Reset RX DMA peripheral + dma_in->dma_in_link.dma_rx_ena = 0; + assert(dma_in->dma_in_link.dma_rx_ena == 0); + + dma_in->dma_conf.in_rst = 1; + dma_in->dma_conf.in_rst = 0; +} + +/** + * 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. + */ +static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr) +{ + dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; + dma_in->dma_in_link.start = 1; +} + +/** + * 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 enable True to enable, false to disable + */ +static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable) +{ + //This is not supported in esp32s2 +} + +/** + * 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 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) +{ + dma_in->dma_conf.indscr_burst_en = enable; +} + +/** + * Configuration of RX DMA EOF interrupt generation way + * + * @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + * @param enable 1: spi_dma_inlink_eof is set when the number of dma pushed data bytes is equal to the value of spi_slv/mst_dma_rd_bytelen[19:0] in spi dma transition. 0: spi_dma_inlink_eof is set by spi_trans_done in non-seg-trans or spi_dma_seg_trans_done in seg-trans. + */ +static inline void spi_dma_ll_set_rx_eof_generation(spi_dma_dev_t *dma_in, bool enable) +{ + dma_in->dma_conf.rx_eof_en = enable; +} + +/** + * 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. + */ +static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out) +{ + //Reset TX DMA peripheral + dma_out->dma_conf.out_rst = 1; + dma_out->dma_conf.out_rst = 0; +} + +/** + * 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. + */ +static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr) +{ + dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; + dma_out->dma_out_link.start = 1; +} + +/** + * 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 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) +{ + dma_out->dma_conf.out_data_burst_en = enable; +} + +/** + * 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 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) +{ + dma_out->dma_conf.outdscr_burst_en = enable; +} + +/** + * Enable automatic outlink-writeback + * + * @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral. + * @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) +{ + dma_out->dma_conf.out_auto_wrback = enable; +} + +static inline void spi_dma_ll_rx_restart(spi_dma_dev_t *dma_in) +{ + dma_in->dma_in_link.restart = 1; +} + +static inline void spi_dma_ll_tx_restart(spi_dma_dev_t *dma_out) +{ + dma_out->dma_out_link.restart = 1; +} + +static inline void spi_dma_ll_rx_disable(spi_dma_dev_t *dma_in) +{ + dma_in->dma_in_link.dma_rx_ena = 0; +} + +static inline void spi_dma_ll_tx_disable(spi_dma_dev_t *dma_out) +{ + dma_out->dma_out_link.dma_tx_ena = 0; + dma_out->dma_out_link.stop = 1; +} + +static inline bool spi_ll_tx_get_empty_err(spi_dev_t *hw) +{ + return hw->dma_int_raw.outfifo_empty_err; +} + #undef SPI_LL_RST_MASK #undef SPI_LL_UNUSED_INT_MASK diff --git a/components/hal/include/hal/spi_slave_hal.h b/components/hal/include/hal/spi_slave_hal.h index f8acf2d973..2beccd45c0 100644 --- a/components/hal/include/hal/spi_slave_hal.h +++ b/components/hal/include/hal/spi_slave_hal.h @@ -36,32 +36,35 @@ #include "soc/spi_struct.h" #include #include "soc/spi_caps.h" +#include "hal/spi_ll.h" /** * Context that should be maintained by both the driver and the HAL. */ typedef struct { /* configured by driver at initialization, don't touch */ - spi_dev_t *hw; ///< Beginning address of the peripheral registers. + spi_dev_t *hw; ///< Beginning address of the peripheral registers. + spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM. + spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral. /* should be configured by driver at initialization */ - lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA. - * The amount should be larger than dmadesc_n. The driver should ensure that - * the data to be sent is shorter than the descriptors can hold. - */ - lldesc_t *dmadesc_tx; /**< 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. - */ - int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use. + lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA. + * The amount should be larger than dmadesc_n. The driver should ensure that + * the data to be sent is shorter than the descriptors can hold. + */ + lldesc_t *dmadesc_tx; /**< 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. + */ + int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use. /* * configurations to be filled after ``spi_slave_hal_init``. Updated to * peripheral registers when ``spi_slave_hal_setup_device`` is called. */ struct { - uint32_t rx_lsbfirst : 1; - uint32_t tx_lsbfirst : 1; - uint32_t use_dma : 1; + uint32_t rx_lsbfirst : 1; + uint32_t tx_lsbfirst : 1; + uint32_t use_dma : 1; }; int mode; @@ -69,21 +72,27 @@ typedef struct { * Transaction specific (data), all these parameters will be updated to the * peripheral every transaction. */ - uint32_t bitlen; ///< Expected maximum length of the transaction, in bits. - const void *tx_buffer; ///< Data to be sent - void *rx_buffer; ///< Buffer to hold the received data. + uint32_t bitlen; ///< Expected maximum length of the transaction, in bits. + const void *tx_buffer; ///< Data to be sent + void *rx_buffer; ///< Buffer to hold the received data. /* Other transaction result after one transaction */ - uint32_t rcv_bitlen; ///< Length of the last transaction, in bits. + uint32_t rcv_bitlen; ///< Length of the last transaction, in bits. } spi_slave_hal_context_t; +typedef struct { + uint32_t host_id; ///< SPI controller ID + spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address + spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address +} spi_slave_hal_config_t; + /** * Init the peripheral and the context. * - * @param hal Context of the HAL layer. + * @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). */ -void spi_slave_hal_init(spi_slave_hal_context_t *hal, int host_id); +void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config); /** * Deinit the peripheral (and the context if needed). diff --git a/components/hal/include/hal/spi_slave_hd_hal.h b/components/hal/include/hal/spi_slave_hd_hal.h index 1621e46892..69ebba4105 100644 --- a/components/hal/include/hal/spi_slave_hd_hal.h +++ b/components/hal/include/hal/spi_slave_hd_hal.h @@ -59,38 +59,38 @@ /// Configuration of the HAL typedef struct { - uint32_t host_id; ///< Host ID of the spi peripheral - dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address - dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address - uint32_t spics_io_num; ///< CS GPIO pin for this device - uint8_t mode; ///< SPI mode (0-3) - uint32_t command_bits; ///< command field bits, multiples of 8 and at least 8. - 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 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 spics_io_num; ///< CS GPIO pin for this device + uint8_t mode; ///< SPI mode (0-3) + uint32_t command_bits; ///< command field bits, multiples of 8 and at least 8. + 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. struct { - uint32_t tx_lsbfirst : 1; ///< Whether TX data should be sent with LSB first. - uint32_t rx_lsbfirst : 1; ///< Whether RX data should be read with LSB first. + uint32_t tx_lsbfirst : 1; ///< Whether TX data should be sent with LSB first. + uint32_t rx_lsbfirst : 1; ///< Whether RX data should be read with LSB first. }; - uint32_t dma_chan; ///< The dma channel used. + uint32_t dma_chan; ///< The dma channel used. } spi_slave_hd_hal_config_t; /// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`. typedef struct { - spi_dev_t *dev; ///< Beginning address of the peripheral registers. - dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM. - dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral. - 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. - */ + 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. + 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. + */ /* Internal status used by the HAL implementation, initialized as 0. */ - uint32_t intr_not_triggered; + uint32_t intr_not_triggered; } spi_slave_hd_hal_context_t; /** diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index 4a46c0a14c..d22c851fcd 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -24,13 +24,24 @@ static const char SPI_HAL_TAG[] = "spi_hal"; return (ret_val); \ } -void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id) +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); +} + +void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_dma_config_t *dma_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; spi_ll_master_init(hw); + s_spi_hal_dma_init_config(hal); //Force a transaction done interrupt. This interrupt won't fire yet because //we initialized the SPI interrupt as disabled. This way, we can just @@ -131,4 +142,4 @@ int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns) } return APB_CLK_FREQ / (delay_apb_n + 1); -} +} \ No newline at end of file diff --git a/components/hal/spi_hal_iram.c b/components/hal/spi_hal_iram.c index dc46b45c6f..f49c96dfe8 100644 --- a/components/hal/spi_hal_iram.c +++ b/components/hal/spi_hal_iram.c @@ -119,7 +119,9 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans) { spi_dev_t *hw = hal->hw; - spi_ll_reset_dma(hw); + + spi_ll_dma_fifo_reset(hal->hw); + //Fill DMA descriptors if (trans->rcv_buffer) { if (!hal->dma_enabled) { @@ -132,9 +134,11 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de spi_ll_dma_rx_enable(hal->hw, 1); spi_dma_ll_rx_start(hal->dma_in, hal->dma_config.dmadesc_rx); } + } else { //DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon if (hal->dma_enabled) { + spi_ll_dma_rx_enable(hal->hw, 1); spi_dma_ll_rx_start(hal->dma_in, 0); } } @@ -152,6 +156,7 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de spi_dma_ll_tx_start(hal->dma_out, hal->dma_config.dmadesc_tx); } } + //in ESP32 these registers should be configured after the DMA is set if ((!dev->half_duplex && trans->rcv_buffer) || trans->send_buffer) { spi_ll_enable_mosi(hw, 1); diff --git a/components/hal/spi_slave_hal.c b/components/hal/spi_slave_hal.c index 3ad0be86fc..904f620e84 100644 --- a/components/hal/spi_slave_hal.c +++ b/components/hal/spi_slave_hal.c @@ -1,19 +1,30 @@ #include "hal/spi_slave_hal.h" #include "hal/spi_ll.h" -void spi_slave_hal_init(spi_slave_hal_context_t *hal, int host_id) +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); +} + +void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config) { memset(hal, 0, sizeof(spi_slave_hal_context_t)); - spi_dev_t *hw = spi_periph_signal[host_id].hw; + spi_dev_t *hw = SPI_LL_GET_HW(hal_config->host_id); hal->hw = hw; + hal->dma_in = hal_config->dma_in; + hal->dma_out = hal_config->dma_out; + s_spi_slave_hal_dma_init_config(hal); spi_ll_slave_init(hal->hw); //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling //any transactions that are queued. spi_ll_set_int_stat(hal->hw); - spi_ll_slave_set_int_type(hal->hw, SPI_LL_INT_TYPE_NORMAL); + spi_ll_enable_int(hal->hw); } void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal) diff --git a/components/hal/spi_slave_hal_iram.c b/components/hal/spi_slave_hal_iram.c index ce4e46dcc3..2d42737594 100644 --- a/components/hal/spi_slave_hal_iram.c +++ b/components/hal/spi_slave_hal_iram.c @@ -14,28 +14,43 @@ void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal) void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) { - spi_ll_slave_reset(hal->hw); if (hal->use_dma) { - spi_ll_reset_dma(hal->hw); + spi_ll_dma_fifo_reset(hal->hw); //Fill DMA descriptors - if (hal->rx_buffer) { + if (hal->rx_buffer) { lldesc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true); - spi_ll_rxdma_start(hal->hw, &hal->dmadesc_rx[0]); + + //reset dma inlink, this should be reset before spi related reset + spi_dma_ll_rx_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]); } if (hal->tx_buffer) { lldesc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false); - spi_ll_txdma_start(hal->hw, (&hal->dmadesc_tx[0])); + + //reset dma outlink, this should be reset before spi related reset + spi_dma_ll_tx_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])); } } else { //No DMA. Turn off SPI and copy data to transmit buffers. if (hal->tx_buffer) { + spi_ll_slave_reset(hal->hw); spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen); } } - + spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen); spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen); + spi_ll_enable_mosi(hal->hw, (hal->tx_buffer == NULL) ? 0 : 1); spi_ll_enable_miso(hal->hw, (hal->rx_buffer == NULL) ? 0 : 1); } @@ -53,7 +68,6 @@ void spi_slave_hal_store_result(spi_slave_hal_context_t *hal) //Copy result out spi_ll_read_buffer(hal->hw, hal->rx_buffer, hal->bitlen); } - spi_ll_slave_set_int_type(hal->hw, SPI_LL_INT_TYPE_NORMAL); } uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal) diff --git a/components/hal/spi_slave_hd_hal.c b/components/hal/spi_slave_hd_hal.c index 099b6c6c50..b966fcba0b 100644 --- a/components/hal/spi_slave_hd_hal.c +++ b/components/hal/spi_slave_hd_hal.c @@ -23,14 +23,25 @@ #include "soc/lldesc.h" #include "hal/spi_slave_hd_hal.h" +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); +} void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config) { memset(hal, 0, sizeof(spi_slave_hd_hal_context_t)); spi_dev_t* hw = SPI_LL_GET_HW(hal_config->host_id); hal->dev = hw; + hal->dma_in = hal_config->dma_in; + hal->dma_out = hal_config->dma_out; //Configure slave + s_spi_slave_hd_hal_dma_init_config(hal); + spi_ll_slave_hd_init(hw); spi_ll_set_addr_bitlen(hw, hal_config->address_bits); spi_ll_set_command_bitlen(hw, hal_config->command_bits); @@ -71,18 +82,24 @@ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, s { lldesc_setup_link(hal->dmadesc_rx, out_buf, len, true); - spi_ll_rxdma_reset(hal->dev); + spi_dma_ll_rx_reset(hal->dma_in); + spi_ll_infifo_full_clr(hal->dev); spi_ll_clear_intr(hal->dev, SPI_LL_INTR_WR_DONE); - spi_ll_rxdma_start(hal->dev, &hal->dmadesc_rx[0]); + + spi_ll_dma_rx_enable(hal->dev, 1); + spi_dma_ll_rx_start(hal->dma_in, &hal->dmadesc_rx[0]); } void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len) { lldesc_setup_link(hal->dmadesc_tx, data, len, false); - spi_ll_txdma_reset(hal->dev); + spi_dma_ll_tx_reset(hal->dma_out); + spi_ll_outfifo_empty_clr(hal->dev); spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8); - spi_ll_txdma_start(hal->dev, &hal->dmadesc_tx[0]); + + spi_ll_dma_tx_enable(hal->dev, 1); + spi_dma_ll_tx_start(hal->dma_out, &hal->dmadesc_tx[0]); } static spi_ll_intr_t get_event_intr(spi_event_t ev)