From b834fcf78aa4cc16d4c3f5349286df3580d24edb Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 31 Aug 2017 19:59:30 +0800 Subject: [PATCH] fix(spi_master): this fix the SPI MOSI output missing bug. --- .../driver/include/driver/periph_ctrl.h | 1 + components/driver/include/driver/spi_common.h | 24 ++++++++++-- components/driver/periph_ctrl.c | 7 ++++ components/driver/spi_common.c | 38 +++++++++++++++++++ components/driver/spi_master.c | 19 ++++++++-- 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/components/driver/include/driver/periph_ctrl.h b/components/driver/include/driver/periph_ctrl.h index 0aab55088..eada30ef0 100644 --- a/components/driver/include/driver/periph_ctrl.h +++ b/components/driver/include/driver/periph_ctrl.h @@ -44,6 +44,7 @@ typedef enum { PERIPH_SPI_MODULE, PERIPH_HSPI_MODULE, PERIPH_VSPI_MODULE, + PERIPH_SPI_DMA_MODULE, } periph_module_t; /** diff --git a/components/driver/include/driver/spi_common.h b/components/driver/include/driver/spi_common.h index 53cde6ffa..6adcc06a9 100644 --- a/components/driver/include/driver/spi_common.h +++ b/components/driver/include/driver/spi_common.h @@ -74,11 +74,30 @@ bool spicommon_periph_claim(spi_host_device_t host); /** * @brief Return the SPI peripheral so another driver can claim it. * - * @param host Peripheral to claim + * @param host Peripheral to return * @return True if peripheral is returned successfully; false if peripheral was free to claim already. */ bool spicommon_periph_free(spi_host_device_t host); +/** + * @brief Try to claim a SPI DMA channel + * + * Call this if your driver wants to use SPI with a DMA channnel. + * + * @param dma_chan channel to claim + * + * @return True if success; false otherwise. + */ +bool spicommon_dma_chan_claim(int dma_chan); + +/** + * @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA. + * + * @param dma_chan channel to return + * + * @return True if success; false otherwise. + */ +bool spicommon_dma_chan_free(int dma_chan); #define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode #define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode @@ -170,9 +189,6 @@ spi_dev_t *spicommon_hw_for_host(spi_host_device_t host); */ int spicommon_irqsource_for_host(spi_host_device_t host); - - - /** * Callback, to be called when a DMA engine reset is completed */ diff --git a/components/driver/periph_ctrl.c b/components/driver/periph_ctrl.c index caadcdc15..429239d38 100644 --- a/components/driver/periph_ctrl.c +++ b/components/driver/periph_ctrl.c @@ -109,6 +109,10 @@ void periph_module_enable(periph_module_t periph) DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2); break; + case PERIPH_SPI_DMA_MODULE: + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_DMA_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST ); + break; default: break; } @@ -202,6 +206,9 @@ void periph_module_disable(periph_module_t periph) case PERIPH_VSPI_MODULE: DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2); DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2); + case PERIPH_SPI_DMA_MODULE: + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_DMA_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); break; default: break; diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index db0dc682d..01c6c4101 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -150,8 +150,13 @@ static const spi_signal_conn_t io_signal[3] = { } }; +#define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1)) + //Periph 1 is 'claimed' by SPI flash code. static bool spi_periph_claimed[3] = {true, false, false}; +static uint8_t spi_dma_chan_enabled = 0; +static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED; + //Returns true if this peripheral is successfully claimed, false if otherwise. bool spicommon_periph_claim(spi_host_device_t host) @@ -180,6 +185,39 @@ spi_dev_t *spicommon_hw_for_host(spi_host_device_t host) return io_signal[host].hw; } +bool spicommon_dma_chan_claim (int dma_chan) +{ + bool ret = false; + assert( dma_chan == 1 || dma_chan == 2 ); + + portENTER_CRITICAL(&spi_dma_spinlock); + if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) { + // get the channel only when it's not claimed yet. + spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan); + ret = true; + } + periph_module_enable( PERIPH_SPI_DMA_MODULE ); + portEXIT_CRITICAL(&spi_dma_spinlock); + + return ret; +} + +bool spicommon_dma_chan_free(int dma_chan) +{ + assert( dma_chan == 1 || dma_chan == 2 ); + assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) ); + + portENTER_CRITICAL(&spi_dma_spinlock); + spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan); + if ( spi_dma_chan_enabled == 0 ) { + //disable the DMA only when all the channels are freed. + periph_module_disable( PERIPH_SPI_DMA_MODULE ); + } + portEXIT_CRITICAL(&spi_dma_spinlock); + + return true; +} + /* Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pins. Feed it a host number and a bus config struct and it'll set up the GPIO matrix and enable the device. It will set is_native to 1 if the bus diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index d7c314c82..dc073dc28 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -108,14 +108,23 @@ static void spi_intr(void *arg); esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan) { - bool native, claimed; + bool native, spi_chan_claimed, dma_chan_claimed; /* ToDo: remove this when we have flash operations cooperating with this */ SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED); SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG); + SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG ); - claimed=spicommon_periph_claim(host); - SPI_CHECK(claimed, "host already in use", ESP_ERR_INVALID_STATE); + spi_chan_claimed=spicommon_periph_claim(host); + SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE); + + if ( dma_chan != 0 ) { + dma_chan_claimed=spicommon_dma_chan_claim(dma_chan); + if ( !dma_chan_claimed ) { + spicommon_periph_free( host ); + SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE); + } + } spihost[host]=malloc(sizeof(spi_host_t)); if (spihost[host]==NULL) goto nomem; @@ -185,6 +194,10 @@ esp_err_t spi_bus_free(spi_host_device_t host) for (x=0; xdevice[x]==NULL, "not all CSses freed", ESP_ERR_INVALID_STATE); } + + if ( spihost[host]->dma_chan > 0 ) { + spicommon_dma_chan_free ( spihost[host]->dma_chan ); + } spihost[host]->hw->slave.trans_inten=0; spihost[host]->hw->slave.trans_done=0; esp_intr_free(spihost[host]->intr);