Browse Source

fix(spi_master): this fix the SPI MOSI output missing bug.

michael 8 years ago
parent
commit
b834fcf78a

+ 1 - 0
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;
 
 /**

+ 20 - 4
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
 */

+ 7 - 0
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;

+ 38 - 0
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

+ 16 - 3
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; x<NO_CS; x++) {
         SPI_CHECK(spihost[host]->device[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);