From 875b7ab7c0a335d3777db4693a106480d699d48f Mon Sep 17 00:00:00 2001 From: wanckl Date: Fri, 5 Jun 2026 18:04:45 +0800 Subject: [PATCH] feat(driver_spi): slave driver support config different tx/rx length --- .../esp_driver_spi/include/driver/spi_slave.h | 4 +- .../esp_driver_spi/src/gpspi/spi_slave.c | 33 ++++-- .../test_apps/slave/main/test_spi_slave.c | 110 ++++++++++-------- .../esp_hal_gpspi/include/hal/spi_slave_hal.h | 3 +- components/esp_hal_gpspi/spi_slave_hal_iram.c | 15 ++- .../api-reference/peripherals/spi_slave.rst | 2 + .../api-reference/peripherals/spi_slave.rst | 2 + 7 files changed, 103 insertions(+), 66 deletions(-) diff --git a/components/esp_driver_spi/include/driver/spi_slave.h b/components/esp_driver_spi/include/driver/spi_slave.h index 154a50ebb10..5f20bf718bc 100644 --- a/components/esp_driver_spi/include/driver/spi_slave.h +++ b/components/esp_driver_spi/include/driver/spi_slave.h @@ -67,7 +67,9 @@ typedef struct { */ struct spi_slave_transaction_t { uint32_t flags; ///< Bitwise OR of SPI_SLAVE_TRANS_* flags - size_t length; ///< Total data length, in bits + size_t length; ///< Total data length, in bits. It both for TX and RX, do NOT use together with independent length + size_t tx_length; ///< Independent Tx data length, in bits, using with tx_buffer. do NOT use together with `length` + size_t rx_length; ///< Independent Rx data length, in bits, using with rx_buffer. do NOT use together with `length` size_t trans_len; ///< Transaction data length, in bits const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase void *rx_buffer; /**< Pointer to receive buffer, or NULL for no MISO phase. diff --git a/components/esp_driver_spi/src/gpspi/spi_slave.c b/components/esp_driver_spi/src/gpspi/spi_slave.c index 667d2b4995d..dde29953408 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave.c @@ -6,6 +6,7 @@ #include #include +#include #include "esp_types.h" #include "esp_attr.h" #include "esp_check.h" @@ -413,7 +414,8 @@ static void SPI_SLAVE_ISR_ATTR spi_slave_uninstall_priv_trans(spi_host_device_t free(priv_trans->tx_buffer); } if (trans->rx_buffer && (trans->rx_buffer != priv_trans->rx_buffer)) { - memcpy(trans->rx_buffer, priv_trans->rx_buffer, (trans->length + 7) / 8); + size_t compatible_len = trans->rx_length ? trans->rx_length : trans->length; + memcpy(trans->rx_buffer, priv_trans->rx_buffer, (MIN(compatible_len, trans->trans_len) + 7) / 8); free(priv_trans->rx_buffer); } } @@ -429,12 +431,12 @@ static esp_err_t SPI_SLAVE_ATTR spi_slave_setup_priv_trans(spi_host_device_t hos } bool auto_malloc = (trans->flags & SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO); - esp_err_t ret = spicommon_dma_setup_priv_buffer(spihost[host]->id, (uint32_t *)trans->tx_buffer, (trans->length + 7) / 8, true, true, auto_malloc, &priv_trans->tx_buffer); + esp_err_t ret = spicommon_dma_setup_priv_buffer(spihost[host]->id, (uint32_t *)trans->tx_buffer, ((trans->length ? trans->length : trans->tx_length) + 7) / 8, true, true, auto_malloc, &priv_trans->tx_buffer); if (ret != ESP_OK) { spi_slave_uninstall_priv_trans(host, priv_trans); return ret; } - ret = spicommon_dma_setup_priv_buffer(spihost[host]->id, (uint32_t *)trans->rx_buffer, (trans->length + 7) / 8, false, true, auto_malloc, &priv_trans->rx_buffer); + ret = spicommon_dma_setup_priv_buffer(spihost[host]->id, (uint32_t *)trans->rx_buffer, ((trans->length ? trans->length : trans->rx_length) + 7) / 8, false, true, auto_malloc, &priv_trans->rx_buffer); if (ret != ESP_OK) { spi_slave_uninstall_priv_trans(host, priv_trans); } @@ -446,7 +448,12 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi BaseType_t r; SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG); SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG); - SPI_CHECK(trans_desc->length <= spihost[host]->bus_attr->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG); + SPI_CHECK(!(trans_desc->length && (trans_desc->tx_length || trans_desc->rx_length)), "length and tx_length/rx_length are mutually exclusive", ESP_ERR_INVALID_ARG); + SPI_CHECK(trans_desc->length <= spihost[host]->bus_attr->max_transfer_sz * 8, "tx data transfer > host maximum", ESP_ERR_INVALID_ARG); + SPI_CHECK(trans_desc->tx_length <= spihost[host]->bus_attr->max_transfer_sz * 8, "tx data transfer > host maximum", ESP_ERR_INVALID_ARG); + SPI_CHECK(trans_desc->rx_length <= spihost[host]->bus_attr->max_transfer_sz * 8, "rx data transfer > host maximum", ESP_ERR_INVALID_ARG); + SPI_CHECK(!trans_desc->tx_buffer || (trans_desc->tx_length || trans_desc->length), "set tx_buffer but no length or tx_length", ESP_ERR_INVALID_ARG); + SPI_CHECK(!trans_desc->rx_buffer || (trans_desc->rx_length || trans_desc->length), "set rx_buffer but no length or rx_length", ESP_ERR_INVALID_ARG); spi_slave_trans_priv_t priv_trans = {.trans = (spi_slave_transaction_t *)trans_desc}; SPI_CHECK(ESP_OK == spi_slave_setup_priv_trans(host, &priv_trans), "slave setup priv_trans failed", ESP_ERR_NO_MEM); @@ -498,7 +505,12 @@ esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_trans_isr(spi_host_device_t host, c BaseType_t do_yield = pdFALSE; ESP_RETURN_ON_FALSE_ISR(is_valid_host(host), ESP_ERR_INVALID_ARG, SPI_TAG, "invalid host"); ESP_RETURN_ON_FALSE_ISR(spihost[host], ESP_ERR_INVALID_ARG, SPI_TAG, "host not slave"); - ESP_RETURN_ON_FALSE_ISR(trans_desc->length <= spihost[host]->bus_attr->max_transfer_sz * 8, ESP_ERR_INVALID_ARG, SPI_TAG, "data transfer > host maximum"); + ESP_RETURN_ON_FALSE_ISR(!(trans_desc->length && (trans_desc->tx_length || trans_desc->rx_length)), ESP_ERR_INVALID_ARG, SPI_TAG, "length and tx_length/rx_length are mutually exclusive"); + ESP_RETURN_ON_FALSE_ISR(trans_desc->length <= spihost[host]->bus_attr->max_transfer_sz * 8, ESP_ERR_INVALID_ARG, SPI_TAG, "tx data transfer > host maximum"); + ESP_RETURN_ON_FALSE_ISR(trans_desc->tx_length <= spihost[host]->bus_attr->max_transfer_sz * 8, ESP_ERR_INVALID_ARG, SPI_TAG, "tx data transfer > host maximum"); + ESP_RETURN_ON_FALSE_ISR(trans_desc->rx_length <= spihost[host]->bus_attr->max_transfer_sz * 8, ESP_ERR_INVALID_ARG, SPI_TAG, "rx data transfer > host maximum"); + ESP_RETURN_ON_FALSE_ISR(!trans_desc->tx_buffer || (trans_desc->tx_length || trans_desc->length), ESP_ERR_INVALID_ARG, SPI_TAG, "set tx_buffer but no length or tx_length"); + ESP_RETURN_ON_FALSE_ISR(!trans_desc->rx_buffer || (trans_desc->rx_length || trans_desc->length), ESP_ERR_INVALID_ARG, SPI_TAG, "set rx_buffer but no length or rx_length"); spi_slave_trans_priv_t priv_trans = { .trans = (spi_slave_transaction_t *)trans_desc, @@ -507,8 +519,8 @@ esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_trans_isr(spi_host_device_t host, c }; if (spihost[host]->bus_attr->dma_enabled) { // isr api is not allowed to auto_malloc, so don't need to 'uninstall' anything here, return directly - ESP_RETURN_ON_ERROR_ISR(spicommon_dma_setup_priv_buffer(host, (uint32_t *)trans_desc->tx_buffer, (trans_desc->length + 7) / 8, true, true, false, &priv_trans.tx_buffer), SPI_TAG, ""); - ESP_RETURN_ON_ERROR_ISR(spicommon_dma_setup_priv_buffer(host, (uint32_t *)trans_desc->rx_buffer, (trans_desc->length + 7) / 8, false, true, false, &priv_trans.rx_buffer), SPI_TAG, ""); + ESP_RETURN_ON_ERROR_ISR(spicommon_dma_setup_priv_buffer(host, (uint32_t *)trans_desc->tx_buffer, ((trans_desc->length ? trans_desc->length : trans_desc->tx_length) + 7) / 8, true, true, false, &priv_trans.tx_buffer), SPI_TAG, ""); + ESP_RETURN_ON_ERROR_ISR(spicommon_dma_setup_priv_buffer(host, (uint32_t *)trans_desc->rx_buffer, ((trans_desc->length ? trans_desc->length : trans_desc->rx_length) + 7) / 8, false, true, false, &priv_trans.rx_buffer), SPI_TAG, ""); } r = xQueueSendFromISR(spihost[host]->trans_queue, (void *)&priv_trans, &do_yield); if (!r) { @@ -589,14 +601,14 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_tr static void SPI_SLAVE_ISR_ATTR s_spi_slave_dma_prepare_data(spi_dma_ctx_t *dma_ctx, spi_slave_hal_context_t *hal) { if (hal->rx_buffer) { - spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true); + spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, hal->rx_buffer, (hal->rx_bitlen + 7) / 8, true); spi_dma_reset(dma_ctx->rx_dma_chan); spi_slave_hal_hw_prepare_rx(hal->hw); spi_dma_start(dma_ctx->rx_dma_chan, dma_ctx->dmadesc_rx); } if (hal->tx_buffer) { - spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false); + spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, hal->tx_buffer, (hal->tx_bitlen + 7) / 8, false); spi_dma_reset(dma_ctx->tx_dma_chan); spi_slave_hal_hw_prepare_tx(hal->hw); @@ -718,7 +730,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) //We have a transaction. Send it. host->cur_trans = priv_trans; - hal->bitlen = priv_trans.trans->length; + hal->tx_bitlen = priv_trans.trans->tx_length ? priv_trans.trans->tx_length : priv_trans.trans->length; + hal->rx_bitlen = priv_trans.trans->rx_length ? priv_trans.trans->rx_length : priv_trans.trans->length; hal->rx_buffer = priv_trans.rx_buffer; hal->tx_buffer = priv_trans.tx_buffer; diff --git a/components/esp_driver_spi/test_apps/slave/main/test_spi_slave.c b/components/esp_driver_spi/test_apps/slave/main/test_spi_slave.c index 27717ae0dd8..870dc93252e 100644 --- a/components/esp_driver_spi/test_apps/slave/main/test_spi_slave.c +++ b/components/esp_driver_spi/test_apps/slave/main/test_spi_slave.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -152,7 +152,7 @@ TEST_CASE("test fullduplex slave with only TX direction", "[spi]") spi_slave_transaction_t slave_t; spi_slave_transaction_t *out; memset(&slave_t, 0, sizeof(spi_slave_transaction_t)); - slave_t.length = 8 * 32; + slave_t.tx_length = 8 * 32; slave_t.tx_buffer = slave_txbuf; slave_t.rx_buffer = NULL; slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO; @@ -189,7 +189,7 @@ TEST_CASE("test fullduplex slave with only TX direction", "[spi]") } #define TEST_SLV_RX_BUF_LEN 15 -TEST_CASE("Test slave rx no_dma overwrite when length below/over config", "[spi]") +TEST_CASE("Test slave rx_buffer overwrite if trans_len below/over config_len", "[spi]") { spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS; @@ -198,65 +198,79 @@ TEST_CASE("Test slave rx no_dma overwrite when length below/over config", "[spi] spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spidev0)); - spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG(); - TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &buscfg, &slvcfg, SPI_DMA_DISABLED)); + for (int use_dma = 0; use_dma < 2; use_dma++) { + printf("\n------------- DMA: %s -------------\n", use_dma ? "Enable" : "Disable"); + spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG(); + TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &buscfg, &slvcfg, use_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED)); + same_pin_func_sel(TEST_SPI_HOST, TEST_SLAVE_HOST, buscfg, devcfg.spics_io_num); - //initialize master and slave on the same pins break some of the output configs, fix them - same_pin_func_sel(TEST_SPI_HOST, TEST_SLAVE_HOST, buscfg, devcfg.spics_io_num); + uint8_t master_tx[TEST_SLV_RX_BUF_LEN], master_rx[TEST_SLV_RX_BUF_LEN]; + uint8_t slave_tx[TEST_SLV_RX_BUF_LEN], slave_rx[TEST_SLV_RX_BUF_LEN]; + for (uint8_t i = 0; i < TEST_SLV_RX_BUF_LEN; i++) { + master_tx[i] = TEST_SLV_RX_BUF_LEN - i; + slave_tx[i] = i + 1; + slave_rx[i] = 100; + } - uint8_t master_tx[TEST_SLV_RX_BUF_LEN], slave_rx[TEST_SLV_RX_BUF_LEN]; - for (uint8_t i = 0; i < TEST_SLV_RX_BUF_LEN; i++) { - master_tx[i] = TEST_SLV_RX_BUF_LEN - i; - slave_rx[i] = 100; - } + //------------------------------ trans_len < config_len ------------------------------ + printf("Testing trans_len < config_len:\n"); + spi_slave_transaction_t *slave_out, slave_tans = { + .tx_buffer = slave_tx, + .rx_buffer = slave_rx, + .tx_length = 8 * 10, // let tx shorter than rx but larger than trans_len + .rx_length = 8 * (TEST_SLV_RX_BUF_LEN), + .flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO, + }; + TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_tans, portMAX_DELAY)); - //------------------------------ trans_len < config_len ------------------------------ - printf("Testing trans_len < config_len:\n"); - spi_slave_transaction_t *slave_out, slave_tans = { - .length = 8 * TEST_SLV_RX_BUF_LEN, - .rx_buffer = slave_rx, - }; - TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_tans, portMAX_DELAY)); + spi_transaction_t master_tans = { + .length = 8 * 7, + .rx_buffer = master_rx, + .tx_buffer = master_tx, + }; + memset(master_rx, 0x55, TEST_SLV_RX_BUF_LEN); + spi_device_polling_transmit(spidev0, &master_tans); - spi_transaction_t master_tans = { - .length = 8 * 7, - .tx_buffer = master_tx, - }; - spi_device_polling_transmit(spidev0, &master_tans); + TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &slave_out, portMAX_DELAY)); - TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &slave_out, portMAX_DELAY)); + ESP_LOGI(SLAVE_TAG, "trans_len: %d, config_len rx %d tx %d", master_tans.length / 8, slave_tans.rx_length / 8, slave_tans.tx_length / 8); + ESP_LOG_BUFFER_HEX("master tx", master_tans.tx_buffer, master_tans.length / 8); + ESP_LOG_BUFFER_HEX("slave rx", slave_tans.rx_buffer, TEST_SLV_RX_BUF_LEN); + ESP_LOG_BUFFER_HEX("master rx", master_rx, TEST_SLV_RX_BUF_LEN); - ESP_LOGI(SLAVE_TAG, "trans_len: %d, config_len %d", slave_tans.trans_len / 8, slave_tans.length / 8); - ESP_LOG_BUFFER_HEX("master tx", master_tans.tx_buffer, master_tans.length / 8); - ESP_LOG_BUFFER_HEX("slave rx", slave_tans.rx_buffer, TEST_SLV_RX_BUF_LEN); + TEST_ASSERT_EQUAL(master_tans.length, slave_tans.trans_len); + for (uint8_t i = slave_tans.trans_len; i < slave_tans.rx_length; i += 8) { + TEST_ASSERT_EQUAL(slave_rx[i / 8], 100); + } + TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_tx, master_rx, master_tans.length / 8); - TEST_ASSERT_EQUAL(master_tans.length, slave_tans.trans_len); - for (uint8_t i = slave_tans.trans_len; i < slave_tans.length; i += 8) { - TEST_ASSERT_EQUAL(slave_rx[i / 8], 100); - } + //------------------------------ trans_len > config_len ------------------------------ + printf("Testing trans_len > config_len:\n"); + slave_tans.rx_length = 8 * 8; + slave_tans.tx_length = 8 * 10; + TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_tans, portMAX_DELAY)); - //------------------------------ trans_len > config_len ------------------------------ - printf("Testing trans_len > config_len:\n"); - slave_tans.length = 8 * 9; - TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_tans, portMAX_DELAY)); + master_tans.length = 8 * 13, + master_tans.rxlength = 8 * 13; + spi_device_polling_transmit(spidev0, &master_tans); - master_tans.length = 8 * 11, - spi_device_polling_transmit(spidev0, &master_tans); + TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &slave_out, portMAX_DELAY)); - TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &slave_out, portMAX_DELAY)); - - ESP_LOGI(SLAVE_TAG, "trans_len: %d, config_len %d", master_tans.length / 8, slave_tans.trans_len / 8); - ESP_LOG_BUFFER_HEX("master tx", master_tans.tx_buffer, master_tans.length / 8); - ESP_LOG_BUFFER_HEX("slave rx", slave_tans.rx_buffer, TEST_SLV_RX_BUF_LEN); + ESP_LOGI(SLAVE_TAG, "trans_len: %d, config_len rx %d tx %d", master_tans.length / 8, slave_tans.rx_length / 8, slave_tans.tx_length / 8); + ESP_LOG_BUFFER_HEX("master tx", master_tans.tx_buffer, master_tans.length / 8); + ESP_LOG_BUFFER_HEX("slave rx", slave_tans.rx_buffer, TEST_SLV_RX_BUF_LEN); + ESP_LOG_BUFFER_HEX("master rx", master_rx, TEST_SLV_RX_BUF_LEN); #if !CONFIG_IDF_TARGET_ESP32 // esp32 already hardware limited trans_len <= config_len - TEST_ASSERT_EQUAL(master_tans.length, slave_tans.trans_len); + TEST_ASSERT_EQUAL(master_tans.length, slave_tans.trans_len); #endif - for (uint8_t i = slave_tans.length; i < TEST_SLV_RX_BUF_LEN * 8; i += 8) { - TEST_ASSERT_EQUAL(slave_rx[i / 8], 100); - } + for (uint8_t i = slave_tans.rx_length; i < TEST_SLV_RX_BUF_LEN * 8; i += 8) { + TEST_ASSERT_EQUAL(slave_rx[i / 8], 100); + } + TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_tx, master_rx, slave_tans.tx_length / 8); - TEST_ESP_OK(spi_slave_free(TEST_SLAVE_HOST)); + TEST_ESP_OK(spi_slave_free(TEST_SLAVE_HOST)); + } TEST_ESP_OK(spi_bus_remove_device(spidev0)); TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST)); } diff --git a/components/esp_hal_gpspi/include/hal/spi_slave_hal.h b/components/esp_hal_gpspi/include/hal/spi_slave_hal.h index 96effcb09d8..97a18a68367 100644 --- a/components/esp_hal_gpspi/include/hal/spi_slave_hal.h +++ b/components/esp_hal_gpspi/include/hal/spi_slave_hal.h @@ -75,7 +75,8 @@ typedef struct { * Transaction specific (data), all these parameters will be updated to the * peripheral every transaction. */ - uint32_t bitlen; ///< Expected maximum length of the transaction, in bits. + uint32_t tx_bitlen; ///< Expected maximum length of the tx transaction, in bits. + uint32_t rx_bitlen; ///< Expected maximum length of the rx transaction, in bits. const void *tx_buffer; ///< Data to be sent void *rx_buffer; ///< Buffer to hold the received data. diff --git a/components/esp_hal_gpspi/spi_slave_hal_iram.c b/components/esp_hal_gpspi/spi_slave_hal_iram.c index 0fa06f60c60..4712d70b66e 100644 --- a/components/esp_hal_gpspi/spi_slave_hal_iram.c +++ b/components/esp_hal_gpspi/spi_slave_hal_iram.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -46,14 +46,16 @@ void spi_slave_hal_hw_fifo_reset(spi_slave_hal_context_t *hal, bool tx_rst, bool void spi_slave_hal_push_tx_buffer(spi_slave_hal_context_t *hal) { if (hal->tx_buffer) { - spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen); + spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->tx_bitlen); } } void spi_slave_hal_set_trans_bitlen(spi_slave_hal_context_t *hal) { - spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen); - spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen); + // As full-duplex transaction, register need config to max length to ensure both TX and RX can be transferred + uint32_t max_bitlen = (hal->rx_bitlen > hal->tx_bitlen) ? hal->rx_bitlen : hal->tx_bitlen; + spi_ll_slave_set_rx_bitlen(hal->hw, max_bitlen); + spi_ll_slave_set_tx_bitlen(hal->hw, max_bitlen); } void spi_slave_hal_enable_data_line(spi_slave_hal_context_t *hal) @@ -68,12 +70,13 @@ void spi_slave_hal_store_result(spi_slave_hal_context_t *hal) //will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise //the length sent. hal->rcv_bitlen = spi_ll_slave_get_rcv_bitlen(hal->hw); - if (hal->rcv_bitlen == hal->bitlen - 1) { + uint32_t len_max = (hal->rx_bitlen > hal->tx_bitlen) ? hal->rx_bitlen : hal->tx_bitlen; + if (hal->rcv_bitlen == len_max - 1) { hal->rcv_bitlen++; } if (!hal->use_dma && hal->rx_buffer) { //Copy result out - spi_ll_read_buffer(hal->hw, hal->rx_buffer, (hal->rcv_bitlen > hal->bitlen) ? hal->bitlen : hal->rcv_bitlen); + spi_ll_read_buffer(hal->hw, hal->rx_buffer, (hal->rcv_bitlen > hal->rx_bitlen) ? hal->rx_bitlen : hal->rcv_bitlen); } } diff --git a/docs/en/api-reference/peripherals/spi_slave.rst b/docs/en/api-reference/peripherals/spi_slave.rst index 4e330c05705..cab843c629c 100644 --- a/docs/en/api-reference/peripherals/spi_slave.rst +++ b/docs/en/api-reference/peripherals/spi_slave.rst @@ -117,6 +117,8 @@ The amount of data that the driver can read or write to the buffers is limited b If the length of the transmission is greater than the buffer length, only the initial number of bits specified in the :cpp:member:`spi_slave_transaction_t::length` member will be sent and received. In this case, :cpp:member:`spi_slave_transaction_t::trans_len` is set to :cpp:member:`spi_slave_transaction_t::length` instead of the actual transaction length. To meet the actual transaction length requirements, set :cpp:member:`spi_slave_transaction_t::length` to a value greater than the maximum :cpp:member:`spi_slave_transaction_t::trans_len` expected. If the transmission length is shorter than the buffer length, only the data equal to the length of the buffer will be transmitted. +When you need to specify different TX/RX lengths in a single transaction, you can use the :cpp:member:`spi_slave_transaction_t::tx_length` and :cpp:member:`spi_slave_transaction_t::rx_length` members to specify the lengths of TX and RX respectively. This configuration is mutually exclusive with :cpp:member:`spi_slave_transaction_t::length`, and cannot be used simultaneously. + GPIO Matrix and IO_MUX ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/peripherals/spi_slave.rst b/docs/zh_CN/api-reference/peripherals/spi_slave.rst index 4a38cb78760..948df4e7d74 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_slave.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_slave.rst @@ -117,6 +117,8 @@ SPI 传输事务 如果传输长度超过缓存区长度,则只有在 :cpp:member:`spi_slave_transaction_t::length` 中指定的初始比特数会被发送和接收。此时, :cpp:member:`spi_slave_transaction_t::trans_len` 被设置为 :cpp:member:`spi_slave_transaction_t::length` 而非实际传输事务长度。若需满足实际传输事务长度的要求,请将 :cpp:member:`spi_slave_transaction_t::length` 设置为大于 :cpp:member:`spi_slave_transaction_t::trans_len` 预期最大值的值。如果传输长度短于缓存区长度,则只传输与缓存区长度相等的数据。 +当需要在一次传输中单独指定不同的 TX/RX 长度时,可以使用 :cpp:member:`spi_slave_transaction_t::tx_length` 和 :cpp:member:`spi_slave_transaction_t::rx_length` 来分别指定 TX 和 RX 的长度。该配置和 :cpp:member:`spi_slave_transaction_t::length` 互斥,不可同时使用。 + GPIO 交换矩阵和 IO_MUX ----------------------