From 1c52acdf86cdb491599fdb4927e3b54222340b34 Mon Sep 17 00:00:00 2001 From: wanckl Date: Tue, 28 Jul 2026 17:24:01 +0800 Subject: [PATCH] fix(driver_spi): add check and guide for encrypted psram transfer --- components/esp_driver_spi/src/gpspi/spi_common.c | 4 +++- components/esp_driver_spi/src/gpspi/spi_slave.c | 6 ++++-- .../esp_driver_spi/test_apps/master/main/test_spi_master.c | 7 ++++++- .../esp_driver_spi/test_apps/slave/main/test_spi_slave.c | 4 ++++ .../test_apps/slave_hd/main/test_spi_slave_hd.c | 5 ++++- docs/en/api-reference/peripherals/spi_master.rst | 4 ++++ docs/en/api-reference/peripherals/spi_slave.rst | 4 ++++ docs/en/api-reference/peripherals/spi_slave_hd.rst | 4 ++++ docs/zh_CN/api-reference/peripherals/spi_master.rst | 6 +++++- docs/zh_CN/api-reference/peripherals/spi_slave.rst | 4 ++++ docs/zh_CN/api-reference/peripherals/spi_slave_hd.rst | 4 ++++ 11 files changed, 46 insertions(+), 6 deletions(-) diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index f4b7ea637c5..6fd5438fc8f 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -485,7 +485,9 @@ esp_err_t SPI_COMMON_ISR_ATTR spicommon_dma_setup_priv_buffer(spi_host_device_t need_malloc |= (use_psram || bus_attr->cache_align_int > 1) ? (((uint32_t)buffer | len) & (alignment - 1)) : (((uint32_t)buffer) & (alignment - 1)); uint32_t align_len = (len + alignment - 1) & (~(alignment - 1)); // up align alignment ESP_EARLY_LOGV(SPI_TAG, "SPI%d %s %p, len %d, is_ptr_ext %d, use_psram: %d, alignment: %d, need_malloc: %d from %s", host_id + 1, is_tx ? "TX" : "RX", buffer, len, is_ptr_ext, use_psram, alignment, need_malloc, (mem_cap & MALLOC_CAP_SPIRAM) ? "psram" : "internal"); - +#if CONFIG_SECURE_FLASH_ENC_ENABLED || CONFIG_SPIRAM_ECC_ENABLE + ESP_RETURN_ON_FALSE_ISR(!(use_psram && (len & (alignment - 1))), ESP_ERR_INVALID_ARG, SPI_TAG, "len %d must align to alignment %d when using psram buffer with encryption or ECC", len, alignment); +#endif if (need_malloc) { ESP_RETURN_ON_FALSE_ISR(auto_malloc, ESP_ERR_INVALID_STATE, SPI_TAG, "%s addr&len not align to %d, or not dma_capable, suggest use 'heap_caps_malloc' or enable auto_align", is_tx ? "TX" : "RX", alignment); uint32_t *temp = heap_caps_aligned_alloc(alignment, align_len, mem_cap); diff --git a/components/esp_driver_spi/src/gpspi/spi_slave.c b/components/esp_driver_spi/src/gpspi/spi_slave.c index ac02dd8a6f2..acef784913c 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave.c @@ -430,12 +430,14 @@ 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 ? trans->length : trans->tx_length) + 7) / 8, true, true, auto_malloc, &priv_trans->tx_buffer); + size_t tx_bytes_len = ((trans->length ? trans->length : trans->tx_length) + 7) / 8; + size_t rx_bytes_len = ((trans->length ? trans->length : trans->rx_length) + 7) / 8; + esp_err_t ret = spicommon_dma_setup_priv_buffer(spihost[host]->id, (uint32_t *)trans->tx_buffer, tx_bytes_len, 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 ? trans->length : trans->rx_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, rx_bytes_len, false, true, auto_malloc, &priv_trans->rx_buffer); if (ret != ESP_OK) { spi_slave_uninstall_priv_trans(host, priv_trans); } diff --git a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c index d71e3e64ebc..daf626757be 100644 --- a/components/esp_driver_spi/test_apps/master/main/test_spi_master.c +++ b/components/esp_driver_spi/test_apps/master/main/test_spi_master.c @@ -2097,7 +2097,7 @@ TEST_CASE("test_spi_master_auto_sleep_retention", "[spi]") #if CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE #define TEST_EDMA_PSRAM_TRANS_NUM 5 -#define TEST_EDMA_TRANS_LEN 20000 +#define TEST_EDMA_TRANS_LEN 20480 #define TEST_EDMA_BUFFER_SZ (TEST_EDMA_PSRAM_TRANS_NUM * TEST_EDMA_TRANS_LEN) void test_spi_psram_trans(spi_device_handle_t dev_handle, void *tx, void *rx) @@ -2109,6 +2109,9 @@ void test_spi_psram_trans(spi_device_handle_t dev_handle, void *tx, void *rx) int trans_len = TEST_EDMA_TRANS_LEN - TEST_EDMA_PSRAM_TRANS_NUM / 2; for (uint8_t cnt = 0; cnt < TEST_EDMA_PSRAM_TRANS_NUM; cnt ++) { +#if CONFIG_SECURE_FLASH_ENC_ENABLED + trans_len = TEST_EDMA_TRANS_LEN; // encrypted chip don't support unaligned psram transfer +#endif trans_cfg.length = trans_len * 8; trans_cfg.rxlength = trans_len * 8; trans_cfg.flags = (cnt % 2) ? 0 : SPI_TRANS_DMA_USE_PSRAM; @@ -2160,8 +2163,10 @@ TEST_CASE("SPI_Master: PSRAM buffer transaction via EDMA", "[spi]") spi_device_polling_start(dev_handle, &trans_cfg, portMAX_DELAY); uint32_t after = esp_get_free_heap_size(); printf("mem_diff: %ld, trans_len: %d\n", after - before, TEST_EDMA_TRANS_LEN); +#if !CONFIG_SECURE_FLASH_ENC_ENABLED // rx buffer still potential re-malloc from psram even if SPI_TRANS_DMA_USE_PSRAM is set TEST_ASSERT(i ? (before - after) < 2 * TEST_EDMA_TRANS_LEN : (before - after) > 2 * TEST_EDMA_TRANS_LEN); +#endif spi_device_polling_end(dev_handle, portMAX_DELAY); printf("TX fail: %d, RX fail: %d\n", !!(trans_cfg.flags & SPI_TRANS_DMA_TX_FAIL), !!(trans_cfg.flags & SPI_TRANS_DMA_RX_FAIL)); if (!i) { // data should be correct if using auto malloc 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 ff5d05f024d..5962224827e 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 @@ -300,7 +300,9 @@ TEST_CASE("test slave using external ram", "[spi]") for (int i = 0; i < 6; i ++) { test_fill_random_to_buffers_dualboard(7 + i, master_tx, slave_ext_tx, PSRAM_TRANS_LEN); +#if !CONFIG_SECURE_FLASH_ENC_ENABLED // encrypted chip don't support unaligned psram transfer slave_tans.length -= i * 8; +#endif master_tans.length = slave_tans.length; master_tans.rxlength = slave_tans.length; ESP_LOGI(SLAVE_TAG, "Test freq: %ld, tx: %p, rx: %p, len: %d", master_tans.override_freq_hz, slave_tans.tx_buffer, slave_tans.rx_buffer, slave_tans.length / 8); @@ -315,7 +317,9 @@ TEST_CASE("test slave using external ram", "[spi]") spi_master_trans_impl_gpio(buscfg, PIN_NUM_CS, 0, (uint8_t *)master_tans.tx_buffer, master_tans.rx_buffer, master_tans.length / 8, false); #endif ESP_LOGI(SLAVE_TAG, "slave malloc: %ld", after - before); +#if !CONFIG_SECURE_FLASH_ENC_ENABLED TEST_ASSERT(i ? (before - after) > PSRAM_TRANS_LEN : (before - after) < PSRAM_TRANS_LEN); +#endif TEST_ESP_OK(spi_slave_get_trans_result(TEST_SPI_HOST, &out_trans, portMAX_DELAY)); TEST_ASSERT_EQUAL(master_tans.length, slave_tans.trans_len); diff --git a/components/esp_driver_spi/test_apps/slave_hd/main/test_spi_slave_hd.c b/components/esp_driver_spi/test_apps/slave_hd/main/test_spi_slave_hd.c index 97e04ed1638..218786027d4 100644 --- a/components/esp_driver_spi/test_apps/slave_hd/main/test_spi_slave_hd.c +++ b/components/esp_driver_spi/test_apps/slave_hd/main/test_spi_slave_hd.c @@ -1095,7 +1095,7 @@ static esp_err_t (*hd_get_trans_res[2])(spi_host_device_t host_id, spi_slave_cha spi_slave_hd_get_trans_res, spi_slave_hd_get_append_trans_res }; -#define TEST_PSRAM_TRANS_LEN 1000 +#define TEST_PSRAM_TRANS_LEN 1600 TEST_CASE("test slave hd edma segment and append mode", "[spi]") { uint8_t *mst_tx = heap_caps_malloc(TEST_PSRAM_TRANS_LEN, MALLOC_CAP_DEFAULT); @@ -1105,6 +1105,9 @@ TEST_CASE("test slave hd edma segment and append mode", "[spi]") spi_slave_hd_data_t *ret_trans, tx_data = { .data = slv_tx, .len = TEST_PSRAM_TRANS_LEN, +#if CONFIG_SECURE_FLASH_ENC_ENABLED + .flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO, // encrypted chip has different alignment +#endif }, rx_data = { .data = slv_rx, .len = TEST_PSRAM_TRANS_LEN, diff --git a/docs/en/api-reference/peripherals/spi_master.rst b/docs/en/api-reference/peripherals/spi_master.rst index 3576667f006..95483c8338a 100644 --- a/docs/en/api-reference/peripherals/spi_master.rst +++ b/docs/en/api-reference/peripherals/spi_master.rst @@ -369,6 +369,10 @@ The example code for the SPI Master driver can be found in the :example:`periphe Note that this feature shares bandwidth (bus frequency * bus bits width) with MSPI bus, so GPSPI transfer bandwidth should be less than PSRAM bandwidth, **otherwise transmission data may be lost**. You can check the return value or :c:macro:`SPI_TRANS_DMA_RX_FAIL` and :c:macro:`SPI_TRANS_DMA_TX_FAIL` flags after the transaction is finished to check if error occurs during the transmission. If the transaction returns :c:macro:`ESP_ERR_INVALID_STATE` error, the transaction fails. + .. note:: + + When encryption is enabled, there are stricter alignment requirements for PSRAM buffer transfers, usually only supporting 16-byte alignment. For unaligned transfers, :c:macro:`ESP_ERR_INVALID_ARG` error will be returned. You can switch to internal memory or remove the :c:macro:`SPI_TRANS_DMA_USE_PSRAM` flag. + Transactions with Data Not Exceeding 32 Bits ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/en/api-reference/peripherals/spi_slave.rst b/docs/en/api-reference/peripherals/spi_slave.rst index cab843c629c..41395fbccec 100644 --- a/docs/en/api-reference/peripherals/spi_slave.rst +++ b/docs/en/api-reference/peripherals/spi_slave.rst @@ -88,6 +88,10 @@ As not every transaction requires both writing and reading data, you can choose Note that this feature shares the MSPI bus bandwidth (bus frequency * bus width), so the transmission bandwidth of the host to this device should be less than the PSRAM bandwidth, otherwise **data may be lost**, and the ``spi_slave_transmit`` function will return the :c:macro:`ESP_ERR_INVALID_STATE` error. + .. note:: + + When encryption is enabled, there are stricter alignment requirements for PSRAM buffer transfers, usually only supporting 16-byte alignment. For unaligned transfers, :c:macro:`ESP_ERR_INVALID_ARG` error will be returned. + Driver Usage ------------ diff --git a/docs/en/api-reference/peripherals/spi_slave_hd.rst b/docs/en/api-reference/peripherals/spi_slave_hd.rst index a627789e480..c0168735744 100644 --- a/docs/en/api-reference/peripherals/spi_slave_hd.rst +++ b/docs/en/api-reference/peripherals/spi_slave_hd.rst @@ -71,6 +71,10 @@ To send data to the master through the sending DMA channel, the application shou Note that this feature shares the MSPI bus bandwidth (bus frequency * bus width), so the transmission bandwidth of the host to this device should be less than the PSRAM bandwidth, otherwise **data may be lost**, and then getting the transmission result will return the :c:macro:`ESP_ERR_INVALID_STATE` error. + .. note:: + + When encryption is enabled, there are stricter alignment requirements for PSRAM buffer transfers, usually only supporting 16-byte alignment. For unaligned transfers, :c:macro:`ESP_ERR_INVALID_ARG` error will be returned. + The application should check the result of data sending by calling :cpp:func:`spi_slave_hd_get_trans_res` with the channel set as :cpp:enumerator:`SPI_SLAVE_CHAN_TX`. This function blocks until the transaction with the command ``Rd_DMA`` from the master successfully completes (or timeout). The ``out_trans`` argument of the function outputs the pointer of the data descriptor which is just finished, providing information about the sending. Receiving data from the master through the receiving DMA channel is quite similar. The application calls :cpp:func:`spi_slave_hd_queue_trans` with proper data descriptor and the channel argument of :cpp:enumerator:`SPI_SLAVE_CHAN_RX`. And the application calls the :cpp:func:`spi_slave_hd_get_trans_res` later to get the descriptor to the receiving buffer before it handles the data in the receiving buffer. diff --git a/docs/zh_CN/api-reference/peripherals/spi_master.rst b/docs/zh_CN/api-reference/peripherals/spi_master.rst index be9d3c8e6b6..ef412179860 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_master.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_master.rst @@ -365,10 +365,14 @@ SPI 主机驱动程序的示例代码存放在 ESP-IDF 示例项目的 :example: 使用 PSRAM 的传输事务 ^^^^^^^^^^^^^^^^^^^^^^ - {IDF_TARGET_NAME} 支持 GPSPI Master 通过 DMA 直接传输 PSRAM 存储的数据而不用内部额外的零时拷贝,应此可以节省内存,在传输配置中添加 :c:macro:`SPI_TRANS_DMA_USE_PSRAM` 标志信号即可使用。 + {IDF_TARGET_NAME} 支持 GPSPI Master 通过 DMA 直接传输 PSRAM 存储的数据而不用内部额外的零时拷贝,因此可以节省内存,在传输配置中添加 :c:macro:`SPI_TRANS_DMA_USE_PSRAM` 标志信号即可使用。 请注意该功能共享 MSPI 总线带宽(总线频率 * 总线位宽),因此 GPSPI 传输带宽应小于 PSRAM 带宽,否则 **可能会丢失传输数据**。可通过在传输结束时检查返回值或 :c:macro:`SPI_TRANS_DMA_RX_FAIL` 和 :c:macro:`SPI_TRANS_DMA_TX_FAIL` 标志信号来判断传输是否发生了错误。若传输事务返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误,则传输事务失败。 + .. note:: + + 当开启加密功能时,使用 PSRAM Buffer 的传输有更严格的对齐要求,通常为仅支持 16 字节对齐的传输。对于不对齐的传输,会返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。可改为使用内部内存,或取消 :c:macro:`SPI_TRANS_DMA_USE_PSRAM` 标志。 + 传输数据小于 32 位的传输事务 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/peripherals/spi_slave.rst b/docs/zh_CN/api-reference/peripherals/spi_slave.rst index 948df4e7d74..996a657d809 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_slave.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_slave.rst @@ -88,6 +88,10 @@ SPI 传输事务 请注意该功能共享 MSPI 总线带宽(总线频率 * 总线位宽),因此主机对该设备的传输带宽应小于 PSRAM 带宽,否则 **可能会丢失传输数据**,此时 ``spi_slave_transmit`` 函数将会返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。 + .. note:: + + 当开启加密功能时,使用 PSRAM Buffer 的传输有更严格的对齐要求,通常为仅支持 16 字节对齐的传输。对于不对齐的传输,会返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。 + 使用驱动程序 ------------ diff --git a/docs/zh_CN/api-reference/peripherals/spi_slave_hd.rst b/docs/zh_CN/api-reference/peripherals/spi_slave_hd.rst index 0b3f259ccf2..fd468a73bb9 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_slave_hd.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_slave_hd.rst @@ -71,6 +71,10 @@ SPI 从机半双工模式 请注意该功能共享 MSPI 总线带宽(总线频率 * 总线位宽),因此主机对该设备的传输带宽应小于 PSRAM 带宽,否则 **可能会丢失传输数据**,此时获取传输结果会返回 :c:macro:`ESP_ERR_INVALID_STATE` 错误。 + .. note:: + + 当开启加密功能时,使用 PSRAM Buffer 的传输有更严格的对齐要求,通常为仅支持 16 字节对齐的传输。对于不对齐的传输,会返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。 + 应用程序需要检查数据发送的结果。为此,应用程序可以调用 :cpp:func:`spi_slave_hd_get_trans_res`,并将通道参数设置为 :cpp:enumerator:`SPI_SLAVE_CHAN_TX`。该函数将阻塞程序,直到主设备发起的 Rd_DMA 命令事务成功完成或超时。函数中的参数 ``out_trans`` 将输出刚刚完成的数据描述符的指针,从而提供有关已完成的发送操作的信息。 通过 DMA 通道从主设备接收数据的操作与发送数据类似。应用程序需要使用正确的数据描述符调用 :cpp:func:`spi_slave_hd_queue_trans`,并将通道参数设置为 :cpp:enumerator:`SPI_SLAVE_CHAN_RX`。随后,应用程序调用 :cpp:func:`spi_slave_hd_get_trans_res` 获取接收 buffer 的描述符,然后处理接收 buffer 中的数据。