From 8af3fe4e8441519ba4955b146a008ff9c70a03d6 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 5 May 2017 11:55:19 +0800 Subject: [PATCH] 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 ba8bc5d90..29b408af6 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 a3706bb66..047ab4139 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 8fa51048e..aa53b5572 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 57f3c3835..2cff6e00b 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 e1021c30b..a0e40a7cd 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