Merge branch 'feat/test_gdma_psram' into 'master'

test(gdma): can do memory to/from psram correctly

See merge request espressif/esp-idf!36758
This commit is contained in:
morris
2025-02-06 17:14:29 +08:00

View File

@@ -521,3 +521,193 @@ TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]")
free(sbuf);
free(dbuf);
}
[[maybe_unused]] static void test_gdma_memcpy_from_to_psram(gdma_channel_handle_t tx_chan, gdma_channel_handle_t rx_chan)
{
#define COPY_SIZE (40*1024)
SemaphoreHandle_t done_sem = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(done_sem);
gdma_rx_event_callbacks_t rx_cbs = {
.on_recv_eof = test_gdma_m2m_rx_eof_callback,
};
TEST_ESP_OK(gdma_register_rx_event_callbacks(rx_chan, &rx_cbs, done_sem));
gdma_strategy_config_t strategy = {
.auto_update_desc = true,
.owner_check = true,
.eof_till_data_popped = true,
};
TEST_ESP_OK(gdma_apply_strategy(tx_chan, &strategy));
TEST_ESP_OK(gdma_apply_strategy(rx_chan, &strategy));
gdma_transfer_config_t transfer_cfg = {
.max_data_burst_size = 32,
.access_ext_mem = true, // allow to do memory copy from/to external memory
};
TEST_ESP_OK(gdma_config_transfer(tx_chan, &transfer_cfg));
TEST_ESP_OK(gdma_config_transfer(rx_chan, &transfer_cfg));
gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0);
// get a free DMA trigger ID for memory copy
uint32_t free_m2m_id_mask = 0;
gdma_get_free_m2m_trig_id_mask(tx_chan, &free_m2m_id_mask);
m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask);
TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger));
TEST_ESP_OK(gdma_connect(rx_chan, m2m_trigger));
gdma_link_list_handle_t tx_link_list = NULL;
gdma_link_list_handle_t rx_link_list = NULL;
// create DMA link list for TX channel (a singly link with 3 nodes)
gdma_link_list_config_t tx_link_list_config = {
.buffer_alignment = 32,
.item_alignment = 8, // 8-byte alignment required by the AXI-GDMA
.num_items = 20,
.flags = {
.items_in_ext_mem = false,
}
};
TEST_ESP_OK(gdma_new_link_list(&tx_link_list_config, &tx_link_list));
// create DMA link list for RX channel
gdma_link_list_config_t rx_link_list_config = {
.buffer_alignment = 32,
.item_alignment = 8, // 8-byte alignment required by the AXI-GDMA
.num_items = 20,
.flags = {
.items_in_ext_mem = false,
},
};
TEST_ESP_OK(gdma_new_link_list(&rx_link_list_config, &rx_link_list));
// allocate the source buffer from SRAM
uint8_t *src_data = heap_caps_aligned_calloc(32, 1, COPY_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(src_data);
TEST_ASSERT_TRUE(esp_ptr_internal(src_data));
// prepare the source data
for (int i = 0; i < COPY_SIZE; i++) {
src_data[i] = i;
}
size_t sram_cache_line_sz = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
size_t psram_cache_line_sz = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
// do cache sync if necessary
if (sram_cache_line_sz) {
TEST_ESP_OK(esp_cache_msync(src_data, COPY_SIZE, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE));
}
// allocate the destination buffer from PSRAM
uint8_t *dst_data = heap_caps_aligned_calloc(32, 1, COPY_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(dst_data);
TEST_ASSERT_TRUE(esp_ptr_external_ram(dst_data));
if (psram_cache_line_sz) {
TEST_ESP_OK(esp_cache_msync(dst_data, COPY_SIZE, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE));
}
gdma_buffer_mount_config_t tx_buf_mount_config = {
.buffer = src_data,
.length = COPY_SIZE,
.flags = {
.mark_eof = true,
.mark_final = true, // using singly list, so terminate the link here
}
};
TEST_ESP_OK(gdma_link_mount_buffers(tx_link_list, 0, &tx_buf_mount_config, 1, NULL));
gdma_buffer_mount_config_t rx_buf_mount_config = {
.buffer = dst_data,
.length = COPY_SIZE,
.flags = {
.mark_final = true, // using singly list, so terminate the link here
}
};
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
TEST_ESP_OK(gdma_start(rx_chan, gdma_link_get_head_addr(rx_link_list)));
TEST_ESP_OK(gdma_start(tx_chan, gdma_link_get_head_addr(tx_link_list)));
xSemaphoreTake(done_sem, pdMS_TO_TICKS(1000));
/// let the DMA to copy the data back to the source buffer again
/// clear the "src_data" because now we want to use it as the destination buffer
memset(src_data, 0, COPY_SIZE);
// do cache sync if necessary
if (sram_cache_line_sz) {
TEST_ESP_OK(esp_cache_msync(src_data, COPY_SIZE, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE));
}
tx_buf_mount_config.buffer = dst_data;
TEST_ESP_OK(gdma_link_mount_buffers(tx_link_list, 0, &tx_buf_mount_config, 1, NULL));
rx_buf_mount_config.buffer = src_data;
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
TEST_ESP_OK(gdma_start(rx_chan, gdma_link_get_head_addr(rx_link_list)));
TEST_ESP_OK(gdma_start(tx_chan, gdma_link_get_head_addr(tx_link_list)));
xSemaphoreTake(done_sem, pdMS_TO_TICKS(1000));
bool compare_result = true;
for (int i = 0; i < COPY_SIZE; i++) {
if (src_data[i] != i % 256) {
printf("miss match! src_data[%d]=%d, should be %d\n", i, src_data[i], i % 256);
compare_result = false;
}
if (dst_data[i] != i % 256) {
printf("miss match! dst_data[%d]=%d, should be %d\n", i, dst_data[i], i % 256);
compare_result = false;
}
}
TEST_ASSERT_TRUE(compare_result);
free(src_data);
free(dst_data);
TEST_ESP_OK(gdma_del_link_list(tx_link_list));
TEST_ESP_OK(gdma_del_link_list(rx_link_list));
vSemaphoreDelete(done_sem);
#undef COPY_SIZE
}
#if SOC_SPIRAM_SUPPORTED
TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]")
{
[[maybe_unused]] gdma_channel_handle_t tx_chan = NULL;
[[maybe_unused]] gdma_channel_handle_t rx_chan = NULL;
[[maybe_unused]] gdma_channel_alloc_config_t tx_chan_alloc_config = {};
[[maybe_unused]] gdma_channel_alloc_config_t rx_chan_alloc_config = {};
#if SOC_AHB_GDMA_SUPPORTED && SOC_AHB_GDMA_SUPPORT_PSRAM
printf("Testing AHB-GDMA memory copy SRAM->PSRAM->SRAM\n");
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
.direction = GDMA_CHANNEL_DIRECTION_TX,
.flags.reserve_sibling = true,
};
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan));
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
.direction = GDMA_CHANNEL_DIRECTION_RX,
.sibling_chan = tx_chan,
};
TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan));
test_gdma_memcpy_from_to_psram(tx_chan, rx_chan);
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif
#if SOC_AXI_GDMA_SUPPORTED && SOC_AXI_GDMA_SUPPORT_PSRAM
printf("Testing AXI-GDMA memory copy SRAM->PSRAM->SRAM\n");
tx_chan_alloc_config = (gdma_channel_alloc_config_t) {
.direction = GDMA_CHANNEL_DIRECTION_TX,
.flags.reserve_sibling = true,
};
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan));
rx_chan_alloc_config = (gdma_channel_alloc_config_t) {
.direction = GDMA_CHANNEL_DIRECTION_RX,
.sibling_chan = tx_chan,
};
TEST_ESP_OK(gdma_new_axi_channel(&rx_chan_alloc_config, &rx_chan));
test_gdma_memcpy_from_to_psram(tx_chan, rx_chan);
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif
}
#endif // SOC_SPIRAM_SUPPORTED