@@ -521,3 +521,193 @@ TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]")
521521 free (sbuf );
522522 free (dbuf );
523523}
524+
525+ [[maybe_unused ]] static void test_gdma_memcpy_from_to_psram (gdma_channel_handle_t tx_chan , gdma_channel_handle_t rx_chan )
526+ {
527+ #define COPY_SIZE (40*1024)
528+ SemaphoreHandle_t done_sem = xSemaphoreCreateBinary ();
529+ TEST_ASSERT_NOT_NULL (done_sem );
530+ gdma_rx_event_callbacks_t rx_cbs = {
531+ .on_recv_eof = test_gdma_m2m_rx_eof_callback ,
532+ };
533+ TEST_ESP_OK (gdma_register_rx_event_callbacks (rx_chan , & rx_cbs , done_sem ));
534+
535+ gdma_strategy_config_t strategy = {
536+ .auto_update_desc = true,
537+ .owner_check = true,
538+ .eof_till_data_popped = true,
539+ };
540+ TEST_ESP_OK (gdma_apply_strategy (tx_chan , & strategy ));
541+ TEST_ESP_OK (gdma_apply_strategy (rx_chan , & strategy ));
542+
543+ gdma_transfer_config_t transfer_cfg = {
544+ .max_data_burst_size = 32 ,
545+ .access_ext_mem = true, // allow to do memory copy from/to external memory
546+ };
547+ TEST_ESP_OK (gdma_config_transfer (tx_chan , & transfer_cfg ));
548+ TEST_ESP_OK (gdma_config_transfer (rx_chan , & transfer_cfg ));
549+
550+ gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER (GDMA_TRIG_PERIPH_M2M , 0 );
551+ // get a free DMA trigger ID for memory copy
552+ uint32_t free_m2m_id_mask = 0 ;
553+ gdma_get_free_m2m_trig_id_mask (tx_chan , & free_m2m_id_mask );
554+ m2m_trigger .instance_id = __builtin_ctz (free_m2m_id_mask );
555+ TEST_ESP_OK (gdma_connect (tx_chan , m2m_trigger ));
556+ TEST_ESP_OK (gdma_connect (rx_chan , m2m_trigger ));
557+
558+ gdma_link_list_handle_t tx_link_list = NULL ;
559+ gdma_link_list_handle_t rx_link_list = NULL ;
560+ // create DMA link list for TX channel (a singly link with 3 nodes)
561+ gdma_link_list_config_t tx_link_list_config = {
562+ .buffer_alignment = 32 ,
563+ .item_alignment = 8 , // 8-byte alignment required by the AXI-GDMA
564+ .num_items = 20 ,
565+ .flags = {
566+ .items_in_ext_mem = false,
567+ }
568+ };
569+ TEST_ESP_OK (gdma_new_link_list (& tx_link_list_config , & tx_link_list ));
570+ // create DMA link list for RX channel
571+ gdma_link_list_config_t rx_link_list_config = {
572+ .buffer_alignment = 32 ,
573+ .item_alignment = 8 , // 8-byte alignment required by the AXI-GDMA
574+ .num_items = 20 ,
575+ .flags = {
576+ .items_in_ext_mem = false,
577+ },
578+ };
579+ TEST_ESP_OK (gdma_new_link_list (& rx_link_list_config , & rx_link_list ));
580+
581+ // allocate the source buffer from SRAM
582+ uint8_t * src_data = heap_caps_aligned_calloc (32 , 1 , COPY_SIZE , MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT );
583+ TEST_ASSERT_NOT_NULL (src_data );
584+ TEST_ASSERT_TRUE (esp_ptr_internal (src_data ));
585+ // prepare the source data
586+ for (int i = 0 ; i < COPY_SIZE ; i ++ ) {
587+ src_data [i ] = i ;
588+ }
589+ size_t sram_cache_line_sz = cache_hal_get_cache_line_size (CACHE_LL_LEVEL_INT_MEM , CACHE_TYPE_DATA );
590+ size_t psram_cache_line_sz = cache_hal_get_cache_line_size (CACHE_LL_LEVEL_EXT_MEM , CACHE_TYPE_DATA );
591+ // do cache sync if necessary
592+ if (sram_cache_line_sz ) {
593+ TEST_ESP_OK (esp_cache_msync (src_data , COPY_SIZE , ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE ));
594+ }
595+
596+ // allocate the destination buffer from PSRAM
597+ uint8_t * dst_data = heap_caps_aligned_calloc (32 , 1 , COPY_SIZE , MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT );
598+ TEST_ASSERT_NOT_NULL (dst_data );
599+ TEST_ASSERT_TRUE (esp_ptr_external_ram (dst_data ));
600+ if (psram_cache_line_sz ) {
601+ TEST_ESP_OK (esp_cache_msync (dst_data , COPY_SIZE , ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE ));
602+ }
603+
604+ gdma_buffer_mount_config_t tx_buf_mount_config = {
605+ .buffer = src_data ,
606+ .length = COPY_SIZE ,
607+ .flags = {
608+ .mark_eof = true,
609+ .mark_final = true, // using singly list, so terminate the link here
610+ }
611+ };
612+ TEST_ESP_OK (gdma_link_mount_buffers (tx_link_list , 0 , & tx_buf_mount_config , 1 , NULL ));
613+
614+ gdma_buffer_mount_config_t rx_buf_mount_config = {
615+ .buffer = dst_data ,
616+ .length = COPY_SIZE ,
617+ .flags = {
618+ .mark_final = true, // using singly list, so terminate the link here
619+ }
620+ };
621+ TEST_ESP_OK (gdma_link_mount_buffers (rx_link_list , 0 , & rx_buf_mount_config , 1 , NULL ));
622+
623+ TEST_ESP_OK (gdma_start (rx_chan , gdma_link_get_head_addr (rx_link_list )));
624+ TEST_ESP_OK (gdma_start (tx_chan , gdma_link_get_head_addr (tx_link_list )));
625+
626+ xSemaphoreTake (done_sem , pdMS_TO_TICKS (1000 ));
627+
628+ /// let the DMA to copy the data back to the source buffer again
629+ /// clear the "src_data" because now we want to use it as the destination buffer
630+ memset (src_data , 0 , COPY_SIZE );
631+ // do cache sync if necessary
632+ if (sram_cache_line_sz ) {
633+ TEST_ESP_OK (esp_cache_msync (src_data , COPY_SIZE , ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE ));
634+ }
635+
636+ tx_buf_mount_config .buffer = dst_data ;
637+ TEST_ESP_OK (gdma_link_mount_buffers (tx_link_list , 0 , & tx_buf_mount_config , 1 , NULL ));
638+ rx_buf_mount_config .buffer = src_data ;
639+ TEST_ESP_OK (gdma_link_mount_buffers (rx_link_list , 0 , & rx_buf_mount_config , 1 , NULL ));
640+
641+ TEST_ESP_OK (gdma_start (rx_chan , gdma_link_get_head_addr (rx_link_list )));
642+ TEST_ESP_OK (gdma_start (tx_chan , gdma_link_get_head_addr (tx_link_list )));
643+
644+ xSemaphoreTake (done_sem , pdMS_TO_TICKS (1000 ));
645+
646+ bool compare_result = true;
647+ for (int i = 0 ; i < COPY_SIZE ; i ++ ) {
648+ if (src_data [i ] != i % 256 ) {
649+ printf ("miss match! src_data[%d]=%d, should be %d\n" , i , src_data [i ], i % 256 );
650+ compare_result = false;
651+ }
652+ if (dst_data [i ] != i % 256 ) {
653+ printf ("miss match! dst_data[%d]=%d, should be %d\n" , i , dst_data [i ], i % 256 );
654+ compare_result = false;
655+ }
656+ }
657+ TEST_ASSERT_TRUE (compare_result );
658+
659+ free (src_data );
660+ free (dst_data );
661+ TEST_ESP_OK (gdma_del_link_list (tx_link_list ));
662+ TEST_ESP_OK (gdma_del_link_list (rx_link_list ));
663+ vSemaphoreDelete (done_sem );
664+ #undef COPY_SIZE
665+ }
666+
667+ #if SOC_SPIRAM_SUPPORTED
668+ TEST_CASE ("GDMA memory copy SRAM->PSRAM->SRAM" , "[GDMA][M2M]" )
669+ {
670+ [[maybe_unused ]] gdma_channel_handle_t tx_chan = NULL ;
671+ [[maybe_unused ]] gdma_channel_handle_t rx_chan = NULL ;
672+ [[maybe_unused ]] gdma_channel_alloc_config_t tx_chan_alloc_config = {};
673+ [[maybe_unused ]] gdma_channel_alloc_config_t rx_chan_alloc_config = {};
674+
675+ #if SOC_AHB_GDMA_SUPPORTED && SOC_AHB_GDMA_SUPPORT_PSRAM
676+ printf ("Testing AHB-GDMA memory copy SRAM->PSRAM->SRAM\n" );
677+ tx_chan_alloc_config = (gdma_channel_alloc_config_t ) {
678+ .direction = GDMA_CHANNEL_DIRECTION_TX ,
679+ .flags .reserve_sibling = true,
680+ };
681+ TEST_ESP_OK (gdma_new_ahb_channel (& tx_chan_alloc_config , & tx_chan ));
682+ rx_chan_alloc_config = (gdma_channel_alloc_config_t ) {
683+ .direction = GDMA_CHANNEL_DIRECTION_RX ,
684+ .sibling_chan = tx_chan ,
685+ };
686+ TEST_ESP_OK (gdma_new_ahb_channel (& rx_chan_alloc_config , & rx_chan ));
687+
688+ test_gdma_memcpy_from_to_psram (tx_chan , rx_chan );
689+
690+ TEST_ESP_OK (gdma_del_channel (tx_chan ));
691+ TEST_ESP_OK (gdma_del_channel (rx_chan ));
692+ #endif
693+
694+ #if SOC_AXI_GDMA_SUPPORTED && SOC_AXI_GDMA_SUPPORT_PSRAM
695+ printf ("Testing AXI-GDMA memory copy SRAM->PSRAM->SRAM\n" );
696+ tx_chan_alloc_config = (gdma_channel_alloc_config_t ) {
697+ .direction = GDMA_CHANNEL_DIRECTION_TX ,
698+ .flags .reserve_sibling = true,
699+ };
700+ TEST_ESP_OK (gdma_new_axi_channel (& tx_chan_alloc_config , & tx_chan ));
701+ rx_chan_alloc_config = (gdma_channel_alloc_config_t ) {
702+ .direction = GDMA_CHANNEL_DIRECTION_RX ,
703+ .sibling_chan = tx_chan ,
704+ };
705+ TEST_ESP_OK (gdma_new_axi_channel (& rx_chan_alloc_config , & rx_chan ));
706+
707+ test_gdma_memcpy_from_to_psram (tx_chan , rx_chan );
708+
709+ TEST_ESP_OK (gdma_del_channel (tx_chan ));
710+ TEST_ESP_OK (gdma_del_channel (rx_chan ));
711+ #endif
712+ }
713+ #endif // SOC_SPIRAM_SUPPORTED
0 commit comments