diff --git a/components/esp_driver_parlio/Kconfig b/components/esp_driver_parlio/Kconfig index e8f94f7189..2823b857d8 100644 --- a/components/esp_driver_parlio/Kconfig +++ b/components/esp_driver_parlio/Kconfig @@ -11,7 +11,7 @@ menu "ESP-Driver:Parallel IO Configurations" config PARLIO_ISR_IRAM_SAFE bool "Parallel IO ISR IRAM-Safe" default n - select GDMA_CTRL_FUNC_IN_IRAM # the driver needs to start the GDMA in the interrupt + select GDMA_ISR_IRAM_SAFE help Ensure the Parallel IO interrupt is IRAM-Safe by allowing the interrupt handler to be executable when the cache is disabled (e.g. SPI Flash write). diff --git a/components/esp_driver_parlio/linker.lf b/components/esp_driver_parlio/linker.lf index ecc7aa0372..957040646a 100644 --- a/components/esp_driver_parlio/linker.lf +++ b/components/esp_driver_parlio/linker.lf @@ -4,3 +4,4 @@ entries: if PARLIO_ISR_IRAM_SAFE: gdma_link: gdma_link_mount_buffers (noflash) gdma_link: gdma_link_get_head_addr (noflash) + gdma: gdma_start (noflash) diff --git a/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt b/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt index 6d465c10d4..d208c16bf9 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt +++ b/components/esp_driver_parlio/test_apps/parlio/main/CMakeLists.txt @@ -15,5 +15,5 @@ endif() # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} PRIV_REQUIRES unity esp_driver_parlio esp_driver_gpio - esp_driver_i2s esp_driver_spi + esp_driver_i2s esp_driver_spi esp_psram WHOLE_ARCHIVE) diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c index a556c8a407..18046cb0d2 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c @@ -288,3 +288,53 @@ TEST_CASE("parallel_tx_clock_gating", "[paralio_tx]") TEST_ESP_OK(gpio_reset_pin(TEST_CLK_GPIO)); } #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING + +#if SOC_PSRAM_DMA_CAPABLE +TEST_CASE("parlio can transmit PSRAM buffer", "[parlio_tx]") +{ + printf("install parlio tx unit\r\n"); + parlio_tx_unit_handle_t tx_unit = NULL; + parlio_tx_unit_config_t config = { + .clk_src = PARLIO_CLK_SRC_DEFAULT, + .data_width = 1, + .clk_in_gpio_num = -1, // use internal clock source + .valid_gpio_num = TEST_VALID_GPIO, // generate the valid signal + .clk_out_gpio_num = TEST_CLK_GPIO, + .data_gpio_nums = { + TEST_DATA0_GPIO, + }, + .output_clk_freq_hz = 20 * 1000 * 1000, + .trans_queue_depth = 4, + .max_transfer_size = 65535, + .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB, + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .flags.clk_gate_en = true, + }; + + TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit)); + TEST_ESP_OK(parlio_tx_unit_enable(tx_unit)); + + const size_t buffer_size = 160 * 1000; + const size_t chunk_size = buffer_size / 4; // 40KB per trunk + uint8_t *buffer = heap_caps_malloc(buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(buffer); + for (int i = 0; i < buffer_size; i++) { + buffer[i] = i; + } + + parlio_transmit_config_t transmit_config = { + .idle_value = 0x00, + }; + + const uint8_t cmd = 0x2C; + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, &cmd, 8, &transmit_config)); + for (int i = 0; i < 20; i++) { + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, buffer + (i % 4) * chunk_size, chunk_size * 8, &transmit_config)); + } + TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1)); + + TEST_ESP_OK(parlio_tx_unit_disable(tx_unit)); + TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); + free(buffer); +} +#endif // SOC_PSRAM_DMA_CAPABLE diff --git a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32c5 b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32c5 new file mode 100644 index 0000000000..728fbe8889 --- /dev/null +++ b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32c5 @@ -0,0 +1,2 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_SPEED_80M=y diff --git a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32p4 b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32p4 new file mode 100644 index 0000000000..3354f703a0 --- /dev/null +++ b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32p4 @@ -0,0 +1,4 @@ +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_hw_support/dma/Kconfig.dma b/components/esp_hw_support/dma/Kconfig.dma index 5620926e3e..affcb671b2 100644 --- a/components/esp_hw_support/dma/Kconfig.dma +++ b/components/esp_hw_support/dma/Kconfig.dma @@ -3,6 +3,7 @@ menu "GDMA Configurations" config GDMA_CTRL_FUNC_IN_IRAM bool "Place GDMA control functions in IRAM" default n + select GDMA_OBJ_DRAM_SAFE help Place GDMA control functions (like start/stop/append/reset) into IRAM, so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. @@ -10,11 +11,19 @@ menu "GDMA Configurations" config GDMA_ISR_IRAM_SAFE bool "GDMA ISR IRAM-Safe" default n + select GDMA_OBJ_DRAM_SAFE help This will ensure the GDMA interrupt handler is IRAM-Safe, allow to avoid flash cache misses, and also be able to run whilst the cache is disabled. (e.g. SPI Flash write). + config GDMA_OBJ_DRAM_SAFE + bool + default n + help + This will ensure the GDMA object is DRAM-Safe, allow to avoid external memory + cache misses, and also be accessible whilst the cache is disabled. + config GDMA_ENABLE_DEBUG_LOG bool "Enable debug log" default n diff --git a/components/esp_hw_support/dma/gdma_priv.h b/components/esp_hw_support/dma/gdma_priv.h index 600397be02..e6fc87a49e 100644 --- a/components/esp_hw_support/dma/gdma_priv.h +++ b/components/esp_hw_support/dma/gdma_priv.h @@ -20,7 +20,7 @@ #include "soc/gdma_periph.h" #include "esp_private/gdma.h" -#if CONFIG_GDMA_ISR_IRAM_SAFE || CONFIG_GDMA_CTRL_FUNC_IN_IRAM +#if CONFIG_GDMA_OBJ_DRAM_SAFE #define GDMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else #define GDMA_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index b5f1a63bff..173413f156 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1059,6 +1059,10 @@ config SOC_SPIRAM_XIP_SUPPORTED bool default y +config SOC_PSRAM_DMA_CAPABLE + bool + default y + config SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index bef7ab59eb..7857678c42 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -439,6 +439,7 @@ /*-------------------------- SPIRAM CAPS ----------------------------------------*/ #define SOC_SPIRAM_XIP_SUPPORTED 1 +#define SOC_PSRAM_DMA_CAPABLE 1 /*-------------------------- SPI MEM CAPS ---------------------------------------*/ #define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1)