mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
fix(driver_spi): add check and guide for encrypted psram transfer
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -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
|
||||
------------
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 位的传输事务
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -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` 错误。
|
||||
|
||||
使用驱动程序
|
||||
------------
|
||||
|
||||
|
||||
@@ -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 中的数据。
|
||||
|
||||
Reference in New Issue
Block a user