From 0cb14f1648d151282ce398f851dbb55f83be2dde Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 15 Aug 2017 11:00:33 +0800 Subject: [PATCH] fix(spi_dma_rx): add check to avoid using SPI half-duplex mode DMA with both MOSI and MISO phases. --- components/driver/include/driver/spi_master.h | 2 +- components/driver/spi_master.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index 099f3b7573..d3b6f81dc5 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -76,7 +76,7 @@ struct spi_transaction_t { ///< NOTE: this field is re-written to be used in a new way. ///< - Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00. size_t length; ///< Total data length, in bits - size_t rxlength; ///< Total data length received, should be not greater than ``length`` in full-duplex mode. (0 defaults this to the value of ``length``) + size_t rxlength; ///< Total data length received, should be not greater than ``length`` in full-duplex mode (0 defaults this to the value of ``length``). void *user; ///< User-defined variable. Can be used to store eg transaction ID. union { const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 0e42be78f7..ea5f8032ed 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -578,17 +578,21 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t * { BaseType_t r; SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG); + //check transmission length SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0 ||trans_desc->rxlength <= 32, "rxdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG); SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_TXDATA)==0 ||trans_desc->length <= 32, "txdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG); - SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG); - 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->cfg.flags & SPI_DEVICE_HALFDUPLEX) || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG); + //check working mode + SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG); + 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( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || handle->host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL) + || !(trans_desc->flags & SPI_TRANS_USE_TXDATA || trans_desc->tx_buffer!=NULL), "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG ); - //Default rxlength to be the same as length, if not filled in. + //In Full duplex mode, default rxlength to be the same as length, if not filled in. // set rxlength to length is ok, even when rx buffer=NULL - if (trans_desc->rxlength==0) { + if (trans_desc->rxlength==0 && !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)) { trans_desc->rxlength=trans_desc->length; } -- 2.40.0