From dfb8aa625753384e5bd4fe523faa648093345c61 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 1 May 2017 03:29:01 +0200 Subject: [PATCH 1/4] place initialization sequence into DRAM to be reachable by DMA Signed-off-by: Jeroen Domburg --- examples/peripherals/spi_master/main/spi_master_example_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/peripherals/spi_master/main/spi_master_example_main.c b/examples/peripherals/spi_master/main/spi_master_example_main.c index b9cdd20092..981a7317f4 100644 --- a/examples/peripherals/spi_master/main/spi_master_example_main.c +++ b/examples/peripherals/spi_master/main/spi_master_example_main.c @@ -50,7 +50,8 @@ typedef struct { uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds. } ili_init_cmd_t; -static const ili_init_cmd_t ili_init_cmds[]={ +//Place data into DRAM. Constant data gets placed into DROM by default, which is not accessible by DMA. +DRAM_ATTR static const ili_init_cmd_t ili_init_cmds[]={ {0xCF, {0x00, 0x83, 0X30}, 3}, {0xED, {0x64, 0x03, 0X12, 0X81}, 4}, {0xE8, {0x85, 0x01, 0x79}, 3}, From 530c3ca05c88811c8247200b00a0f8094533e8fc Mon Sep 17 00:00:00 2001 From: devsaurus Date: Tue, 2 May 2017 22:42:45 +0200 Subject: [PATCH 2/4] components/driver/spi_master: free dma descriptors Signed-off-by: Jeroen Domburg --- components/driver/spi_master.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 5bf3955d06..8fa51048e7 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -177,6 +177,8 @@ esp_err_t spi_bus_free(spi_host_device_t host) spihost[host]->hw->slave.trans_done=0; esp_intr_free(spihost[host]->intr); spicommon_periph_free(host); + free(spihost[host]->dmadesc_tx); + free(spihost[host]->dmadesc_rx); free(spihost[host]); spihost[host]=NULL; return ESP_OK; From 8af3fe4e8441519ba4955b146a008ff9c70a03d6 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 5 May 2017 11:55:19 +0800 Subject: [PATCH 3/4] Warn against and check for non-DMA-capable pointers being passed to SPI when DMA is used --- components/driver/include/driver/spi_master.h | 4 ++++ components/driver/include/driver/spi_slave.h | 4 ++++ components/driver/spi_master.c | 4 ++++ components/driver/spi_slave.c | 4 ++++ components/esp32/include/esp_heap_alloc_caps.h | 13 +++++++++++++ 5 files changed, 29 insertions(+) diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index ba8bc5d90f..29b408af66 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -100,6 +100,10 @@ typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a * for a SPI bus allows transfers on the bus to have sizes only limited by the amount of * internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of * bytes transfered to a maximum of 32. + * + * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in + * DMA-capable memory. + * * @return * - ESP_ERR_INVALID_ARG if configuration is invalid * - ESP_ERR_INVALID_STATE if host already is in use diff --git a/components/driver/include/driver/spi_slave.h b/components/driver/include/driver/spi_slave.h index a3706bb661..047ab41392 100644 --- a/components/driver/include/driver/spi_slave.h +++ b/components/driver/include/driver/spi_slave.h @@ -69,6 +69,10 @@ struct spi_slave_transaction_t { * @param dma_chan Either 1 or 2. A SPI bus used by this driver must have a DMA channel associated with * it. The SPI hardware has two DMA channels to share. This parameter indicates which * one to use. + * + * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in + * DMA-capable memory. + * * @return * - ESP_ERR_INVALID_ARG if configuration is invalid * - ESP_ERR_INVALID_STATE if host already is in use diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 8fa51048e7..aa53b55725 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -575,6 +575,10 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t * SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG); SPI_CHECK(trans_desc->length <= handle->host->max_transfer_sz*8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG); SPI_CHECK(trans_desc->rxlength <= handle->host->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG); + SPI_CHECK(handle->host->dma_chan == 0 || (trans_desc->flags & SPI_TRANS_USE_TXDATA) || + trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer), "txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG); + SPI_CHECK(handle->host->dma_chan == 0 || (trans_desc->flags & SPI_TRANS_USE_RXDATA) || + trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer), "rxdata not in DMA-capable memory", ESP_ERR_INVALID_ARG); r=xQueueSend(handle->trans_queue, (void*)&trans_desc, ticks_to_wait); if (!r) return ESP_ERR_TIMEOUT; esp_intr_enable(handle->host->intr); diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index 57f3c38352..2cff6e00b6 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -202,6 +202,10 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact BaseType_t r; SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG); SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG); + SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer), + "txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG); + SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer), + "rxdata not in DMA-capable memory", ESP_ERR_INVALID_ARG); SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG); r = xQueueSend(spihost[host]->trans_queue, (void *)&trans_desc, ticks_to_wait); diff --git a/components/esp32/include/esp_heap_alloc_caps.h b/components/esp32/include/esp_heap_alloc_caps.h index e1021c30b1..a0e40a7cdc 100644 --- a/components/esp32/include/esp_heap_alloc_caps.h +++ b/components/esp32/include/esp_heap_alloc_caps.h @@ -87,4 +87,17 @@ size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps ); +/** + * @brief Convenience function to check if a pointer is DMA-capable. + * + * @param ptr Pointer to check + * + * @return True if DMA-capable, false if not. + */ +static inline bool esp_ptr_dma_capable( const void *ptr ) +{ + return ( (int)ptr >= 0x3FFAE000 && (int)ptr < 0x40000000 ); +} + + #endif \ No newline at end of file From 9962cc9c9f4e6ca146ebdc9ae4dc02bbdfa4024b Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Mon, 8 May 2017 16:11:46 +0800 Subject: [PATCH 4/4] Fix out-of-bounds on dmaworkaround_channels_busy --- components/driver/spi_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index d58d202d31..9f2d8ac764 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -350,7 +350,7 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t int otherchan = (dmachan == 1) ? 2 : 1; bool ret; portENTER_CRITICAL(&dmaworkaround_mux); - if (dmaworkaround_channels_busy[otherchan]) { + if (dmaworkaround_channels_busy[otherchan-1]) { //Other channel is busy. Call back when it's done. dmaworkaround_cb = cb; dmaworkaround_cb_arg = arg; @@ -374,7 +374,7 @@ bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress() void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan) { portENTER_CRITICAL(&dmaworkaround_mux); - dmaworkaround_channels_busy[dmachan] = 0; + dmaworkaround_channels_busy[dmachan-1] = 0; if (dmaworkaround_waiting_for_chan == dmachan) { //Reset DMA SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); @@ -390,7 +390,7 @@ void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan) void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan) { portENTER_CRITICAL(&dmaworkaround_mux); - dmaworkaround_channels_busy[dmachan] = 1; + dmaworkaround_channels_busy[dmachan-1] = 1; portEXIT_CRITICAL(&dmaworkaround_mux); }