mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
Merge branch 'bugfix/spi_hd_rx' into 'master'
fix(spi_dma_rx): add check to avoid using SPI half-duplex mode DMA with both MOSI and MISO phases. See merge request !1111
This commit is contained in:
commit
3161854efb
@ -78,7 +78,7 @@ struct spi_transaction_t {
|
||||
///< <b>NOTE: this field, used to be "address" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF3.0.</b>
|
||||
///< - Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00 (in previous version, you may have to write 0x12340000).
|
||||
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
|
||||
|
@ -577,17 +577,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;
|
||||
}
|
||||
|
||||
|
@ -53,14 +53,28 @@ A transaction on the SPI bus consists of five phases, any of which may be skippe
|
||||
|
||||
* The command phase. In this phase, a command (0-16 bit) is clocked out.
|
||||
* The address phase. In this phase, an address (0-64 bit) is clocked out.
|
||||
* The read phase. The slave sends data to the master.
|
||||
* The write phase. The master sends data to the slave.
|
||||
* The dummy phase. The phase is configurable, used to meet the timing requirements.
|
||||
* The read phase. The slave sends data to the master.
|
||||
|
||||
In full duplex, the read and write phases are combined, causing the SPI host to read and
|
||||
write data simultaneously.
|
||||
write data simultaneously. The total transaction length is decided by
|
||||
``dev_conf.command_bits + dev_conf.address_bits + trans_conf.length``, while the ``trans_conf.rx_length``
|
||||
only determins length of data received into the buffer.
|
||||
|
||||
In half duplex, the length of write phase and read phase are decided by ``trans_conf.length`` and
|
||||
``trans_conf.rx_length`` respectively. ** Note that a half duplex transaction with both a read and
|
||||
write phase is not supported when using DMA. ** If such transaction is needed, you have to use one
|
||||
of the alternative solutions:
|
||||
1. use full-duplex mode instead.
|
||||
2. disable the DMA by set the last parameter to 0 in bus initialization function just as belows:
|
||||
``ret=spi_bus_initialize(VSPI_HOST, &buscfg, 0);``
|
||||
|
||||
this may prohibit you from transmitting and receiving data longer than 32 bytes.
|
||||
3. try to use command and address field to replace the write phase.
|
||||
|
||||
The command and address phase are optional in that not every SPI device will need to be sent a command
|
||||
and/or address. Tis is reflected in the device configuration: when the ``command_bits`` or ``data_bits``
|
||||
and/or address. This is reflected in the device configuration: when the ``command_bits`` or ``address_bits``
|
||||
fields are set to zero, no command or address phase is done.
|
||||
|
||||
Something similar is true for the read and write phase: not every transaction needs both data to be written
|
||||
@ -93,9 +107,12 @@ Transaction data
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Normally, data to be transferred to or from a device will be read from or written to a chunk of memory
|
||||
indicated by the ``rx_buffer`` and ``tx_buffer`` members of the transaction structure. The SPI driver
|
||||
may decide to use DMA for transfers, so these buffers should be allocated in DMA-capable memory using
|
||||
``pvPortMallocCaps(size, MALLOC_CAP_DMA)``.
|
||||
indicated by the ``rx_buffer`` and ``tx_buffer`` members of the transaction structure.
|
||||
When DMA is enabled for transfers, these buffers are highly recommended to meet the requirements as belows:
|
||||
1. allocated in DMA-capable memory using ``pvPortMallocCaps(size, MALLOC_CAP_DMA)``;
|
||||
2. 32-bit aligned (start from the boundary and have length of multiples of 4 bytes).
|
||||
If these requirements are not satisfied, efficiency of the transaction will suffer due to the allocation and
|
||||
memcpy of temporary buffers.
|
||||
|
||||
Sometimes, the amount of data is very small making it less than optimal allocating a separate buffer
|
||||
for it. If the data to be transferred is 32 bits or less, it can be stored in the transaction struct
|
||||
@ -107,7 +124,7 @@ as ``tx_data`` and ``rx_data``.
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Display graphics on the ILI9341-based 320x240 LCD: :example:`peripherals/spi_master`.
|
||||
Display graphics on the 320x240 LCD of WROVER-Kits: :example:`peripherals/spi_master`.
|
||||
|
||||
|
||||
API Reference - SPI Common
|
||||
|
Loading…
x
Reference in New Issue
Block a user