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
GDMA Memory to Memory example code
GDMA Memory to Memory example code
MagicMicros Co., Ltd. - Rayong, Thailand
Electronics design, PCB layout & programming.
Electronics design, PCB layout & programming.
Re: GDMA Memory to Memory example code
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
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
Re: GDMA Memory to Memory example code
Excellent!
Thank you very much!
Just what I needed.
Thank you very much!
Just what I needed.
MagicMicros Co., Ltd. - Rayong, Thailand
Electronics design, PCB layout & programming.
Electronics design, PCB layout & programming.
-
- Posts: 16
- Joined: Tue Jul 18, 2023 3:59 am
Re: GDMA Memory to Memory example code
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...
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);
}
}
-
- Posts: 16
- Joined: Tue Jul 18, 2023 3:59 am
Re: GDMA Memory to Memory example code
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: No registered users and 101 guests