GDMA Memory to Memory example code

jesper
Posts: 25
Joined: Thu Nov 09, 2017 4:38 pm

GDMA Memory to Memory example code

Postby jesper » Sun Oct 02, 2022 3:23 pm

Is there any example code available on how to use the GDMA?
Specifically on how to do M2M transfers?

I've been digging all over the sources and internet and can't figure out how to setup the GDMA for this.

Any plans for documentation on the GDMA as a component?

/J
MagicMicros Co., Ltd. - Rayong, Thailand
Electronics design, PCB layout & programming.

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: GDMA Memory to Memory example code

Postby ESP_igrr » Mon Oct 03, 2022 3:42 pm

Hi jesper,
IDF provides a higher level API called "esp_async_memcpy" for this use case. We document it and not the GDMA because there are chips where there is no GDMA, but some kind of memory-copy-DMA is still available (like on ESP32-S2).
The docs for esp_async_memcpy are available here: https://docs.espressif.com/projects/esp ... emcpy.html

GDMA APIs are currently under "esp_private" directory (components/esp_hw_support/include/esp_private/gdma.h), so they are not intended to be used in applications directly. Therefore there is no API reference page for them.

In case you prefer to use the GDMA instead of the esp_async_memcpy, I'm afraid the only reference is the implementation of esp_async_memcpy itself, which you can find here: https://github.com/espressif/esp-idf/bl ... mpl_gdma.c

jesper
Posts: 25
Joined: Thu Nov 09, 2017 4:38 pm

Re: GDMA Memory to Memory example code

Postby jesper » Tue Oct 04, 2022 5:07 am

Excellent!
Thank you very much!
Just what I needed.
MagicMicros Co., Ltd. - Rayong, Thailand
Electronics design, PCB layout & programming.

jprpower104
Posts: 16
Joined: Tue Jul 18, 2023 3:59 am

Re: GDMA Memory to Memory example code

Postby jprpower104 » Wed Sep 20, 2023 9:29 pm

Hi Jesper and ESP_Igrr


Can you implement a example with GDMA?? can you share for learn too? because i can't send nothing with this code...

Code: Select all


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/periph_defs.h"
#include "soc/soc_memory_layout.h"
#include "soc/soc_caps.h"
#include "hal/gdma_ll.h"
#include "hal/gdma_hal.h"
#include "esp_private/periph_ctrl.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "C:/Users/sopor/esp/esp-idf/components/esp_hw_support/port/include/esp_async_memcpy_impl.h"
#include "C:\Users\sopor\esp\esp-idf\components\esp_hw_support\dma\gdma_priv.h"

//#include "esp_async_memcpy_impl.h"

#if SOC_APM_SUPPORTED
    #include "hal/apm_ll.h"
#endif


IRAM_ATTR static bool async_memcpy_impl_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
    async_memcpy_impl_t *mcp_impl = (async_memcpy_impl_t *)user_data;
    mcp_impl->rx_eof_addr = event_data->rx_eof_desc_addr;

    async_memcpy_isr_on_rx_done_event(mcp_impl);
    printf("INT GDMA callbacks sucessful \n");
    return mcp_impl->isr_need_yield;
}

esp_err_t async_memcpy_impl_init(async_memcpy_impl_t *impl)
{
    esp_err_t ret = ESP_OK;
    // create TX channel and reserve sibling channel for future use
    gdma_channel_alloc_config_t tx_alloc_config = 
    {
        .sibling_chan   = NULL, 
        .direction      = GDMA_CHANNEL_DIRECTION_TX,
        .flags = 
        {
            .reserve_sibling = 1
        }
    };

    ret = gdma_new_channel(&tx_alloc_config, &impl->tx_channel);
    if (ret != ESP_OK) 
    {
        return ret;
    }

    // create RX channel and specify it should be reside in the same pair as TX
    gdma_channel_alloc_config_t rx_alloc_config = 
    {
        .sibling_chan   = impl->tx_channel,
        .direction      = GDMA_CHANNEL_DIRECTION_RX,
        .flags = 
        {
            .reserve_sibling = NULL
        }
    };
    ret = gdma_new_channel(&rx_alloc_config, &impl->rx_channel);
    if (ret != ESP_OK) 
    {
        return ret;
    }

    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(impl->tx_channel, &free_m2m_id_mask);
    m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask);
    gdma_connect(impl->rx_channel, m2m_trigger);
    gdma_connect(impl->tx_channel, m2m_trigger);

    gdma_strategy_config_t strategy_config = 
    {
        .owner_check = true,
        .auto_update_desc = true,
    };

    gdma_transfer_ability_t transfer_ability = 
    {
        .sram_trans_align = impl->sram_trans_align,
        .psram_trans_align = impl->psram_trans_align,
    };
    ret = gdma_set_transfer_ability(impl->tx_channel, &transfer_ability);
    if (ret != ESP_OK) 
    {
        return ret;
    }
    ret = gdma_set_transfer_ability(impl->rx_channel, &transfer_ability);
    if (ret != ESP_OK) 
    {
        return ret;
    }
    gdma_apply_strategy(impl->tx_channel, &strategy_config);
    gdma_apply_strategy(impl->rx_channel, &strategy_config);

#if SOC_APM_SUPPORTED
    // APM strategy: trusted mode
    // TODO: IDF-5354 GDMA for M2M usage only need read and write permissions, we should disable the execute permission by the APM controller
    apm_tee_ll_set_master_secure_mode(APM_LL_MASTER_GDMA + m2m_trigger.instance_id, APM_LL_SECURE_MODE_TEE);
#endif // SOC_APM_SUPPORTED

    gdma_rx_event_callbacks_t cbs = 
    {
        .on_recv_eof = async_memcpy_impl_rx_eof_callback
    };

    ret = gdma_register_rx_event_callbacks(impl->rx_channel, &cbs, impl);
    return ret;
}

esp_err_t async_memcpy_impl_deinit(async_memcpy_impl_t *impl)
{
    gdma_disconnect(impl->rx_channel);
    gdma_disconnect(impl->tx_channel);
    gdma_del_channel(impl->rx_channel);
    gdma_del_channel(impl->tx_channel);
    return ESP_OK;
}

esp_err_t async_memcpy_impl_start(async_memcpy_impl_t *impl, intptr_t outlink_base, intptr_t inlink_base)
{
    gdma_start(impl->rx_channel, inlink_base);
    gdma_start(impl->tx_channel, outlink_base);
    return ESP_OK;
}

esp_err_t async_memcpy_impl_stop(async_memcpy_impl_t *impl)
{
    gdma_stop(impl->rx_channel);
    gdma_stop(impl->tx_channel);
    return ESP_OK;
}

esp_err_t async_memcpy_impl_restart(async_memcpy_impl_t *impl)
{
    gdma_append(impl->rx_channel);
    gdma_append(impl->tx_channel);
    return ESP_OK;
}

esp_err_t async_memcpy_impl_new_etm_event(async_memcpy_impl_t *impl, async_memcpy_etm_event_t event_type, esp_etm_event_handle_t *out_event)
{
    if (event_type == ASYNC_MEMCPY_ETM_EVENT_COPY_DONE) {
        // use the RX EOF to indicate the async memcpy done event
        gdma_etm_event_config_t etm_event_conf = {
            .event_type = GDMA_ETM_EVENT_EOF,
        };
        return gdma_new_etm_event(impl->rx_channel, &etm_event_conf, out_event);
    } else {
        return ESP_ERR_NOT_SUPPORTED;
    }
}

bool async_memcpy_impl_is_buffer_address_valid(async_memcpy_impl_t *impl, void *src, void *dst)
{
    bool valid = true;
    if (esp_ptr_external_ram(dst)) {
        if (impl->psram_trans_align) {
            valid = valid && (((intptr_t)dst & (impl->psram_trans_align - 1)) == 0);
        }
    } else {
        if (impl->sram_trans_align) {
            valid = valid && (((intptr_t)dst & (impl->sram_trans_align - 1)) == 0);
        }
    }
    return valid;
}


extern "C" void app_main(void)
{
    esp_err_t ret;
    async_memcpy_impl_t M2M_gmda_test;
    gdma_tx_channel_t tx_ch;
    gdma_rx_channel_t rx_ch;
    char source_buf[] = "hola mundo";
    char receiv_buf[] = "          ";//(char *)malloc(sizeof(source_buf)*sizeof(char));


    ret = async_memcpy_impl_init(&M2M_gmda_test);
    if(ret==ESP_OK)
    {
        printf("M2M GDMA init sucesful! \n");
    }
    else
    {
        printf("Error in M2M GDMA init! \n");
    }

    tx_ch.user_data = &source_buf[0];
    rx_ch.user_data = &receiv_buf[0];

    async_memcpy_impl_start(&M2M_gmda_test, (intptr_t)&tx_ch.base, (intptr_t)&rx_ch.base);
    while(1)
    {
        vTaskDelay(pdMS_TO_TICKS(1000));
        printf("source  buffer = %s \n",source_buf);
        printf("receive buffer = %s \n",receiv_buf);
    }
}


jprpower104
Posts: 16
Joined: Tue Jul 18, 2023 3:59 am

Re: GDMA Memory to Memory example code

Postby jprpower104 » Wed Sep 20, 2023 9:32 pm

Pay attention in the app_main part and I don't can send nothing from "source_buf" to "receiv_buf", if you see the bug more clear of them me, pay share me you oppinion please.

Code: Select all


extern "C" void app_main(void)
{
    esp_err_t ret;
    async_memcpy_impl_t M2M_gmda_test;
    gdma_tx_channel_t tx_ch;
    gdma_rx_channel_t rx_ch;
    char source_buf[] = "hola mundo";
    char receiv_buf[] = "          ";//(char *)malloc(sizeof(source_buf)*sizeof(char));


    ret = async_memcpy_impl_init(&M2M_gmda_test);
    if(ret==ESP_OK)
    {
        printf("M2M GDMA init sucesful! \n");
    }
    else
    {
        printf("Error in M2M GDMA init! \n");
    }

    tx_ch.user_data = &source_buf[0];
    rx_ch.user_data = &receiv_buf[0];

    async_memcpy_impl_start(&M2M_gmda_test, (intptr_t)&tx_ch.base, (intptr_t)&rx_ch.base);
    while(1)
    {
        vTaskDelay(pdMS_TO_TICKS(1000));
        printf("source  buffer = %s \n",source_buf);
        printf("receive buffer = %s \n",receiv_buf);
    }
}


Who is online

Users browsing this forum: jsmith56x, sterisa and 267 guests