diff --git a/components/bt/common/ble_log/src/prph/ble_log_prph_uart_dma.c b/components/bt/common/ble_log/src/prph/ble_log_prph_uart_dma.c index de52fb58c21..8af7851c3bd 100644 --- a/components/bt/common/ble_log/src/prph/ble_log_prph_uart_dma.c +++ b/components/bt/common/ble_log/src/prph/ble_log_prph_uart_dma.c @@ -27,7 +27,7 @@ /* ponytail: data burst disabled — UHCI enforces burst-size alignment (addr+len) on * uhci_transmit() once GDMA weighted arbitration is enabled, and UART log bandwidth * is baud-rate limited anyway, so burst buys nothing here */ -#define BLE_LOG_UART_DMA_BURST_SIZE (0) +#define BLE_LOG_UART_DMA_BURST_SIZE (1) #if BLE_LOG_PRPH_UART_DMA_REDIR #define BLE_LOG_UART_REDIR_BUF_SIZE (512) #define BLE_LOG_UART_REDIR_FLUSH_PERIOD_US (1000 * 1000) diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c index 0c2c30441ef..ebb6f82efe6 100644 --- a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c @@ -272,7 +272,7 @@ hci_driver_uart_dma_uhci_install(void) .max_transmit_size = HCI_TX_MAX_SIZE, /* Total bytes of all segments in one transaction. */ .max_transmit_buffer_count = HCI_TX_MAX_SEGMENT_COUNT, /* Caps uhci_multi_buffer_transmit() array_size. */ .max_receive_internal_mem = HCI_UHCI_RX_DESC_MEM, /* Sizes the RX DMA descriptor chain, not the ring. */ - .dma_burst_size = 32, /* Power-of-two burst; 0 would disable burst. */ + .dma_burst_size = 32, /* Power-of-two burst size in bytes. */ .rx_eof_flags.idle_eof = 1, /* Frame ends when the UART RX line goes idle. */ }; uhci_event_callbacks_t uhci_cbs = { diff --git a/components/bt/porting_btdm/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting_btdm/transport/driver/uart/hci_driver_uart_dma.c index bf863fc387f..bf6830677f2 100644 --- a/components/bt/porting_btdm/transport/driver/uart/hci_driver_uart_dma.c +++ b/components/bt/porting_btdm/transport/driver/uart/hci_driver_uart_dma.c @@ -279,7 +279,7 @@ hci_driver_uart_dma_uhci_install(void) .max_transmit_size = HCI_TX_MAX_SIZE, /* Total bytes of all segments in one transaction. */ .max_transmit_buffer_count = HCI_TX_MAX_SEGMENT_COUNT, /* Caps uhci_multi_buffer_transmit() array_size. */ .max_receive_internal_mem = HCI_UHCI_RX_DESC_MEM, /* Sizes the RX DMA descriptor chain, not the ring. */ - .dma_burst_size = 32, /* Power-of-two burst; 0 would disable burst. */ + .dma_burst_size = 32, /* Power-of-two burst size in bytes. */ .rx_eof_flags.idle_eof = 1, /* Frame ends when the UART RX line goes idle. */ }; uhci_event_callbacks_t uhci_cbs = { diff --git a/components/esp_asrc_adapter/asrc_adapter.c b/components/esp_asrc_adapter/asrc_adapter.c index d5ecf5f0f98..9666152726e 100644 --- a/components/esp_asrc_adapter/asrc_adapter.c +++ b/components/esp_asrc_adapter/asrc_adapter.c @@ -144,7 +144,7 @@ esp_err_t asrc_hw_gdma_create_channel(int asrc_idx, void *user_data, uint16_t ma ESP_GOTO_ON_ERROR(gdma_apply_strategy(dma_tx, &strategy_config), cleanup, TAG, "Fail to apply tx strategy"); ESP_GOTO_ON_ERROR(gdma_apply_strategy(dma_rx, &strategy_config), cleanup, TAG, "Fail to apply rx strategy"); gdma_transfer_config_t transfer_config = { - .max_data_burst_size = max_data_burst_size, + .max_data_burst_size = max_data_burst_size ? max_data_burst_size : 16, .access_ext_mem = true, }; ESP_GOTO_ON_ERROR(gdma_config_transfer(dma_rx, &transfer_config), cleanup, TAG, "Fail to config rx transfer"); diff --git a/components/esp_asrc_adapter/include/asrc_adapter.h b/components/esp_asrc_adapter/include/asrc_adapter.h index fa63966971a..9346e3a25ab 100644 --- a/components/esp_asrc_adapter/include/asrc_adapter.h +++ b/components/esp_asrc_adapter/include/asrc_adapter.h @@ -43,7 +43,7 @@ typedef struct { * * @param[in] asrc_idx ASRC hardware index * @param[in] user_data User context passed to GDMA callbacks - * @param[in] max_data_burst_size Maximum data burst size + * @param[in] max_data_burst_size Maximum data burst size. Set to 0 to use the adapter default. Set to 1 to disable the data burst. * @param[out] dma_tx_chan Returned GDMA TX channel handle * @param[out] dma_rx_chan Returned GDMA RX channel handle * diff --git a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h index 1fddb238ee7..28586232774 100644 --- a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h +++ b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h @@ -77,8 +77,8 @@ typedef struct esp_cam_ctlr_dvp_config { uint32_t external_xtal : 1; /*!< Using external XTAL, if set, xclk_io and dvp output clock will be ignored */ }; /*!< Boolean Flags */ - uint32_t dma_burst_size; /*!< DVP DMA burst transmission block size, set to 0 means to disable the data burst, - other value must be power of 2, e.g., 4/8/16/32/64/128 */ + uint32_t dma_burst_size; /*!< DVP DMA burst size, in bytes, must be a power of 2. + Set to 0 to use the driver default. Set to 1 to disable the data burst. */ uint32_t xclk_freq; /*!< DVP output clock frequency in HZ, only valid if `external_xtal` is set to true */ const esp_cam_ctlr_dvp_pin_config_t *pin; /*!< DVP pin configuration, this will be ignored by "esp_cam_new_dvp_ctlr" if "pin_dont_init" is set */ diff --git a/components/esp_driver_dma/include/esp_async_crc.h b/components/esp_driver_dma/include/esp_async_crc.h index e941d2c55ea..5d5d3596710 100644 --- a/components/esp_driver_dma/include/esp_async_crc.h +++ b/components/esp_driver_dma/include/esp_async_crc.h @@ -52,7 +52,9 @@ typedef bool (*async_crc_isr_cb_t)(async_crc_handle_t crc_hdl, async_crc_event_d typedef struct { uint32_t backlog; /*!< Maximum number of pending CRC requests that can be queued per driver instance. Higher values use more memory but provide better throughput for bursty workloads. */ - size_t dma_burst_size; /*!< DMA transfer burst size, in bytes */ + size_t dma_burst_size; /*!< DMA transfer burst size, in bytes, must be a power of 2. + Set to 0 to use the driver default. + Set to 1 to disable the data burst. */ uint32_t intr_priority; /*!< DMA interrupt priority. 0 means default low/medium priority. */ } async_crc_config_t; diff --git a/components/esp_driver_dma/include/esp_async_memcpy.h b/components/esp_driver_dma/include/esp_async_memcpy.h index 12b74a8001b..9a059f3677e 100644 --- a/components/esp_driver_dma/include/esp_async_memcpy.h +++ b/components/esp_driver_dma/include/esp_async_memcpy.h @@ -52,7 +52,9 @@ typedef bool (*async_memcpy_isr_cb_t)(async_memcpy_handle_t mcp_hdl, async_memcp typedef struct { uint32_t backlog; /*!< Maximum number of transactions that can be prepared in the background */ uint32_t weight; /*!< Weight of async memcpy dma channel, higher weight means higher average bandwidth */ - size_t dma_burst_size; /*!< DMA transfer burst size, in bytes */ + size_t dma_burst_size; /*!< DMA transfer burst size, in bytes, must be a power of 2. + Set to 0 to use the driver default. + Set to 1 to disable the data burst. */ uint32_t flags; /*!< Extra flags to control async memcpy feature */ } async_memcpy_config_t; @@ -160,7 +162,7 @@ esp_err_t esp_async_memcpy_install_dw_gdma(const async_memcpy_config_t *config, * - ESP_FAIL: Install async memcpy driver failed because of other error */ esp_err_t esp_async_memcpy_install(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp) - __attribute__((deprecated("Select a DMA backend explicitly with esp_async_memcpy_install_* instead"))); +__attribute__((deprecated("Select a DMA backend explicitly with esp_async_memcpy_install_* instead"))); /** @endcond */ /** diff --git a/components/esp_driver_dma/include/esp_private/gdma.h b/components/esp_driver_dma/include/esp_private/gdma.h index 219004c083c..2c9c5500a52 100644 --- a/components/esp_driver_dma/include/esp_private/gdma.h +++ b/components/esp_driver_dma/include/esp_private/gdma.h @@ -201,8 +201,8 @@ esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan); */ typedef struct { uint32_t max_data_burst_size; /*!< Set the max burst size when DMA read/write the data buffer. - Set to 0 means to disable the data burst. - Other values must be powers of 2 or supported by the selected GDMA bus. */ + Set to 0 or 1 means to disable the data burst. + Other value must be power of 2 and supported by the DMA bus interface */ bool access_ext_mem; /*!< Set this if the DMA transfer will access external memory */ } gdma_transfer_config_t; diff --git a/components/esp_driver_dma/src/async_crc_gdma.c b/components/esp_driver_dma/src/async_crc_gdma.c index 5a3079842e1..50eceece3c3 100644 --- a/components/esp_driver_dma/src/async_crc_gdma.c +++ b/components/esp_driver_dma/src/async_crc_gdma.c @@ -22,6 +22,8 @@ ESP_LOG_ATTR_TAG(TAG, "async_crc_gdma"); #define CRC_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095 #define CRC_DMA_RX_SINK_BUFFER_SIZE 32 +/// Default DMA burst size (in bytes), used when the user leaves `dma_burst_size` as 0 +#define CRC_DMA_DEFAULT_BURST_SIZE 16 __attribute__((always_inline)) static inline uint32_t bit_reverse32(uint32_t val) @@ -155,8 +157,9 @@ esp_err_t esp_async_crc_install_gdma_template(const async_crc_config_t *config, gdma_apply_strategy(crc_gdma->rx_channel, &rx_strategy_cfg); // Configure DMA transfer + // Note: 0 means "unset" in the config struct, fall back to the driver default burst size. gdma_transfer_config_t transfer_cfg = { - .max_data_burst_size = config->dma_burst_size, + .max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : CRC_DMA_DEFAULT_BURST_SIZE, .access_ext_mem = true, // allow to copy data from external memory }; ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->tx_channel, &transfer_cfg), err, TAG, "config TX DMA transfer failed"); diff --git a/components/esp_driver_dma/src/async_memcpy_dw_gdma.c b/components/esp_driver_dma/src/async_memcpy_dw_gdma.c index d1071149fe6..befe4c96f7d 100644 --- a/components/esp_driver_dma/src/async_memcpy_dw_gdma.c +++ b/components/esp_driver_dma/src/async_memcpy_dw_gdma.c @@ -35,6 +35,9 @@ ESP_LOG_ATTR_TAG(TAG, "async_mcp.dw_gdma"); /// @brief Maximum body transfer width (in bits), capped by the AXI data width. #define MCP_DW_GDMA_MAX_BODY_WIDTH_BITS 64 +/// Default DMA burst size (in bytes), used when the user leaves `dma_burst_size` as 0 +#define MCP_DW_GDMA_DEFAULT_BURST_SIZE 16 + /// @brief Transaction object for async memcpy typedef struct async_memcpy_transaction_t { dw_gdma_link_list_handle_t link_list; // DW_GDMA link list for this transaction (body only) @@ -184,7 +187,8 @@ esp_err_t esp_async_memcpy_install_dw_gdma(const async_memcpy_config_t *config, portMUX_INITIALIZE(&mcp_dw_gdma->spin_lock); atomic_init(&mcp_dw_gdma->fsm, MCP_FSM_IDLE); mcp_dw_gdma->num_trans_objs = trans_queue_len; - mcp_dw_gdma->dma_burst_size = config->dma_burst_size; + // Note: 0 means "unset" in the config struct, fall back to the driver default burst size + mcp_dw_gdma->dma_burst_size = config->dma_burst_size ? config->dma_burst_size : MCP_DW_GDMA_DEFAULT_BURST_SIZE; mcp_dw_gdma->parent.del = mcp_dw_gdma_del; mcp_dw_gdma->parent.memcpy = mcp_dw_gdma_memcpy; diff --git a/components/esp_driver_dma/src/async_memcpy_gdma.c b/components/esp_driver_dma/src/async_memcpy_gdma.c index 117f86944a9..d50ecb27db3 100644 --- a/components/esp_driver_dma/src/async_memcpy_gdma.c +++ b/components/esp_driver_dma/src/async_memcpy_gdma.c @@ -30,6 +30,8 @@ ESP_LOG_ATTR_TAG(TAG, "async_mcp.gdma"); #define MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095 +/// Default DMA burst size (in bytes), used when the user leaves `dma_burst_size` as 0 +#define MCP_GDMA_DEFAULT_BURST_SIZE 16 /// @brief Transaction object for async memcpy typedef struct async_memcpy_transaction_t { @@ -138,8 +140,10 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi ESP_GOTO_ON_ERROR(gdma_set_weight(mcp_gdma->tx_channel, config->weight), err, TAG, "Set GDMA tx channel weight failed"); } #endif + // Note: 0 means "unset" in the config struct, fall back to the driver default burst size. + // To disable the data burst explicitly, set `dma_burst_size` to 1. gdma_transfer_config_t transfer_cfg = { - .max_data_burst_size = config->dma_burst_size, + .max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : MCP_GDMA_DEFAULT_BURST_SIZE, .access_ext_mem = true, // allow to do memory copy from/to external memory }; ESP_GOTO_ON_ERROR(gdma_config_transfer(mcp_gdma->tx_channel, &transfer_cfg), err, TAG, "config transfer for tx channel failed"); diff --git a/components/esp_driver_dma/src/gdma.c b/components/esp_driver_dma/src/gdma.c index d555bfa632b..03cb8ac9eee 100644 --- a/components/esp_driver_dma/src/gdma.c +++ b/components/esp_driver_dma/src/gdma.c @@ -431,7 +431,8 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf if (config->access_ext_mem) { #if (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH) && SOC_AHB_GDMA_VERSION != 1 - // Under Flash Encryption/PSRAM ECC, DMA must use MSPI-aligned bursts. + // Under Flash Encryption/PSRAM ECC, DMA must use MSPI-aligned bursts, so this hardware + // constraint takes precedence over a user requested burst disable. size_t mspi_alignment = esp_mspi_get_alignment(NULL); if (mspi_alignment > 1) { if (max_data_burst_size < mspi_alignment) { @@ -445,13 +446,11 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf TAG, "max_data_burst_size must not exceed %d when accessing external memory", GDMA_LL_MAX_BURST_SIZE_PSRAM); #endif } - if (max_data_burst_size) { + // treat 0 and 1 as "no burst": a single-beat burst has no benefit over the non-burst mode. + bool en_data_burst = max_data_burst_size > 1; + if (en_data_burst) { ESP_RETURN_ON_FALSE(gdma_hal_check_burst_size(hal, max_data_burst_size), ESP_ERR_INVALID_ARG, TAG, "invalid max_data_burst_size: %"PRIu32, max_data_burst_size); - } - - bool en_data_burst = max_data_burst_size > 0; - if (en_data_burst) { #if CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION // due to hardware limitation, if weighted arbitration is enabled, the data must be aligned to burst size int_mem_alignment = MAX(int_mem_alignment, max_data_burst_size); diff --git a/components/esp_driver_dma/test_apps/dma/main/test_async_memcpy.c b/components/esp_driver_dma/test_apps/dma/main/test_async_memcpy.c index f6f8970b0b7..5be54ea90dd 100644 --- a/components/esp_driver_dma/test_apps/dma/main/test_async_memcpy.c +++ b/components/esp_driver_dma/test_apps/dma/main/test_async_memcpy.c @@ -162,25 +162,20 @@ static void test_memory_copy_blocking(async_memcpy_handle_t driver) .align = 16, }; for (int i = 0; i < sizeof(test_buffer_size) / sizeof(test_buffer_size[0]); i++) { - // Test different align edge - for (int off = 0; off < 4; off++) { - test_context.buffer_size = test_buffer_size[i]; - test_context.seed = i; - if (!gdma_test_mspi_strict_alignment_required()) { - test_context.src_offset = off; - test_context.dst_offset = off; - } - async_memcpy_setup_testbench(&test_context); + test_context.buffer_size = test_buffer_size[i]; + test_context.seed = i; + async_memcpy_setup_testbench(&test_context); - TEST_ESP_OK(esp_memcpy_blocking(driver, test_context.to_addr, test_context.from_addr, test_context.copy_size, -1)); - async_memcpy_verify_and_clear_testbench(test_context.copy_size, test_context.src_buf, test_context.dst_buf, - test_context.from_addr, test_context.to_addr); - } + TEST_ESP_OK(esp_memcpy_blocking(driver, test_context.to_addr, test_context.from_addr, test_context.copy_size, -1)); + async_memcpy_verify_and_clear_testbench(test_context.copy_size, test_context.src_buf, test_context.dst_buf, + test_context.from_addr, test_context.to_addr); } } TEST_CASE("memory copy by DMA (blocking)", "[async mcp]") { + // Aligned copies with the driver default burst. + // Unaligned dest is covered by "memory copy with dest address unaligned" case. async_memcpy_config_t config = { .backlog = 1, .dma_burst_size = 0, @@ -247,63 +242,83 @@ TEST_CASE("memory copy by DMA (blocking)", "[async mcp]") } } -TEST_CASE("memory copy with dest address unaligned", "[async mcp]") +typedef esp_err_t (*test_mcp_install_fn)(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp); + +// SRAM can disable burst to cover the unaligned software path on chips whose RX +// burst requires dest alignment. PSRAM cannot: the external-memory block size +// (e.g. ESP32-S3 ext_mem_bk_size) is programmed together with the burst size and +// must match the cache line. Dest is cache-split so the DMA body stays aligned. +[[maybe_unused]] static void test_unaligned_dest_with_backend(const char *name, test_mcp_install_fn install, bool psram_capable) { - [[maybe_unused]] async_memcpy_config_t driver_config = { + async_memcpy_config_t config = { .backlog = 4, .dma_burst_size = 32, }; - [[maybe_unused]] async_memcpy_handle_t driver = NULL; + async_memcpy_handle_t driver = NULL; +#if SOC_GDMA_SUPPORTED && (GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT || CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION) + config.dma_burst_size = 1; +#endif + + printf("Testing memcpy by %s\r\n", name); + TEST_ESP_OK(install(&config, &driver)); + test_memcpy_with_dest_addr_unaligned(driver, false, false); + TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); + +#if SOC_HAS(SPIRAM) + if (psram_capable) { + config.dma_burst_size = 32; +#if CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION + // Weighted arbitration still needs every buffer aligned to the burst + // size, including the TX source body. Keep burst disabled there. + config.dma_burst_size = 1; +#endif + printf("Testing memcpy by %s (PSRAM)\r\n", name); + TEST_ESP_OK(install(&config, &driver)); + test_memcpy_with_dest_addr_unaligned(driver, true, true); + TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); + } +#else + (void)psram_capable; +#endif // SOC_HAS(SPIRAM) +} + +TEST_CASE("memory copy with dest address unaligned", "[async mcp]") +{ if (gdma_test_mspi_strict_alignment_required()) { TEST_PASS_MESSAGE("MSPI strict alignment required (Flash Encryption / PSRAM ECC), skip this test"); } #if SOC_CP_DMA_SUPPORTED - printf("Testing memcpy by CP DMA\r\n"); - TEST_ESP_OK(esp_async_memcpy_install_cpdma(&driver_config, &driver)); - test_memcpy_with_dest_addr_unaligned(driver, false, false); - TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); + test_unaligned_dest_with_backend("CP DMA", esp_async_memcpy_install_cpdma, false); #endif // SOC_CP_DMA_SUPPORTED -#if SOC_HAS(AHB_GDMA) && !GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT && !CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION - printf("Testing memcpy by AHB GDMA\r\n"); - TEST_ESP_OK(esp_async_memcpy_install_gdma_ahb(&driver_config, &driver)); - test_memcpy_with_dest_addr_unaligned(driver, false, false); -#if GDMA_LL_GET(AHB_PSRAM_CAPABLE) && SOC_HAS(SPIRAM) - test_memcpy_with_dest_addr_unaligned(driver, true, true); -#endif // GDMA_LL_GET(AHB_PSRAM_CAPABLE) && SOC_HAS(SPIRAM) - TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); +#if SOC_HAS(AHB_GDMA) +#if GDMA_LL_GET(AHB_PSRAM_CAPABLE) + test_unaligned_dest_with_backend("AHB GDMA", esp_async_memcpy_install_gdma_ahb, true); +#else + test_unaligned_dest_with_backend("AHB GDMA", esp_async_memcpy_install_gdma_ahb, false); +#endif #endif // SOC_HAS(AHB_GDMA) -#if SOC_HAS(AXI_GDMA) && !CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION - printf("Testing memcpy by AXI GDMA\r\n"); - TEST_ESP_OK(esp_async_memcpy_install_gdma_axi(&driver_config, &driver)); - test_memcpy_with_dest_addr_unaligned(driver, false, false); -#if GDMA_LL_GET(AXI_PSRAM_CAPABLE) && SOC_HAS(SPIRAM) - test_memcpy_with_dest_addr_unaligned(driver, true, true); -#endif // GDMA_LL_GET(AXI_PSRAM_CAPABLE) && SOC_HAS(SPIRAM) - TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); +#if SOC_HAS(AXI_GDMA) +#if GDMA_LL_GET(AXI_PSRAM_CAPABLE) + test_unaligned_dest_with_backend("AXI GDMA", esp_async_memcpy_install_gdma_axi, true); +#else + test_unaligned_dest_with_backend("AXI GDMA", esp_async_memcpy_install_gdma_axi, false); +#endif #endif // SOC_HAS(AXI_GDMA) -#if SOC_HAS(LP_AHB_GDMA) && !CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION - printf("Testing memcpy by LP AHB GDMA\r\n"); - TEST_ESP_OK(esp_async_memcpy_install_gdma_lp_ahb(&driver_config, &driver)); - test_memcpy_with_dest_addr_unaligned(driver, false, false); -#if GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE) && SOC_HAS(SPIRAM) - test_memcpy_with_dest_addr_unaligned(driver, true, true); -#endif // GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE) && SOC_HAS(SPIRAM) - TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); +#if SOC_HAS(LP_AHB_GDMA) +#if GDMA_LL_GET(LP_AHB_PSRAM_CAPABLE) + test_unaligned_dest_with_backend("LP AHB GDMA", esp_async_memcpy_install_gdma_lp_ahb, true); +#else + test_unaligned_dest_with_backend("LP AHB GDMA", esp_async_memcpy_install_gdma_lp_ahb, false); +#endif #endif // SOC_HAS(LP_AHB_GDMA) #if SOC_HAS(DW_GDMA) - printf("Testing memcpy by DW_GDMA\r\n"); - TEST_ESP_OK(esp_async_memcpy_install_dw_gdma(&driver_config, &driver)); - test_memcpy_with_dest_addr_unaligned(driver, false, false); -#if SOC_HAS(SPIRAM) - test_memcpy_with_dest_addr_unaligned(driver, true, true); -#endif // SOC_HAS(SPIRAM) - TEST_ESP_OK(esp_async_memcpy_uninstall(driver)); + test_unaligned_dest_with_backend("DW_GDMA", esp_async_memcpy_install_dw_gdma, true); #endif // SOC_HAS(DW_GDMA) } diff --git a/components/esp_driver_dma/test_apps/dma/main/test_gdma.c b/components/esp_driver_dma/test_apps/dma/main/test_gdma.c index b08989b9b4b..2f97c8b3b75 100644 --- a/components/esp_driver_dma/test_apps/dma/main/test_gdma.c +++ b/components/esp_driver_dma/test_apps/dma/main/test_gdma.c @@ -941,6 +941,13 @@ static void test_gdma_burst_size_validation(gdma_new_channel_func_t new_channel, }; TEST_ESP_OK(gdma_config_transfer(tx_chan, &transfer_config)); + // 0 and 1 both mean "disable data burst", and must be accepted even on chips + // whose hardware burst size is not programmable to 1 (e.g. S3: 16/32/64 only). + transfer_config.max_data_burst_size = 0; + TEST_ESP_OK(gdma_config_transfer(tx_chan, &transfer_config)); + transfer_config.max_data_burst_size = 1; + TEST_ESP_OK(gdma_config_transfer(tx_chan, &transfer_config)); + transfer_config.max_data_burst_size = 3; TEST_ESP_ERR(ESP_ERR_INVALID_ARG, gdma_config_transfer(tx_chan, &transfer_config)); diff --git a/components/esp_driver_dma/test_apps/dma/pytest_dma.py b/components/esp_driver_dma/test_apps/dma/pytest_dma.py index fa8b146d85d..bab086ca8e6 100644 --- a/components/esp_driver_dma/test_apps/dma/pytest_dma.py +++ b/components/esp_driver_dma/test_apps/dma/pytest_dma.py @@ -13,20 +13,22 @@ def get_flash_encryption_marks(target: str) -> tuple[pytest.MarkDecorator, ...]: return (pytest.mark.flash_encryption,) -@pytest.mark.generic +def get_psram_marks(target: str) -> tuple[pytest.MarkDecorator, ...]: + if target == 'esp32s3': + return (pytest.mark.octal_psram,) + + return (pytest.mark.generic,) + + @pytest.mark.parametrize( - 'config', + 'config, target', [ - 'release', + pytest.param('release', target, marks=get_psram_marks(target)) + for target in soc_filtered_targets('SOC_GDMA_SUPPORTED == 1 or SOC_CP_DMA_SUPPORTED == 1') ], indirect=True, ) -@idf_parametrize( - 'target', - ['esp32s2', 'esp32s31', 'esp32c2', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32c61', 'esp32h2', 'esp32h4', 'esp32p4'], - indirect=['target'], -) -def test_dma(dut: Dut) -> None: +def test_gdma(dut: Dut) -> None: dut.run_all_single_board_cases() @@ -40,20 +42,7 @@ def test_dma(dut: Dut) -> None: indirect=True, ) @idf_parametrize('target', ['esp32p4'], indirect=['target']) -def test_dma_esp32p4_rev1(dut: Dut) -> None: - dut.run_all_single_board_cases() - - -@pytest.mark.octal_psram -@pytest.mark.parametrize( - 'config', - [ - 'release', - ], - indirect=True, -) -@idf_parametrize('target', ['esp32s3'], indirect=['target']) -def test_dma_psram(dut: Dut) -> None: +def test_gdma_esp32p4_rev1(dut: Dut) -> None: dut.run_all_single_board_cases() @@ -66,7 +55,7 @@ def test_dma_psram(dut: Dut) -> None: indirect=True, ) @idf_parametrize('target', soc_filtered_targets('SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION == 1'), indirect=['target']) -def test_dma_weighted_arbitration(dut: Dut) -> None: +def test_gdma_weighted_arbitration(dut: Dut) -> None: dut.run_all_single_board_cases() @@ -80,5 +69,5 @@ def test_dma_weighted_arbitration(dut: Dut) -> None: ], indirect=True, ) -def test_dma_flash_encryption(dut: Dut) -> None: +def test_gdma_flash_encryption(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/esp_driver_i2s/include/driver/i2s_common.h b/components/esp_driver_i2s/include/driver/i2s_common.h index e7fae39e919..ec1012ae037 100644 --- a/components/esp_driver_i2s/include/driver/i2s_common.h +++ b/components/esp_driver_i2s/include/driver/i2s_common.h @@ -74,7 +74,7 @@ typedef struct { uint32_t dma_frame_num; /*!< I2S frame number in one DMA buffer. One frame means one-time sample data in all slots, * it should be the multiple of `3` when the data bit width is 24. */ - size_t dma_burst_size; /*!< DMA data burst size in bytes. Set to 0 to use driver default (32). + size_t dma_burst_size; /*!< DMA data burst size in bytes. Set to 0 to use the driver default. * When non-zero, must be a chip-supported power of 2 (see GDMA driver or chip TRM). * Ignored on chips that do not support configurable burst size. */ diff --git a/components/esp_driver_i3c/include/driver/i3c_master.h b/components/esp_driver_i3c/include/driver/i3c_master.h index f756f237e0a..7082cb63c52 100644 --- a/components/esp_driver_i3c/include/driver/i3c_master.h +++ b/components/esp_driver_i3c/include/driver/i3c_master.h @@ -50,7 +50,7 @@ typedef struct { */ typedef struct { size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes */ - size_t dma_burst_size; /*!< DMA burst size, in bytes. If 0, driver will use default value (16 bytes) */ + size_t dma_burst_size; /*!< DMA burst size, in bytes. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ } i3c_master_dma_config_t; /** diff --git a/components/esp_driver_isp/include/driver/isp_core.h b/components/esp_driver_isp/include/driver/isp_core.h index 6869fac72cb..a0fe44d892e 100644 --- a/components/esp_driver_isp/include/driver/isp_core.h +++ b/components/esp_driver_isp/include/driver/isp_core.h @@ -32,7 +32,7 @@ typedef struct { uint32_t h_res; ///< Input horizontal resolution, i.e. the number of pixels in a line uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame color_raw_element_order_t bayer_order; ///< Bayer order - uint32_t dma_burst_size; ///< DMA output burst length in units of 64-bit beats. Set to 0 to use default value 16 + uint32_t dma_burst_size; ///< DMA output burst length in units of 64-bit beats. Set to 0 to use the driver default int intr_priority; ///< The interrupt priority, range 0~3, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) struct { uint32_t bypass_isp : 1; ///< Bypass ISP pipelines diff --git a/components/esp_driver_parlio/include/driver/parlio_rx.h b/components/esp_driver_parlio/include/driver/parlio_rx.h index 2c40796ae79..58ce0988768 100644 --- a/components/esp_driver_parlio/include/driver/parlio_rx.h +++ b/components/esp_driver_parlio/include/driver/parlio_rx.h @@ -22,7 +22,7 @@ extern "C" { typedef struct { size_t trans_queue_depth; /*!< Depth of internal transaction queue */ size_t max_recv_size; /*!< Maximum receive size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */ - size_t dma_burst_size; /*!< DMA burst size, in bytes */ + size_t dma_burst_size; /*!< DMA burst size, in bytes, must be a power of 2. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ size_t data_width; /*!< Parallel IO data width, can set to 1/2/4/8/..., but can't be greater than PARLIO_RX_UNIT_MAX_DATA_WIDTH */ parlio_clock_source_t clk_src; /*!< Parallel IO clock source */ uint32_t ext_clk_freq_hz; /*!< The external source clock frequency. Only be valid when select PARLIO_CLK_SRC_EXTERNAL as clock source */ diff --git a/components/esp_driver_parlio/include/driver/parlio_tx.h b/components/esp_driver_parlio/include/driver/parlio_tx.h index 6113248186e..dce9d067b5f 100644 --- a/components/esp_driver_parlio/include/driver/parlio_tx.h +++ b/components/esp_driver_parlio/include/driver/parlio_tx.h @@ -34,7 +34,7 @@ typedef struct { uint16_t valid_stop_delay; /*!< The clock cycles that the valid signal keeps active after data end */ size_t trans_queue_depth; /*!< Depth of internal transaction queue */ size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */ - size_t dma_burst_size; /*!< DMA burst size, in bytes */ + size_t dma_burst_size; /*!< DMA burst size, in bytes, must be a power of 2. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ union { parlio_sample_edge_t sample_edge __attribute__((deprecated("Please use `shift_edge` instead"))); /*!< Parallel IO sample edge */ parlio_shift_edge_t shift_edge; /*!< Parallel IO Tx shift edge */ diff --git a/components/esp_driver_uart/include/driver/uhci.h b/components/esp_driver_uart/include/driver/uhci.h index eb4f4773737..102b6483d36 100644 --- a/components/esp_driver_uart/include/driver/uhci.h +++ b/components/esp_driver_uart/include/driver/uhci.h @@ -22,7 +22,7 @@ typedef struct { size_t max_transmit_size; /*!< Maximum transfer size in one transaction, in bytes. Note that this is the total size of all buffers combined */ size_t max_transmit_buffer_count; /*!< Maximum number of buffers that can be transmitted together in one transaction, via `uhci_multi_buffer_transmit()`. Set to 0 or 1 if only single-buffer transmit (`uhci_transmit()`) is needed. */ size_t max_receive_internal_mem; /*!< Expected maximum buffer size for uhci_receive(). This value determines the number of descriptors in the receive DMA chain. Each DMA descriptor can reference a buffer of up to X bytes (depending on the chip). For large transfers, at least two descriptors are recommended for ping-pong operation. */ - size_t dma_burst_size; /*!< DMA burst size, in bytes. Set to 0 to disable data burst. Otherwise, use a power of 2. */ + size_t dma_burst_size; /*!< DMA burst size, in bytes, must be a power of 2. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ size_t max_packet_receive; /*!< Max receive size, auto stop receiving after reach this value, only valid when `length_eof` set true */ struct { diff --git a/components/esp_driver_uart/src/uhci.c b/components/esp_driver_uart/src/uhci.c index 1c4e6c61f0a..9b9f921fe54 100644 --- a/components/esp_driver_uart/src/uhci.c +++ b/components/esp_driver_uart/src/uhci.c @@ -204,7 +204,7 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const gdma_transfer_config_t transfer_cfg = { .access_ext_mem = true, - .max_data_burst_size = config->dma_burst_size, + .max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : UHCI_DEFAULT_DMA_BURST_SIZE, }; ESP_RETURN_ON_ERROR(gdma_config_transfer(uhci_ctrl->tx_dir.dma_chan, &transfer_cfg), TAG, "Config DMA tx channel transfer failed"); diff --git a/components/esp_driver_uart/src/uhci_private.h b/components/esp_driver_uart/src/uhci_private.h index 4ef4bbce7a6..a9c3692c5bb 100644 --- a/components/esp_driver_uart/src/uhci_private.h +++ b/components/esp_driver_uart/src/uhci_private.h @@ -23,6 +23,7 @@ extern "C" { typedef struct uhci_controller_t uhci_controller_t; #define UHCI_PM_LOCK_NAME_LEN_MAX 16 +#define UHCI_DEFAULT_DMA_BURST_SIZE 16 // Default DMA burst size in bytes, used when user config leaves dma_burst_size as 0 #if CONFIG_UHCI_ISR_HANDLER_IN_IRAM #define UHCI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) diff --git a/components/esp_lcd/include/esp_lcd_io_i80.h b/components/esp_lcd/include/esp_lcd_io_i80.h index 1df265aca00..97a68b9b2eb 100644 --- a/components/esp_lcd/include/esp_lcd_io_i80.h +++ b/components/esp_lcd/include/esp_lcd_io_i80.h @@ -29,7 +29,7 @@ typedef struct { gpio_num_t data_gpio_nums[ESP_LCD_I80_BUS_WIDTH_MAX]; /*!< GPIOs used for data lines */ size_t bus_width; /*!< Number of data lines, 8 or 16 */ size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */ - size_t dma_burst_size; /*!< DMA burst size, in bytes */ + size_t dma_burst_size; /*!< DMA burst size, in bytes, must be a power of 2. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ /// Extra configuration flags for I80 bus struct extra_i80_bus_flags { uint32_t allow_pd: 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode. diff --git a/components/esp_lcd/include/esp_lcd_io_parl.h b/components/esp_lcd/include/esp_lcd_io_parl.h index ec0b8fd7cfd..b80c485c71b 100644 --- a/components/esp_lcd/include/esp_lcd_io_parl.h +++ b/components/esp_lcd/include/esp_lcd_io_parl.h @@ -30,7 +30,7 @@ typedef struct { uint32_t pclk_hz; /*!< Frequency of pixel clock */ parlio_clock_source_t clk_src; /*!< Clock source for the Parlio peripheral */ size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */ - size_t dma_burst_size; /*!< DMA burst size, in bytes */ + size_t dma_burst_size; /*!< DMA burst size, in bytes, must be a power of 2. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ size_t trans_queue_depth; /*!< Transaction queue size, larger queue, higher throughput */ int lcd_cmd_bits; /*!< Bit-width of LCD command */ int lcd_param_bits; /*!< Bit-width of LCD parameter */ diff --git a/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h b/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h index 3b517f804fa..805611f8416 100644 --- a/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h +++ b/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h @@ -150,7 +150,7 @@ typedef struct { void *user_fbs[ESP_RGB_LCD_PANEL_MAX_FB_NUM]; /*!< Array of user-provided frame buffers. If not NULL, the driver will use these buffers instead of allocating its own */ size_t bounce_buffer_size_px; /*!< If it's non-zero, the driver allocates two DRAM bounce buffers for DMA use. DMA fetching from DRAM bounce buffer is much faster than PSRAM frame buffer. */ - size_t dma_burst_size; /*!< DMA burst size, in bytes */ + size_t dma_burst_size; /*!< DMA burst size, in bytes, must be a power of 2. Set to 0 to use the driver default. Set to 1 to disable the data burst. */ gpio_num_t hsync_gpio_num; /*!< GPIO used for HSYNC signal */ gpio_num_t vsync_gpio_num; /*!< GPIO used for VSYNC signal */ gpio_num_t de_gpio_num; /*!< GPIO used for DE signal, set to -1 if it's not used */ diff --git a/docs/en/api-reference/peripherals/async_crc.rst b/docs/en/api-reference/peripherals/async_crc.rst index b22fc3a9db7..35c5ec24000 100644 --- a/docs/en/api-reference/peripherals/async_crc.rst +++ b/docs/en/api-reference/peripherals/async_crc.rst @@ -101,7 +101,7 @@ When creating a driver instance, you need to configure: - **backlog**: Maximum number of pending CRC requests that can be queued. Higher values use more memory but provide better throughput for bursty workloads. - **intr_priority**: DMA interrupt priority. Set to ``0`` to use the default low/medium priority, or set a non-zero value to request a specific interrupt priority. -- **dma_burst_size**: DMA transfer burst size in bytes. +- **dma_burst_size**: DMA transfer burst size in bytes. Set to ``0`` to use the driver default (16 bytes), or to ``1`` to disable the data burst. The driver handle ``crc_hdl`` is an opaque pointer that you use for all subsequent operations. @@ -327,6 +327,7 @@ The ``dma_burst_size`` affects DMA transfer efficiency: - Larger burst sizes can improve throughput - Typical values: 16, 32, 64 bytes +- Set to ``0`` to use the driver default (16 bytes), or to ``1`` to disable the data burst The optimal value depends on your chip's DMA controller capabilities. diff --git a/docs/en/api-reference/peripherals/async_memcpy.rst b/docs/en/api-reference/peripherals/async_memcpy.rst index 3ae299a406b..5893b20130e 100644 --- a/docs/en/api-reference/peripherals/async_memcpy.rst +++ b/docs/en/api-reference/peripherals/async_memcpy.rst @@ -92,7 +92,11 @@ Select a DMA backend explicitly when installing the driver. The AHB GDMA backend :SOC_LP_AHB_GDMA_SUPPORTED: - :cpp:func:`esp_async_memcpy_install_gdma_lp_ahb` :SOC_DW_GDMA_SUPPORTED: - :cpp:func:`esp_async_memcpy_install_dw_gdma` -For a single blocking copy, set :cpp:member:`async_memcpy_config_t::backlog` to 1. Increase it when multiple copies can be pending. :cpp:member:`async_memcpy_config_t::dma_burst_size` controls the burst size in bytes; start with 16 and tune it only after measuring your workload. Set :cpp:member:`async_memcpy_config_t::weight` to 0 unless weighted arbitration is supported and your application needs to adjust its average bus bandwidth. +For a single blocking copy, set :cpp:member:`async_memcpy_config_t::backlog` to 1. Increase it when multiple copies can be pending. + +:cpp:member:`async_memcpy_config_t::dma_burst_size` controls the burst size in bytes; start with 16 and tune it only after measuring your workload. Set it to ``0`` to use the driver default (16 bytes), or to ``1`` to disable the data burst. + +Set :cpp:member:`async_memcpy_config_t::weight` to 0 unless weighted arbitration is supported and your application needs to adjust its average bus bandwidth. Scenario 2: Continue Working While DMA Copies ============================================== diff --git a/docs/en/migration-guides/release-6.x/6.2/index.rst b/docs/en/migration-guides/release-6.x/6.2/index.rst index 5514f72afa2..139bb189196 100644 --- a/docs/en/migration-guides/release-6.x/6.2/index.rst +++ b/docs/en/migration-guides/release-6.x/6.2/index.rst @@ -7,5 +7,6 @@ Migration from 6.1 to 6.2 :maxdepth: 1 :SOC_BT_CLASSIC_SUPPORTED: bluetooth-classic + peripherals security system diff --git a/docs/en/migration-guides/release-6.x/6.2/peripherals.rst b/docs/en/migration-guides/release-6.x/6.2/peripherals.rst new file mode 100644 index 00000000000..9b9091e5889 --- /dev/null +++ b/docs/en/migration-guides/release-6.x/6.2/peripherals.rst @@ -0,0 +1,27 @@ +Peripherals +=========== + +:link_to_translation:`zh_CN:[中文]` + +DMA +--- + +Unified ``dma_burst_size`` Default +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:cpp:member:`uhci_controller_config_t::dma_burst_size`, :cpp:member:`async_memcpy_config_t::dma_burst_size`, and :cpp:member:`async_crc_config_t::dma_burst_size` now treat ``0`` as unset and fall back to that driver's own recommended default. This matches I2S, SPI, and LCD, and closes a hole where a zero-initialized config struct could only disable the burst — there was no way to ask for the driver default. + +``1`` is newly defined as "disable the data burst". A single-beat burst has no benefit over non-burst mode. + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - ``dma_burst_size`` + - Meaning + * - ``0`` + - Fall back to the driver's recommended default + * - ``1`` + - Disable data burst + * - ``N`` (``N > 1``, power of 2) + - User-specified burst size diff --git a/docs/zh_CN/api-reference/peripherals/async_crc.rst b/docs/zh_CN/api-reference/peripherals/async_crc.rst index 79f42f44c60..4bec19029cd 100644 --- a/docs/zh_CN/api-reference/peripherals/async_crc.rst +++ b/docs/zh_CN/api-reference/peripherals/async_crc.rst @@ -101,7 +101,7 @@ - **backlog**:可排队等待的最大 CRC 请求数。较高的值使用更多内存,但在突发工作负载下提供更好的吞吐量。 - **intr_priority**:DMA 中断优先级。设置为 ``0`` 时使用默认的低/中优先级;设置为非零值时请求指定的中断优先级。 -- **dma_burst_size**:DMA 传输突发大小(字节)。 +- **dma_burst_size**:DMA 传输突发大小(字节)。设为 ``0`` 表示使用驱动默认值(16 字节),设为 ``1`` 表示关闭数据突发传输。 驱动程序句柄 ``crc_hdl`` 是一个不透明指针,用于所有后续操作。 @@ -327,6 +327,7 @@ DMA 突发大小 - 较大的突发大小可以提高吞吐量 - 典型值:16、32、64 字节 +- 设为 ``0`` 表示使用驱动默认值(16 字节),设为 ``1`` 表示关闭数据突发传输 最佳值取决于芯片的 DMA 控制器功能。 diff --git a/docs/zh_CN/api-reference/peripherals/async_memcpy.rst b/docs/zh_CN/api-reference/peripherals/async_memcpy.rst index 32cf136f728..ff0289a8da7 100644 --- a/docs/zh_CN/api-reference/peripherals/async_memcpy.rst +++ b/docs/zh_CN/api-reference/peripherals/async_memcpy.rst @@ -92,7 +92,11 @@ DMA 必须能访问源和目标 buffer。目标 buffer 应分配在 DMA 可访 :SOC_LP_AHB_GDMA_SUPPORTED: - :cpp:func:`esp_async_memcpy_install_gdma_lp_ahb` :SOC_DW_GDMA_SUPPORTED: - :cpp:func:`esp_async_memcpy_install_dw_gdma` -对于一次阻塞复制,将 :cpp:member:`async_memcpy_config_t::backlog` 设为 1 即可;若可能同时等待多个复制请求,应增大该值。:cpp:member:`async_memcpy_config_t::dma_burst_size` 设置 DMA 突发大小,单位为字节;可从 16 开始,仅在性能测试后再调整。除非目标芯片支持加权仲裁且应用需要调节平均总线带宽,否则将 :cpp:member:`async_memcpy_config_t::weight` 设为 0。 +对于一次阻塞复制,将 :cpp:member:`async_memcpy_config_t::backlog` 设为 1 即可;若可能同时等待多个复制请求,应增大该值。 + +:cpp:member:`async_memcpy_config_t::dma_burst_size` 设置 DMA 突发大小,单位为字节;可从 16 开始,仅在性能测试后再调整。设为 ``0`` 表示使用驱动默认值(16 字节),设为 ``1`` 表示关闭数据突发传输。 + +除非目标芯片支持加权仲裁且应用需要调节平均总线带宽,否则将 :cpp:member:`async_memcpy_config_t::weight` 设为 0。 场景 2:在 DMA 复制期间继续工作 ================================= diff --git a/docs/zh_CN/migration-guides/release-6.x/6.2/index.rst b/docs/zh_CN/migration-guides/release-6.x/6.2/index.rst index 1214ec6aead..08254985753 100644 --- a/docs/zh_CN/migration-guides/release-6.x/6.2/index.rst +++ b/docs/zh_CN/migration-guides/release-6.x/6.2/index.rst @@ -7,5 +7,6 @@ :maxdepth: 1 :SOC_BT_CLASSIC_SUPPORTED: bluetooth-classic + peripherals security system diff --git a/docs/zh_CN/migration-guides/release-6.x/6.2/peripherals.rst b/docs/zh_CN/migration-guides/release-6.x/6.2/peripherals.rst new file mode 100644 index 00000000000..e62c3489349 --- /dev/null +++ b/docs/zh_CN/migration-guides/release-6.x/6.2/peripherals.rst @@ -0,0 +1,27 @@ +外设驱动 +======== + +:link_to_translation:`en:[English]` + +DMA +--- + +统一 ``dma_burst_size`` 的默认值语义 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:cpp:member:`uhci_controller_config_t::dma_burst_size`、:cpp:member:`async_memcpy_config_t::dma_burst_size` 和 :cpp:member:`async_crc_config_t::dma_burst_size` 现在把 ``0`` 视为未设置,并回落到该驱动自己推荐的默认值。这与 I2S、SPI、LCD 的约定一致,也补上了原先的漏洞:配置结构体零初始化时只能关掉 burst,无法表达“使用驱动默认值”。 + +``1`` 是新引入的含义,表示显式关闭数据突发传输。单 beat 突发相对于非突发没有收益。 + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - ``dma_burst_size`` + - 含义 + * - ``0`` + - 回落到该驱动推荐的默认值 + * - ``1`` + - 关闭数据突发传输 + * - ``N`` (``N > 1``,且为 2 的幂) + - 用户指定的突发大小