spi: seperate the pointer for the TX and RX DMA

This commit is contained in:
Armando 2020-09-14 17:33:10 +08:00
parent 27a6f2666a
commit 59e350b195
10 changed files with 579 additions and 296 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -36,32 +36,35 @@
#include "soc/spi_struct.h"
#include <esp_types.h>
#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).

View File

@ -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;
/**

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)