diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c index b704aa9e66..fd0e75a5fd 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c @@ -11,6 +11,7 @@ #include "freertos/semphr.h" #include "unity.h" #include "esp_heap_caps.h" +#include "esp_memory_utils.h" #include "esp_private/gdma.h" #include "hal/dma_types.h" #include "soc/soc_caps.h" @@ -62,6 +63,8 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu uint32_t crc_result = 0; const char *test_input_string = "Share::Connect::Innovate"; size_t input_data_size = strlen(test_input_string); + // this test case also test the GDMA can fetch data from MSPI Flash + TEST_ASSERT_TRUE(esp_ptr_in_drom(test_input_string)); printf("Calculate CRC value for string: \"%s\"\r\n", test_input_string); gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0); @@ -71,27 +74,22 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask); TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger)); - // allocate the source and destination buffer from SRAM - // |--------------------------------------------------| - // | 128 bytes DMA descriptor | 128 bytes data buffer | - // |--------------------------------------------------| - size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - uint8_t *src_buf = heap_caps_aligned_calloc(sram_alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - TEST_ASSERT_NOT_NULL(src_buf); - dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; - uint8_t *src_data = src_buf + 64; - memcpy(src_data, test_input_string, input_data_size); + size_t sram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + size_t alignment = MAX(sram_cache_line_size, 8); + dma_descriptor_align8_t *tx_descs = heap_caps_aligned_calloc(alignment, 1, sizeof(dma_descriptor_align8_t), + MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(tx_descs); - tx_descs->buffer = src_data; - tx_descs->dw0.size = 256 - 64; + tx_descs->buffer = (void *)test_input_string; + tx_descs->dw0.size = input_data_size + 1; // +1 for '\0' tx_descs->dw0.length = input_data_size; tx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; tx_descs->dw0.suc_eof = 1; tx_descs->next = NULL; - if (sram_alignment) { + if (sram_cache_line_size) { // do write-back for the buffer because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + TEST_ESP_OK(esp_cache_msync((void *)tx_descs, sizeof(dma_descriptor_align8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED)); } for (int i = 0; i < test_num_crc_algorithm; i++) { @@ -111,7 +109,7 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu TEST_ASSERT_EQUAL(crc_test_cases[i].expected_result, crc_result); } - free(src_buf); + free(tx_descs); } TEST_CASE("GDMA CRC Calculation", "[GDMA][CRC]") diff --git a/components/hal/esp32p4/include/hal/ahb_dma_ll.h b/components/hal/esp32p4/include/hal/ahb_dma_ll.h index b7a4667ed1..acf76923e0 100644 --- a/components/hal/esp32p4/include/hal/ahb_dma_ll.h +++ b/components/hal/esp32p4/include/hal/ahb_dma_ll.h @@ -57,6 +57,18 @@ static inline void ahb_dma_ll_reset_fsm(ahb_dma_dev_t *dev) dev->misc_conf.ahbm_rst_inter = 0; } +/** + * @brief Preset valid memory range for AHB-DMA + * + * @param dev DMA register base address + */ +static inline void ahb_dma_ll_set_default_memory_range(ahb_dma_dev_t *dev) +{ + // AHB-DMA can access L2MEM, L2ROM, MSPI Flash, MSPI PSRAM + dev->intr_mem_start_addr.val = 0x40000000; + dev->intr_mem_end_addr.val = 0x4FFC0000; +} + ///////////////////////////////////// RX ///////////////////////////////////////// /** * @brief Get DMA RX channel interrupt status word diff --git a/components/hal/esp32p4/include/hal/axi_dma_ll.h b/components/hal/esp32p4/include/hal/axi_dma_ll.h index 171b204527..5cd6808872 100644 --- a/components/hal/esp32p4/include/hal/axi_dma_ll.h +++ b/components/hal/esp32p4/include/hal/axi_dma_ll.h @@ -59,6 +59,20 @@ static inline void axi_dma_ll_reset_fsm(axi_dma_dev_t *dev) dev->misc_conf.axim_rst_wr_inter = 0; } +/** + * @brief Preset valid memory range for AXI-DMA + * + * @param dev DMA register base address + */ +static inline void axi_dma_ll_set_default_memory_range(axi_dma_dev_t *dev) +{ + // AXI-DMA can access L2MEM, L2ROM, MSPI Flash, MSPI PSRAM + dev->intr_mem_start_addr.val = 0x4FC00000; + dev->intr_mem_end_addr.val = 0x4FFC0000; + dev->extr_mem_start_addr.val = 0x40000000; + dev->extr_mem_end_addr.val = 0x4C000000; +} + ///////////////////////////////////// RX ///////////////////////////////////////// /** * @brief Get DMA RX channel interrupt status word diff --git a/components/hal/gdma_hal_ahb_v2.c b/components/hal/gdma_hal_ahb_v2.c index 2b4f7a9e90..71385465fe 100644 --- a/components/hal/gdma_hal_ahb_v2.c +++ b/components/hal/gdma_hal_ahb_v2.c @@ -244,4 +244,5 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) #if SOC_GDMA_SUPPORT_ETM hal->enable_etm_task = gdma_ahb_hal_enable_etm_task; #endif // SOC_GDMA_SUPPORT_ETM + ahb_dma_ll_set_default_memory_range(hal->ahb_dma_dev); } diff --git a/components/hal/gdma_hal_axi.c b/components/hal/gdma_hal_axi.c index 67e3aeae40..da31498cad 100644 --- a/components/hal/gdma_hal_axi.c +++ b/components/hal/gdma_hal_axi.c @@ -244,4 +244,5 @@ void gdma_axi_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) #if SOC_GDMA_SUPPORT_ETM hal->enable_etm_task = gdma_axi_hal_enable_etm_task; #endif // SOC_GDMA_SUPPORT_ETM + axi_dma_ll_set_default_memory_range(hal->axi_dma_dev); } diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6597ac120f..3fb643d379 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -451,6 +451,10 @@ config SOC_DS_KEY_CHECK_MAX_WAIT_US int default 1100 +config SOC_DMA_CAN_ACCESS_MSPI_MEM + bool + default y + config SOC_AHB_GDMA_VERSION int default 2 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2b8089c0f7..c2706a0ba1 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -182,6 +182,9 @@ See TRM DS chapter for more details */ #define SOC_DS_KEY_CHECK_MAX_WAIT_US (1100) +/*-------------------------- DMA Common CAPS ----------------------------------------*/ +#define SOC_DMA_CAN_ACCESS_MSPI_MEM 1 /*!< DMA can access MSPI memory (e.g. Flash, PSRAM) */ + /*-------------------------- GDMA CAPS -------------------------------------*/ #define SOC_AHB_GDMA_VERSION 2 #define SOC_GDMA_SUPPORT_CRC 1 diff --git a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index dcd5198928..b20dc9bb82 100644 --- a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -77,6 +77,13 @@ Non-IRAM-Safe Interrupt Handlers If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt handler will not get executed when the caches are disabled. Once the caches are restored, the non-IRAM-safe interrupts will be re-enabled. After this moment, the interrupt handler will run normally again. This means that as long as caches are disabled, users will not see the corresponding hardware event happening. +.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM + + When DMA Read Data from Flash + ----------------------------- + + When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM. + .. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index a222654aa8..7e45a61373 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -77,6 +77,13 @@ IRAM 安全中断处理程序 如果在注册时没有设置 ``ESP_INTR_FLAG_IRAM`` 标志,当禁用 cache 时,将不会执行中断处理程序。一旦 cache 恢复,非 IRAM 安全的中断将重新启用,中断处理程序随即再次正常运行。这意味着,只要禁用了 cache,就不会发生相应的硬件事件。 +.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM + + 当 DMA 也可以访问 Flash 中的数据时 + ---------------------------------- + + 当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。 + .. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND