Skip to content

Commit 8a9dc46

Browse files
committed
Merge branch 'bugfix/spi_master_add_dummy_check' into 'master'
spi_master: add dummy check when both mosi and miso are set Closes IDF-1872 and IDF-266 See merge request espressif/esp-idf!9406
2 parents 7e2511f + fc6010c commit 8a9dc46

File tree

4 files changed

+23
-17
lines changed

4 files changed

+23
-17
lines changed

components/driver/spi_master.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
352352

353353
spi_hal_timing_conf_t temp_timing_conf;
354354

355-
esp_err_t ret = spi_hal_get_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle,
355+
esp_err_t ret = spi_hal_cal_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle,
356356
!(bus_attr->flags & SPICOMMON_BUSFLAG_IOMUX_PINS),
357357
dev_config->input_delay_ns, &freq,
358358
&temp_timing_conf);
@@ -663,32 +663,37 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
663663
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
664664
spi_host_t *host = handle->host;
665665
const spi_bus_attr_t* bus_attr = host->bus_attr;
666+
bool tx_enabled = (trans_desc->flags & SPI_TRANS_USE_TXDATA) || (trans_desc->tx_buffer);
667+
bool rx_enabled = (trans_desc->flags & SPI_TRANS_USE_RXDATA) || (trans_desc->rx_buffer);
668+
spi_transaction_ext_t *t_ext = (spi_transaction_ext_t *)trans_desc;
669+
bool dummy_enabled = (((trans_desc->flags & SPI_TRANS_VARIABLE_DUMMY)? t_ext->dummy_bits: handle->cfg.dummy_bits) != 0);
670+
bool extra_dummy_enabled = handle->timing_conf.timing_dummy;
671+
bool is_half_duplex = ((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) != 0);
672+
666673
//check transmission length
667674
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);
668675
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);
669676
SPI_CHECK(trans_desc->length <= bus_attr->max_transfer_sz*8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG);
670677
SPI_CHECK(trans_desc->rxlength <= bus_attr->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
671-
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);
678+
SPI_CHECK(is_half_duplex || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG);
672679
//check working mode
673680
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);
674-
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);
681+
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "incompatible iface params", ESP_ERR_INVALID_ARG);
675682
#ifdef CONFIG_IDF_TARGET_ESP32
676-
SPI_CHECK( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || bus_attr->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
677-
|| !(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 );
683+
SPI_CHECK(!is_half_duplex || bus_attr->dma_chan == 0 || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
678684
#endif
679685
//MOSI phase is skipped only when both tx_buffer and SPI_TRANS_USE_TXDATA are not set.
680-
SPI_CHECK(trans_desc->length != 0 || (trans_desc->tx_buffer == NULL && !(trans_desc->flags & SPI_TRANS_USE_TXDATA)),
681-
"trans tx_buffer should be NULL and SPI_TRANS_USE_TXDATA should be cleared to skip MOSI phase.", ESP_ERR_INVALID_ARG);
686+
SPI_CHECK(trans_desc->length != 0 || !tx_enabled, "trans tx_buffer should be NULL and SPI_TRANS_USE_TXDATA should be cleared to skip MOSI phase.", ESP_ERR_INVALID_ARG);
682687
//MISO phase is skipped only when both rx_buffer and SPI_TRANS_USE_RXDATA are not set.
683688
//If set rxlength=0 in full_duplex mode, it will be automatically set to length
684-
SPI_CHECK(!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || trans_desc->rxlength != 0 ||
685-
(trans_desc->rx_buffer == NULL && ((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0)),
686-
"trans rx_buffer should be NULL and SPI_TRANS_USE_RXDATA should be cleared to skip MISO phase.", ESP_ERR_INVALID_ARG);
689+
SPI_CHECK(!is_half_duplex || trans_desc->rxlength != 0 || !rx_enabled, "trans rx_buffer should be NULL and SPI_TRANS_USE_RXDATA should be cleared to skip MISO phase.", ESP_ERR_INVALID_ARG);
687690
//In Full duplex mode, default rxlength to be the same as length, if not filled in.
688691
// set rxlength to length is ok, even when rx buffer=NULL
689-
if (trans_desc->rxlength==0 && !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)) {
692+
if (trans_desc->rxlength==0 && !is_half_duplex) {
690693
trans_desc->rxlength=trans_desc->length;
691694
}
695+
//Dummy phase is not available when both data out and in are enabled, regardless of FD or HD mode.
696+
SPI_CHECK(!tx_enabled || !rx_enabled || !dummy_enabled || !extra_dummy_enabled, "Dummy phase is not available when both data out and in are enabled", ESP_ERR_INVALID_ARG);
692697

693698
return ESP_OK;
694699
}

components/soc/include/hal/spi_hal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal);
169169
* Utils
170170
* ---------------------------------------------------------*/
171171
/**
172-
* Get the configuration of clock and timing. The configuration will be used when ``spi_hal_setup_device``.
172+
* Calculate the configuration of clock and timing. The configuration will be used when ``spi_hal_setup_device``.
173173
*
174174
* It is highly suggested to do this at initialization, since it takes long time.
175175
*
@@ -185,7 +185,7 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal);
185185
*
186186
* @return ESP_OK if desired is available, otherwise fail.
187187
*/
188-
esp_err_t spi_hal_get_clock_conf(const spi_hal_context_t *hal, int speed_hz, int duty_cycle, bool use_gpio, int input_delay_ns, int *out_freq, spi_hal_timing_conf_t *timing_conf);
188+
esp_err_t spi_hal_cal_clock_conf(const spi_hal_context_t *hal, int speed_hz, int duty_cycle, bool use_gpio, int input_delay_ns, int *out_freq, spi_hal_timing_conf_t *timing_conf);
189189

190190
/**
191191
* Get the frequency actual used.

components/soc/src/hal/spi_hal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void spi_hal_deinit(spi_hal_context_t *hal)
4949
}
5050
}
5151

52-
esp_err_t spi_hal_get_clock_conf(const spi_hal_context_t *hal, int speed_hz, int duty_cycle, bool use_gpio, int input_delay_ns, int *out_freq, spi_hal_timing_conf_t *timing_conf)
52+
esp_err_t spi_hal_cal_clock_conf(const spi_hal_context_t *hal, int speed_hz, int duty_cycle, bool use_gpio, int input_delay_ns, int *out_freq, spi_hal_timing_conf_t *timing_conf)
5353
{
5454
spi_hal_timing_conf_t temp_conf;
5555

docs/en/api-reference/peripherals/spi_master.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -520,10 +520,11 @@ Known Issues
520520
This can prohibit you from transmitting and receiving data longer than 64 bytes.
521521
3. Try using the command and address fields to replace the write phase.
522522

523-
2. Full-duplex transactions are not compatible with the *dummy bit workaround*, hence the frequency is limited. See :ref:`dummy
524-
bit speed-up workaround <dummy_bit_workaround>`.
523+
2. Full-duplex transactions are not compatible with the *dummy bit workaround*, hence the frequency is limited. See :ref:`dummy bit speed-up workaround <dummy_bit_workaround>`.
525524

526-
3. ``cs_ena_pretrans`` is not compatible with the command and address phases of full-duplex transactions.
525+
3. ``dummy_bits`` in :cpp:type:`spi_device_interface_config_t` and :cpp:type:`spi_transaction_ext_t` are not available when SPI read and write phases are both enabled (regardless of full duplex or half duplex mode).
526+
527+
4. ``cs_ena_pretrans`` is not compatible with the command and address phases of full-duplex transactions.
527528

528529

529530
Application Example

0 commit comments

Comments
 (0)