refactor(spi_master): replace dma_ll in spi hal layer (part 2.1)

pull/13090/head
wanlei 2023-12-28 19:58:54 +08:00
rodzic 227c5d2cb7
commit 2baee4fb0f
12 zmienionych plików z 189 dodań i 211 usunięć

Wyświetl plik

@ -26,6 +26,7 @@ menu "ESP-Driver:SPI Configurations"
select PERIPH_CTRL_FUNC_IN_IRAM select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_MASTER_FUNC_IN_IRAM select HAL_SPI_MASTER_FUNC_IN_IRAM
select ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM select ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM
select GDMA_CTRL_FUNC_IN_IRAM if SOC_GDMA_SUPPORTED
help help
Place the SPI master ISR in to IRAM to avoid possible cache miss. Place the SPI master ISR in to IRAM to avoid possible cache miss.

Wyświetl plik

@ -102,6 +102,16 @@ esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma
*/ */
esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *actual_max_sz); esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *actual_max_sz);
/**
* Setupt/Configure dma descriptor link list
*
* @param dmadesc start of dma descriptor memory
* @param data start of data buffer to be configured in
* @param len length of data buffer, in byte
* @param is_rx if descriptor is for rx/receive direction
*/
void spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx);
/** /**
* @brief Free DMA for SPI * @brief Free DMA for SPI
* *

Wyświetl plik

@ -1,7 +1,7 @@
[mapping:gpspi_driver] [mapping:gpspi_driver]
archive: libesp_driver_spi.a archive: libesp_driver_spi.a
entries: entries:
if SOC_GDMA_SUPPORTED = n: # SOC_GDMA_SUPPORTED is undeclared if GDMA not support, so use `SOC_GDMA_SUPPORTED != y` instead
if SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y: if SOC_GDMA_SUPPORTED != y && (SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y):
spi_dma: spi_dma_reset (noflash) spi_dma: spi_dma_reset (noflash)
spi_dma: spi_dma_start (noflash) spi_dma: spi_dma_start (noflash)

Wyświetl plik

@ -14,6 +14,7 @@
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "soc/spi_periph.h" #include "soc/spi_periph.h"
#include "soc/ext_mem_defs.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
@ -304,6 +305,43 @@ esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *
*actual_max_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; *actual_max_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
return ESP_OK; return ESP_OK;
} }
#if SOC_NON_CACHEABLE_OFFSET
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
void SPI_MASTER_ISR_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{
dmadesc = ADDR_DMA_2_CPU(dmadesc);
int n = 0;
while (len) {
int dmachunklen = len;
if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
}
if (is_rx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].dw0.size = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].dw0.size = dmachunklen;
dmadesc[n].dw0.length = dmachunklen;
}
dmadesc[n].buffer = (uint8_t *)data;
dmadesc[n].dw0.suc_eof = 0;
dmadesc[n].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
}
//----------------------------------------------------------free dma periph-------------------------------------------------------// //----------------------------------------------------------free dma periph-------------------------------------------------------//
esp_err_t spicommon_dma_chan_free(spi_dma_ctx_t *dma_ctx) esp_err_t spicommon_dma_chan_free(spi_dma_ctx_t *dma_ctx)
{ {

Wyświetl plik

@ -261,29 +261,10 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
} }
} }
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address
spi_hal_config_t hal_config = { .dma_enabled = bus_attr->dma_enabled, };
if (bus_attr->dma_enabled && dma_ctx) {
hal_config.dmadesc_tx = dma_ctx->dmadesc_tx;
hal_config.dmadesc_rx = dma_ctx->dmadesc_rx;
hal_config.dmadesc_n = dma_ctx->dma_desc_num;
#if SOC_GDMA_SUPPORTED
//temporary used for gdma_ll alias in hal layer
gdma_get_channel_id(dma_ctx->tx_dma_chan, (int *)&hal_config.tx_dma_chan);
gdma_get_channel_id(dma_ctx->rx_dma_chan, (int *)&hal_config.rx_dma_chan);
#else
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. Pass the registers of SPI peripheral to control it.
hal_config.dma_in = SPI_LL_GET_HW(host_id);
hal_config.dma_out = SPI_LL_GET_HW(host_id);
hal_config.tx_dma_chan = dma_ctx->tx_dma_chan.chan_id;
hal_config.rx_dma_chan = dma_ctx->rx_dma_chan.chan_id;
#endif
}
SPI_MASTER_PERI_CLOCK_ATOMIC() { SPI_MASTER_PERI_CLOCK_ATOMIC() {
spi_ll_enable_clock(host_id, true); spi_ll_enable_clock(host_id, true);
} }
spi_hal_init(&host->hal, host_id, &hal_config); spi_hal_init(&host->hal, host_id);
if (host_id != SPI1_HOST) { if (host_id != SPI1_HOST) {
//SPI1 attributes are already initialized at start up. //SPI1 attributes are already initialized at start up.
@ -625,6 +606,56 @@ static void SPI_MASTER_ISR_ATTR spi_bus_intr_disable(void *host)
esp_intr_disable(((spi_host_t*)host)->intr); esp_intr_disable(((spi_host_t*)host)->intr);
} }
#if SOC_GDMA_SUPPORTED // AHB_DMA_V1 and AXI_DMA
// dma is provided by gdma driver on these targets
#define spi_dma_reset gdma_reset
#define spi_dma_start(chan, addr) gdma_start(chan, (intptr_t)(addr))
#endif
static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
{
const spi_dma_ctx_t *dma_ctx = host->dma_ctx;
if (trans->rcv_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
spi_dma_reset(dma_ctx->rx_dma_chan);
spi_hal_hw_prepare_rx(hal->hw);
spi_dma_start(dma_ctx->rx_dma_chan, dma_ctx->dmadesc_rx);
}
#if CONFIG_IDF_TARGET_ESP32
else if (!dev->half_duplex) {
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_start(dma_ctx->rx_dma_chan, NULL);
}
#endif
if (trans->send_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
spi_dma_reset(dma_ctx->tx_dma_chan);
spi_hal_hw_prepare_tx(hal->hw);
spi_dma_start(dma_ctx->tx_dma_chan, dma_ctx->dmadesc_tx);
}
}
static void SPI_MASTER_ISR_ATTR s_spi_prepare_data(spi_device_t *dev, const spi_hal_trans_config_t *hal_trans)
{
spi_host_t *host = dev->host;
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
spi_hal_context_t *hal = &(host->hal);
if (host->bus_attr->dma_enabled) {
s_spi_dma_prepare_data(host, hal, hal_dev, hal_trans);
} else {
//Need to copy data to registers manually
spi_hal_push_tx_buffer(hal, hal_trans);
}
//in ESP32 these registers should be configured after the DMA is set
spi_hal_enable_data_line(hal->hw, (!hal_dev->half_duplex && hal_trans->rcv_buffer) || hal_trans->send_buffer, !!hal_trans->rcv_buffer);
}
// The function is called to send a new transaction, in ISR or in the task. // The function is called to send a new transaction, in ISR or in the task.
// Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used) // Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used)
static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf) static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf)
@ -677,7 +708,7 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
} }
spi_hal_setup_trans(hal, hal_dev, &hal_trans); spi_hal_setup_trans(hal, hal_dev, &hal_trans);
spi_hal_prepare_data(hal, hal_dev, &hal_trans); s_spi_prepare_data(dev, &hal_trans);
//Call pre-transmission callback, if any //Call pre-transmission callback, if any
if (dev->cfg.pre_cb) { if (dev->cfg.pre_cb) {
@ -693,7 +724,9 @@ static void SPI_MASTER_ISR_ATTR spi_post_trans(spi_host_t *host)
{ {
spi_transaction_t *cur_trans = host->cur_trans_buf.trans; spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
spi_hal_fetch_result(&host->hal); if (!host->bus_attr->dma_enabled) {
spi_hal_fetch_result(&host->hal);
}
//Call post-transaction callback, if any //Call post-transaction callback, if any
spi_device_t* dev = host->device[host->cur_cs]; spi_device_t* dev = host->device[host->cur_cs];
if (dev->cfg.post_cb) { if (dev->cfg.post_cb) {

Wyświetl plik

@ -288,6 +288,7 @@ static inline void spi_ll_dma_rx_fifo_reset(spi_dev_t *hw)
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
__attribute__((always_inline))
static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) static inline void spi_ll_infifo_full_clr(spi_dev_t *hw)
{ {
//This is not used in esp32 //This is not used in esp32
@ -298,6 +299,7 @@ static inline void spi_ll_infifo_full_clr(spi_dev_t *hw)
* *
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
*/ */
__attribute__((always_inline))
static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
{ {
//This is not used in esp32 //This is not used in esp32
@ -313,6 +315,7 @@ static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable * @param enable 1: enable; 2: disable
*/ */
__attribute__((always_inline))
static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
{ {
//This is not used in esp32 //This is not used in esp32
@ -324,6 +327,7 @@ static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable * @param enable 1: enable; 2: disable
*/ */
__attribute__((always_inline))
static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable)
{ {
//This is not used in esp32 //This is not used in esp32
@ -1090,6 +1094,7 @@ static inline void spi_dma_ll_reset_register(spi_host_device_t host_id) {
* @param dma_in Beginning address of the DMA peripheral registers 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.
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel) static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
{ {
//Reset RX DMA peripheral //Reset RX DMA peripheral
@ -1104,6 +1109,7 @@ static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor. * @param addr Address of the beginning DMA descriptor.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr) static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr)
{ {
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
@ -1140,6 +1146,7 @@ static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, uint32
* @param dma_out Beginning address of the DMA peripheral registers 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.
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel) static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
{ {
//Reset TX DMA peripheral //Reset TX DMA peripheral
@ -1154,6 +1161,7 @@ static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor. * @param addr Address of the beginning DMA descriptor.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr) static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr)
{ {
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;

Wyświetl plik

@ -388,6 +388,7 @@ static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable * @param enable 1: enable; 2: disable
*/ */
__attribute__((always_inline))
static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
{ {
//This is not used in esp32s2 //This is not used in esp32s2
@ -399,6 +400,7 @@ static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
* @param hw Beginning address of the peripheral registers. * @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable * @param enable 1: enable; 2: disable
*/ */
__attribute__((always_inline))
static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable)
{ {
//This is not used in esp32s2 //This is not used in esp32s2
@ -1266,6 +1268,7 @@ static inline void spi_dma_ll_reset_register(spi_host_device_t host_id) {
* @param dma_in Beginning address of the DMA peripheral registers 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.
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel) static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
{ {
dma_in->dma_conf.in_rst = 1; dma_in->dma_conf.in_rst = 1;
@ -1279,6 +1282,7 @@ static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor. * @param addr Address of the beginning DMA descriptor.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr) static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr)
{ {
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF; dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
@ -1340,6 +1344,7 @@ static inline uint32_t spi_dma_ll_get_in_suc_eof_desc_addr(spi_dma_dev_t *dma_in
* @param dma_out Beginning address of the DMA peripheral registers 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.
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel) static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
{ {
//Reset TX DMA peripheral //Reset TX DMA peripheral
@ -1354,6 +1359,7 @@ static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used. * @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor. * @param addr Address of the beginning DMA descriptor.
*/ */
__attribute__((always_inline))
static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr) static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr)
{ {
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF; dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;

Wyświetl plik

@ -12,16 +12,15 @@
// The HAL layer for SPI master (common part) // The HAL layer for SPI master (common part)
// SPI HAL usages: // SPI HAL usages (without DMA):
// 1. initialize the bus // 1. initialize the bus
// 2. initialize the DMA descriptors if DMA used // 2. setup the clock speed (since this takes long time)
// 3. setup the clock speed (since this takes long time) // 3. call setup_device to update parameters for the specific device
// 4. call setup_device to update parameters for the specific device // 4. call setup_trans to update parameters for the specific transaction
// 5. call setup_trans to update parameters for the specific transaction // 5. prepare data to send into hw registers
// 6. prepare data to send, and prepare the receiving buffer // 6. trigger user defined SPI transaction to start
// 7. trigger user defined SPI transaction to start // 7. wait until the user transaction is done
// 8. wait until the user transaction is done // 8. fetch the received data
// 9. fetch the received data
// Parameter to be updated only during ``setup_device`` will be highlighted in the // Parameter to be updated only during ``setup_device`` will be highlighted in the
// field comments. // field comments.
@ -75,27 +74,6 @@ typedef struct {
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
} spi_hal_timing_conf_t; } spi_hal_timing_conf_t;
/**
* DMA configuration structure
* Should be set by driver at initialization
*/
typedef struct {
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
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
spi_dma_desc_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.
*/
spi_dma_desc_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.
*/
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
} spi_hal_config_t;
/** /**
* Transaction configuration structure, this should be assigned by driver each time. * Transaction configuration structure, this should be assigned by driver each time.
* All these parameters will be updated to the peripheral every transaction. * All these parameters will be updated to the peripheral every transaction.
@ -118,25 +96,9 @@ typedef struct {
* Context that should be maintained by both the driver and the HAL. * Context that should be maintained by both the driver and the HAL.
*/ */
typedef struct { typedef struct {
/* These two need to be malloced by the driver first */
spi_dma_desc_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.
*/
spi_dma_desc_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.
*/
/* Configured by driver at initialization, don't touch */ /* 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 (DMA -> RAM).
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA).
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
/* Internal parameters, don't touch */ /* Internal parameters, don't touch */
spi_hal_trans_config_t trans_config; ///< Transaction configuration spi_hal_trans_config_t trans_config; ///< Transaction configuration
} spi_hal_context_t; } spi_hal_context_t;
@ -172,9 +134,8 @@ typedef struct {
* *
* @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 SPI2 and 2 for SPI3. * @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for SPI2 and 2 for SPI3.
* @param hal_config Configuration of the hal defined by the upper layer.
*/ */
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *hal_config); void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id);
/** /**
* Deinit the peripheral (and the context if needed). * Deinit the peripheral (and the context if needed).
@ -201,13 +162,27 @@ void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *ha
void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans); void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
/** /**
* Prepare the data for the current transaction. * Enable/Disable miso/mosi signals on peripheral side
* *
* @param hal Context of the HAL layer. * @param hw Beginning address of the peripheral registers.
* @param hal_dev Device configuration * @param mosi_ena enable/disable mosi line
* @param hal_trans Transaction configuration * @param miso_ena enable/disable miso line
*/ */
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans); void spi_hal_enable_data_line(spi_dev_t *hw, bool mosi_ena, bool miso_ena);
/**
* Prepare tx hardware for a new DMA trans
*
* @param hw Beginning address of the peripheral registers.
*/
void spi_hal_hw_prepare_rx(spi_dev_t *hw);
/**
* Prepare tx hardware for a new DMA trans
*
* @param hw Beginning address of the peripheral registers.
*/
void spi_hal_hw_prepare_tx(spi_dev_t *hw);
/** /**
* Trigger start a user-defined transaction. * Trigger start a user-defined transaction.
@ -223,6 +198,14 @@ void spi_hal_user_start(const spi_hal_context_t *hal);
*/ */
bool spi_hal_usr_is_done(const spi_hal_context_t *hal); bool spi_hal_usr_is_done(const spi_hal_context_t *hal);
/**
* Setup transaction operations, write tx buffer to HW registers
*
* @param hal Context of the HAL layer.
* @param hal_trans Transaction configuration.
*/
void spi_hal_push_tx_buffer(const spi_hal_context_t *hal, const spi_hal_trans_config_t *hal_trans);
/** /**
* Post transaction operations, mainly fetch data from the buffer. * Post transaction operations, mainly fetch data from the buffer.
* *

Wyświetl plik

@ -21,19 +21,11 @@ static const __attribute__((unused)) char SPI_HAL_TAG[] = "spi_hal";
return (ret_val); \ return (ret_val); \
} }
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *config) void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id)
{ {
memset(hal, 0, sizeof(spi_hal_context_t)); memset(hal, 0, sizeof(spi_hal_context_t));
spi_dev_t *hw = SPI_LL_GET_HW(host_id); spi_dev_t *hw = SPI_LL_GET_HW(host_id);
hal->hw = hw; hal->hw = hw;
hal->dma_in = config->dma_in;
hal->dma_out = config->dma_out;
hal->dma_enabled = config->dma_enabled;
hal->dmadesc_tx = config->dmadesc_tx;
hal->dmadesc_rx = config->dmadesc_rx;
hal->tx_dma_chan = config->tx_dma_chan;
hal->rx_dma_chan = config->rx_dma_chan;
hal->dmadesc_n = config->dmadesc_n;
#if SPI_LL_MOSI_FREE_LEVEL #if SPI_LL_MOSI_FREE_LEVEL
// Change default data line level to low which same as esp32 // Change default data line level to low which same as esp32

Wyświetl plik

@ -12,37 +12,6 @@
#include "soc/ext_mem_defs.h" #include "soc/ext_mem_defs.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
#if SOC_GDMA_SUPPORTED
#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1)
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan);
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
gdma_ll_rx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_rx_start(&GDMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_tx_start(&GDMA, chan);\
} while (0)
#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer
#include "hal/axi_dma_ll.h"
#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan);
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_rx_start(&AXI_DMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_tx_start(&AXI_DMA, chan);\
} while (0)
#endif
#endif //SOC_GDMA_SUPPORTED
void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev) void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev)
{ {
//Configure clock settings //Configure clock settings
@ -145,94 +114,24 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev
memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t)); memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t));
} }
#if SOC_NON_CACHEABLE_OFFSET void spi_hal_enable_data_line(spi_dev_t *hw, bool mosi_ena, bool miso_ena)
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
//TODO: IDF-6152, refactor spi hal layer
static void s_spi_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{ {
dmadesc = ADDR_DMA_2_CPU(dmadesc); spi_ll_enable_mosi(hw, mosi_ena);
int n = 0; spi_ll_enable_miso(hw, miso_ena);
while (len) {
int dmachunklen = len;
if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
}
if (is_rx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].dw0.size = (dmachunklen + 3) & (~3);
dmadesc[n].dw0.length = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].dw0.size = dmachunklen;
dmadesc[n].dw0.length = dmachunklen;
}
dmadesc[n].buffer = (uint8_t *)data;
dmadesc[n].dw0.suc_eof = 0;
dmadesc[n].dw0.owner = 1;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
} }
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans) void spi_hal_hw_prepare_rx(spi_dev_t *hw)
{ {
spi_dev_t *hw = hal->hw; spi_ll_dma_rx_fifo_reset(hw);
spi_ll_infifo_full_clr(hw);
spi_ll_dma_rx_enable(hw, 1);
}
//Fill DMA descriptors void spi_hal_hw_prepare_tx(spi_dev_t *hw)
if (trans->rcv_buffer) { {
if (!hal->dma_enabled) { spi_ll_dma_tx_fifo_reset(hw);
//No need to setup anything; we'll copy the result out of the work registers directly later. spi_ll_outfifo_empty_clr(hw);
} else { spi_ll_dma_tx_enable(hw, 1);
s_spi_hal_dma_desc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
spi_ll_dma_rx_fifo_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->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx);
}
}
#if CONFIG_IDF_TARGET_ESP32
else {
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
if (hal->dma_enabled && !dev->half_duplex) {
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, 0);
}
}
#endif
if (trans->send_buffer) {
if (!hal->dma_enabled) {
//Need to copy data to registers manually
spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen);
} else {
s_spi_hal_dma_desc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
spi_ll_dma_tx_fifo_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->tx_dma_chan, (lldesc_t *)hal->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);
} else {
spi_ll_enable_mosi(hw, 0);
}
spi_ll_enable_miso(hw, (trans->rcv_buffer) ? 1 : 0);
} }
void spi_hal_user_start(const spi_hal_context_t *hal) void spi_hal_user_start(const spi_hal_context_t *hal)
@ -246,11 +145,19 @@ bool spi_hal_usr_is_done(const spi_hal_context_t *hal)
return spi_ll_usr_is_done(hal->hw); return spi_ll_usr_is_done(hal->hw);
} }
void spi_hal_push_tx_buffer(const spi_hal_context_t *hal, const spi_hal_trans_config_t *hal_trans)
{
if (hal_trans->send_buffer) {
spi_ll_write_buffer(hal->hw, hal_trans->send_buffer, hal_trans->tx_bitlen);
}
//No need to setup anything for RX, we'll copy the result out of the work registers directly later.
}
void spi_hal_fetch_result(const spi_hal_context_t *hal) void spi_hal_fetch_result(const spi_hal_context_t *hal)
{ {
const spi_hal_trans_config_t *trans = &hal->trans_config; const spi_hal_trans_config_t *trans = &hal->trans_config;
if (trans->rcv_buffer && !hal->dma_enabled) { if (trans->rcv_buffer) {
//Need to copy from SPI regs to result buffer. //Need to copy from SPI regs to result buffer.
spi_ll_read_buffer(hal->hw, trans->rcv_buffer, trans->rx_bitlen); spi_ll_read_buffer(hal->hw, trans->rcv_buffer, trans->rx_bitlen);
} }

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -28,10 +28,10 @@
#define IDF_PERFORMANCE_MAX_ECDSA_P256_VERIFY_OP 49000 #define IDF_PERFORMANCE_MAX_ECDSA_P256_VERIFY_OP 49000
#define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 40*1000*1000 #define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 40*1000*1000
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 20 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 23
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 16 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 18
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 45 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 47
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 41 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 42
// floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround) // floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround)
#define IDF_PERFORMANCE_MAX_CYCLES_PER_DIV 70 #define IDF_PERFORMANCE_MAX_CYCLES_PER_DIV 70

Wyświetl plik

@ -27,9 +27,9 @@
#define IDF_PERFORMANCE_MAX_ECDSA_P256_VERIFY_OP 67000 #define IDF_PERFORMANCE_MAX_ECDSA_P256_VERIFY_OP 67000
#define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 26*1000*1000 #define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 26*1000*1000
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 28 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 32
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 24 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 25
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 58 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 61
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 54 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 54
// floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround) // floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround)