mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-02 22:51:14 +00:00
refactor(spi_master): replace dma_ll in spi hal layer (part 2.1)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "soc/ext_mem_defs.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_master.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;
|
||||
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-------------------------------------------------------//
|
||||
esp_err_t spicommon_dma_chan_free(spi_dma_ctx_t *dma_ctx)
|
||||
{
|
||||
|
@@ -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_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) {
|
||||
//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);
|
||||
}
|
||||
|
||||
#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.
|
||||
// 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)
|
||||
@@ -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_prepare_data(hal, hal_dev, &hal_trans);
|
||||
s_spi_prepare_data(dev, &hal_trans);
|
||||
|
||||
//Call pre-transmission callback, if any
|
||||
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_hal_fetch_result(&host->hal);
|
||||
if (!host->bus_attr->dma_enabled) {
|
||||
spi_hal_fetch_result(&host->hal);
|
||||
}
|
||||
//Call post-transaction callback, if any
|
||||
spi_device_t* dev = host->device[host->cur_cs];
|
||||
if (dev->cfg.post_cb) {
|
||||
|
Reference in New Issue
Block a user