Merge branch 'feat/add_esp_dma_capable_malloc' into 'master'

dma_utils: add esp dma capable malloc function

Closes IDF-9638

See merge request espressif/esp-idf!29869
pull/13550/head
Gao Xu 2024-04-02 21:31:45 +08:00
commit db3e43908a
41 zmienionych plików z 830 dodań i 441 usunięć

Wyświetl plik

@ -1,4 +1,4 @@
[codespell]
skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb
ignore-words-list = ser,dout,rsource,fram,inout
ignore-words-list = ser,dout,rsource,fram,inout,shs
write-changes = true

Wyświetl plik

@ -575,14 +575,19 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj)
size_t desc_size = 0;
for (int cnt = 0; cnt < buf_cnt; cnt++) {
/* Allocate DMA buffer */
esp_dma_calloc(1, sizeof(char) * dma_obj->buf_size, (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA), (void **)&dma_obj->buf[cnt], NULL);
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = MALLOC_CAP_INTERNAL,
.dma_alignment_bytes = 4,
};
//TODO: IDF-9636
esp_dma_capable_calloc(1, sizeof(char) * dma_obj->buf_size, &dma_mem_info, (void **)&dma_obj->buf[cnt], NULL);
ESP_GOTO_ON_FALSE(dma_obj->buf[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma buffer");
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(dma_obj->buf[cnt], dma_obj->buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
/* Allocate DMA descriptor */
esp_dma_calloc(1, sizeof(lldesc_t), MALLOC_CAP_DEFAULT, (void **)&dma_obj->desc[cnt], &desc_size);
esp_dma_capable_calloc(1, sizeof(lldesc_t), &dma_mem_info, (void **)&dma_obj->desc[cnt], &desc_size);
ESP_GOTO_ON_FALSE(dma_obj->desc[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma description entry");
}
/* DMA descriptor must be initialize after all descriptor has been created, otherwise they can't be linked together as a chain */

Wyświetl plik

@ -69,10 +69,15 @@
static const char *TAG = "i2s_common";
__attribute__((always_inline))
inline void *i2s_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size)
inline void *i2s_dma_calloc(i2s_chan_handle_t handle, size_t num, size_t size, size_t *actual_size)
{
void *ptr = NULL;
esp_dma_calloc(num, size, caps, &ptr, actual_size);
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = I2S_DMA_ALLOC_CAPS,
.dma_alignment_bytes = 4,
};
//TODO: IDF-9636
esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size);
return ptr;
}
@ -422,7 +427,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
size_t desc_size = 0;
for (int i = 0; i < num; i++) {
/* Allocate DMA descriptor */
handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS, &desc_size);
handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(handle, 1, sizeof(lldesc_t), &desc_size);
ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed");
handle->dma.desc[i]->owner = 1;
handle->dma.desc[i]->eof = 1;
@ -430,7 +435,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
handle->dma.desc[i]->length = bufsize;
handle->dma.desc[i]->size = bufsize;
handle->dma.desc[i]->offset = 0;
handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS, NULL);
handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(handle, 1, bufsize * sizeof(uint8_t), NULL);
ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed");
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(handle->dma.bufs[i], bufsize * sizeof(uint8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M);

Wyświetl plik

@ -176,7 +176,11 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_
ESP_RETURN_ON_FALSE(decoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg decode handle is null");
ESP_RETURN_ON_FALSE(decode_cfg, ESP_ERR_INVALID_ARG, TAG, "jpeg decode config is null");
ESP_RETURN_ON_FALSE(decode_outbuf, ESP_ERR_INVALID_ARG, TAG, "jpeg decode picture buffer is null");
ESP_RETURN_ON_FALSE(esp_dma_is_buffer_aligned(decode_outbuf, outbuf_size, ESP_DMA_BUF_LOCATION_PSRAM), ESP_ERR_INVALID_ARG, TAG, "jpeg decode decode_outbuf or out_buffer size is not aligned, please use jpeg_alloc_decoder_mem to malloc your buffer");
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = 4,
};
//TODO: IDF-9637
ESP_RETURN_ON_FALSE(esp_dma_is_buffer_alignment_satisfied(decode_outbuf, outbuf_size, dma_mem_info), ESP_ERR_INVALID_ARG, TAG, "jpeg decode decode_outbuf or out_buffer size is not aligned, please use jpeg_alloc_decoder_mem to malloc your buffer");
esp_err_t ret = ESP_OK;

Wyświetl plik

@ -46,6 +46,7 @@ extern "C" {
.set_input_delay = &sdmmc_host_set_input_delay, \
.dma_aligned_buffer = NULL, \
.pwr_ctrl_handle = NULL, \
.get_dma_info = &sdmmc_host_get_dma_info, \
}
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -247,6 +247,17 @@ esp_err_t sdmmc_host_get_real_freq(int slot, int* real_freq_khz);
*/
esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase);
/**
* @brief Get the DMA memory information for the host driver
*
* @param[in] slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param[out] dma_mem_info DMA memory information structure
* @return
* - ESP_OK: ON success.
* - ESP_ERR_INVALID_ARG: Invalid argument.
*/
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -921,3 +921,13 @@ static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width)
}
return ESP_OK;
}
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info)
{
if (!(slot == 0 || slot == 1)) {
return ESP_ERR_INVALID_ARG;
}
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
dma_mem_info->dma_alignment_bytes = 4;
return ESP_OK;
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -53,7 +53,8 @@ typedef int sdspi_dev_handle_t;
.command_timeout_ms = 0, \
.get_real_freq = &sdspi_host_get_real_freq, \
.input_delay_phase = SDMMC_DELAY_PHASE_0, \
.set_input_delay = NULL \
.set_input_delay = NULL, \
.get_dma_info = &sdspi_host_get_dma_info, \
}
/**
@ -209,6 +210,17 @@ esp_err_t sdspi_host_io_int_enable(sdspi_dev_handle_t handle);
*/
esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_ticks);
/**
* @brief Get the DMA memory information for the host driver
*
* @param[in] slot Not used
* @param[out] dma_mem_info DMA memory information structure
* @return
* - ESP_OK: ON success.
* - ESP_ERR_INVALID_ARG: Invalid argument.
*/
esp_err_t sdspi_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -998,3 +998,11 @@ esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_t
}
return ESP_OK;
}
esp_err_t sdspi_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info)
{
(void)slot;
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
dma_mem_info->dma_alignment_bytes = 4;
return ESP_OK;
}

Wyświetl plik

@ -451,7 +451,7 @@ typedef struct {
#define ETH_MAC_DEFAULT_CONFIG() \
{ \
.sw_reset_timeout_ms = 100, \
.rx_task_stack_size = 2048, \
.rx_task_stack_size = 4096, \
.rx_task_prio = 15, \
.flags = 0, \
}

Wyświetl plik

@ -385,7 +385,7 @@ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_
buf = malloc(copy_len);
if (buf != NULL) {
emac_esp_dma_auto_buf_info_t *buff_info = (emac_esp_dma_auto_buf_info_t *)buf;
/* no need to check allocated buffer min lenght prior writing since we know that EMAC DMA is configured to
/* no need to check allocated buffer min length prior writing since we know that EMAC DMA is configured to
not forward erroneous or undersized frames (less than 64B) on ESP32, see emac_hal_init_dma_default */
#ifndef NDEBUG
buff_info->magic_id = EMAC_HAL_BUF_MAGIC_ID;
@ -531,15 +531,20 @@ esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_han
/* alloc memory for ethernet dma descriptor */
uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
esp_dma_calloc(1, desc_size, 0, (void*)&emac_esp_dma->descriptors, NULL);
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = MALLOC_CAP_INTERNAL,
.dma_alignment_bytes = 4,
};
esp_dma_capable_calloc(1, desc_size, &dma_mem_info, (void*)&emac_esp_dma->descriptors, NULL);
ESP_GOTO_ON_FALSE(emac_esp_dma->descriptors, ESP_ERR_NO_MEM, err, TAG, "no mem for descriptors");
/* alloc memory for ethernet dma buffer */
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
esp_dma_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, 0, (void*)&emac_esp_dma->rx_buf[i], NULL);
esp_dma_capable_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, &dma_mem_info, (void*)&emac_esp_dma->rx_buf[i], NULL);
ESP_GOTO_ON_FALSE(emac_esp_dma->rx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for RX DMA buffers");
}
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
esp_dma_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, 0, (void*)&emac_esp_dma->tx_buf[i], NULL);
esp_dma_capable_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, &dma_mem_info, (void*)&emac_esp_dma->tx_buf[i], NULL);
ESP_GOTO_ON_FALSE(emac_esp_dma->tx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for TX DMA buffers");
}
emac_hal_init(&emac_esp_dma->hal);

Wyświetl plik

@ -15,38 +15,156 @@
#include "esp_dma_utils.h"
#include "esp_private/esp_cache_private.h"
#include "soc/soc_caps.h"
#include "hal/hal_utils.h"
static const char *TAG = "dma_utils";
_Static_assert(ESP_DMA_MALLOC_FLAG_PSRAM == ESP_CACHE_MALLOC_FLAG_PSRAM);
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_DOWN_BY(num, align) ((num) & (~((align) - 1)))
esp_err_t esp_dma_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size)
esp_err_t esp_dma_capable_malloc(size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size)
{
ESP_RETURN_ON_FALSE_ISR(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer");
ESP_RETURN_ON_FALSE_ISR(dma_mem_info && out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer");
esp_err_t ret = ESP_OK;
size_t alignment_bytes = 0;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
ret = esp_cache_aligned_malloc(size, flags | ESP_CACHE_MALLOC_FLAG_DMA, out_ptr, actual_size);
#else
if (flags & ESP_DMA_MALLOC_FLAG_PSRAM) {
ret = esp_cache_aligned_malloc(size, flags | ESP_CACHE_MALLOC_FLAG_DMA, out_ptr, actual_size);
} else {
size = ALIGN_UP_BY(size, 4);
void *ptr = heap_caps_aligned_alloc(4, size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
ESP_RETURN_ON_FALSE_ISR(ptr, ESP_ERR_NO_MEM, TAG, "no enough heap memory");
*out_ptr = ptr;
if (actual_size) {
*actual_size = size;
}
//dma align
size_t dma_alignment_bytes = dma_mem_info->dma_alignment_bytes;
//cache align
int cache_flags = 0;
size_t cache_alignment_bytes = 0;
int heap_caps = dma_mem_info->extra_heap_caps | MALLOC_CAP_DMA;
if (dma_mem_info->extra_heap_caps & MALLOC_CAP_SPIRAM) {
cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
heap_caps = dma_mem_info->extra_heap_caps | MALLOC_CAP_SPIRAM;
}
esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment_bytes);
assert(ret == ESP_OK);
//Get the least common multiple of two alignment
alignment_bytes = hal_utils_calc_lcm(dma_alignment_bytes, cache_alignment_bytes);
//malloc
size = ALIGN_UP_BY(size, alignment_bytes);
void *ptr = heap_caps_aligned_alloc(alignment_bytes, size, heap_caps);
ESP_RETURN_ON_FALSE_ISR(ptr, ESP_ERR_NO_MEM, TAG, "Not enough heap memory");
*out_ptr = ptr;
if (actual_size) {
*actual_size = size;
}
return ESP_OK;
}
esp_err_t esp_dma_capable_calloc(size_t calloc_num, size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size)
{
esp_err_t ret = ESP_FAIL;
size_t size_bytes = 0;
bool ovf = false;
ovf = __builtin_mul_overflow(calloc_num, size, &size_bytes);
ESP_RETURN_ON_FALSE_ISR(!ovf, ESP_ERR_INVALID_ARG, TAG, "wrong size, total size overflow");
void *ptr = NULL;
ret = esp_dma_capable_malloc(size_bytes, dma_mem_info, &ptr, actual_size);
if (ret == ESP_OK) {
memset(ptr, 0, size_bytes);
*out_ptr = ptr;
}
#endif
return ret;
}
static bool s_buf_in_region(const void *ptr, size_t size, esp_dma_buf_location_t location)
{
bool found = false;
if (location == ESP_DMA_BUF_LOCATION_INTERNAL) {
if (esp_ptr_dma_capable(ptr) && esp_ptr_dma_capable(ptr + size - 1)) {
found = true;
}
} else if (location == ESP_DMA_BUF_LOCATION_PSRAM) {
#if SOC_PSRAM_DMA_CAPABLE
if (esp_ptr_external_ram(ptr) && esp_ptr_external_ram(ptr + size - 1)) {
found = true;
}
#endif
}
return found;
}
static inline bool s_is_buf_aligned(intptr_t ptr, size_t alignment)
{
return (ptr % alignment == 0);
}
bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma_mem_info_t dma_mem_info)
{
assert(ptr);
bool found = false;
for (int i = ESP_DMA_BUF_LOCATION_INTERNAL; i < ESP_DMA_BUF_LOCATION_AUTO; i++) {
if (s_buf_in_region(ptr, size, i)) {
found = true;
break;
}
}
if (!found) {
return false;
}
size_t alignment_bytes = 0;
//dma align
size_t dma_alignment_bytes = dma_mem_info.dma_alignment_bytes;
//cache align
int cache_flags = 0;
size_t cache_alignment_bytes = 0;
if (esp_ptr_external_ram(ptr)) {
cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
}
esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment_bytes);
assert(ret == ESP_OK);
//Get the least common multiple of two alignment
alignment_bytes = hal_utils_calc_lcm(dma_alignment_bytes, cache_alignment_bytes);
bool is_aligned = s_is_buf_aligned((intptr_t)ptr, alignment_bytes) && s_is_buf_aligned((intptr_t)size, alignment_bytes);
return is_aligned;
}
//-----------------------Deprecated APIs-----------------------//
esp_err_t s_legacy_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size)
{
ESP_RETURN_ON_FALSE_ISR(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer");
int heap_caps = 0;
if (flags & ESP_DMA_MALLOC_FLAG_PSRAM) {
heap_caps |= MALLOC_CAP_SPIRAM;
} else {
heap_caps |= MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL;
}
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = heap_caps,
.dma_alignment_bytes = 4, //legacy API behaviour is only check max dma buffer alignment
};
ESP_RETURN_ON_ERROR_ISR(esp_dma_capable_malloc(size, &dma_mem_info, out_ptr, actual_size), TAG, "failed to do malloc");
return ESP_OK;
}
esp_err_t esp_dma_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size)
{
return s_legacy_malloc(size, flags, out_ptr, actual_size);
}
esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, size_t *actual_size)
{
@ -60,7 +178,7 @@ esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr,
ESP_RETURN_ON_FALSE_ISR(!ovf, ESP_ERR_INVALID_ARG, TAG, "wrong size, total size overflow");
void *ptr = NULL;
ret = esp_dma_malloc(size_bytes, flags, &ptr, actual_size);
ret = s_legacy_malloc(size_bytes, flags, &ptr, actual_size);
if (ret == ESP_OK) {
memset(ptr, 0, size_bytes);
*out_ptr = ptr;
@ -69,17 +187,18 @@ esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr,
return ret;
}
static bool s_buf_in_region(const void *ptr, size_t size, esp_dma_buf_location_t location, uint32_t *in_out_flags)
static bool s_buf_in_region_legacy(const void *ptr, size_t size, esp_dma_buf_location_t location, int *heap_caps)
{
bool found = false;
if (location == ESP_DMA_BUF_LOCATION_INTERNAL) {
if (esp_ptr_dma_capable(ptr) && esp_ptr_dma_capable(ptr + size - 1)) {
*heap_caps = MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL;
found = true;
}
} else if (location == ESP_DMA_BUF_LOCATION_PSRAM) {
#if SOC_PSRAM_DMA_CAPABLE
if (esp_ptr_external_ram(ptr) && esp_ptr_external_ram(ptr + size - 1)) {
*in_out_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
*heap_caps = MALLOC_CAP_SPIRAM;
found = true;
}
#endif
@ -90,33 +209,28 @@ static bool s_buf_in_region(const void *ptr, size_t size, esp_dma_buf_location_t
bool esp_dma_is_buffer_aligned(const void *ptr, size_t size, esp_dma_buf_location_t location)
{
assert(ptr);
uint32_t flags = ESP_CACHE_MALLOC_FLAG_DMA;
bool found = false;
int heap_caps = 0;
if (location == ESP_DMA_BUF_LOCATION_AUTO) {
for (int i = ESP_DMA_BUF_LOCATION_INTERNAL; i < ESP_DMA_BUF_LOCATION_AUTO; i++) {
if (s_buf_in_region(ptr, size, i, &flags)) {
if (s_buf_in_region_legacy(ptr, size, i, &heap_caps)) {
found = true;
break;
}
}
} else if (location == ESP_DMA_BUF_LOCATION_INTERNAL) {
found = s_buf_in_region(ptr, size, ESP_DMA_BUF_LOCATION_INTERNAL, &flags);
found = s_buf_in_region_legacy(ptr, size, ESP_DMA_BUF_LOCATION_INTERNAL, &heap_caps);
} else {
found = s_buf_in_region(ptr, size, ESP_DMA_BUF_LOCATION_PSRAM, &flags);
found = s_buf_in_region_legacy(ptr, size, ESP_DMA_BUF_LOCATION_PSRAM, &heap_caps);
}
if (!found) {
return false;
}
bool is_aligned = false;
size_t dma_alignment = 0;
size_t cache_alignment = 0;
size_t alignment = 0;
esp_err_t ret = esp_cache_get_alignment(flags, &cache_alignment);
assert(ret == ESP_OK);
alignment = MAX(dma_alignment, cache_alignment);
is_aligned = ((intptr_t)ptr % alignment == 0) && (size % alignment == 0);
return is_aligned;
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = heap_caps,
.dma_alignment_bytes = 4, //legacy API behaviour is only check max dma buffer alignment
};
return esp_dma_is_buffer_alignment_satisfied(ptr, size, dma_mem_info);
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

Wyświetl plik

@ -9,11 +9,77 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "esp_heap_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief DMA Mem info
*/
typedef struct {
int extra_heap_caps; ///< extra heap caps based on MALLOC_CAP_DMA
size_t dma_alignment_bytes; ///< DMA alignment
} esp_dma_mem_info_t;
/**
* @brief Helper function for malloc a DMA capable memory buffer
*
* @note This API will take care of the cache alignment internally,
* you will need to set `esp_dma_mem_info_t: dma_alignment_bytes`
* with either the custom alignment or DMA alignment of used peripheral driver.
*
* @param[in] size Size in bytes, the amount of memory to allocate
* @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t`
* @param[out] out_ptr A pointer to the memory allocated successfully
* @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the DMA alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value.
*
* @return
* - ESP_OK:
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NO_MEM: No enough memory for allocation
*/
esp_err_t esp_dma_capable_malloc(size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size);
/**
* @brief Helper function for calloc a DMA capable memory buffer
*
* @param[in] calloc_num Number of elements to allocate
* @param[in] size Size in bytes, the amount of memory to allocate
* @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t`
* @param[out] out_ptr A pointer to the memory allocated successfully
* @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the DMA alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value.
*
* @return
* - ESP_OK:
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NO_MEM: No enough memory for allocation
*/
esp_err_t esp_dma_capable_calloc(size_t calloc_num, size_t size, const esp_dma_mem_info_t *dma_mem_info, void **out_ptr, size_t *actual_size);
/**
* @brief Helper function to check if a DMA buffer pointer and size meet both hardware alignment requirements and custom alignment requirements
*
* @param[in] ptr Pointer to the buffer
* @param[in] size Size of the buffer
* @param[in] dma_mem_info DMA and memory info, see `esp_dma_mem_info_t`
*
* @return
* - True: Buffer is aligned
* - False: Buffer is not aligned, or buffer is not DMA capable
*/
bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma_mem_info_t dma_mem_info);
/**
* @brief Needed info to get GDMA alignment
*/
typedef struct {
bool is_desc; ///< allocate DMA descriptor
bool on_psram; ///< allocate DMA from the PSRAM
} dma_alignment_info_t;
//-----------------------Deprecated APIs-----------------------//
/**
* DMA malloc flags
*/
@ -23,35 +89,16 @@ extern "C" {
#define ESP_DMA_MALLOC_FLAG_PSRAM BIT(0)
/**
* @brief Helper function for malloc a DMA capable memory buffer
*
* @param[in] size Size in bytes, the amount of memory to allocate
* @param[in] flags Flags, see `ESP_DMA_MALLOC_FLAG_x`
* @param[out] out_ptr A pointer to the memory allocated successfully
* @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the DMA alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value.
*
* @return
* - ESP_OK:
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NO_MEM: No enough memory for allocation
* @note This API will use MAX alignment requirement
*/
esp_err_t esp_dma_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size);
esp_err_t esp_dma_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size)
__attribute__((deprecated("esp_dma_malloc is deprecated, please use esp_dma_capable_malloc")));
/**
* @brief Helper function for calloc a DMA capable memory buffer
*
* @param[in] n Number of continuing chunks of memory to allocate
* @param[in] size Size of one chunk, in bytes
* @param[in] flags Flags, see `ESP_DMA_MALLOC_FLAG_x`
* @param[out] out_ptr A pointer to the memory allocated successfully
* @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the cache alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value.
*
* @return
* - ESP_OK:
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NO_MEM: No enough memory for allocation
* @note This API will use MAX alignment requirement
*/
esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, size_t *actual_size);
esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, size_t *actual_size)
__attribute__((deprecated("esp_dma_calloc is deprecated, please use esp_dma_capable_calloc")));
/**
* @brief DMA buffer location
@ -63,17 +110,10 @@ typedef enum {
} esp_dma_buf_location_t;
/**
* @brief Helper function to check if a buffer meets DMA alignment requirements
*
* @param[in] ptr Pointer to the buffer
* @param[in] size Size of the buffer
* @param[in] location Location of the DMA buffer, see `esp_dma_buf_location_t`
*
* @return
* - True: Buffer is aligned
* - False: Buffer is not aligned, or buffer is not DMA capable
* @note This API will use MAX alignment requirement
*/
bool esp_dma_is_buffer_aligned(const void *ptr, size_t size, esp_dma_buf_location_t location);
bool esp_dma_is_buffer_aligned(const void *ptr, size_t size, esp_dma_buf_location_t location)
__attribute__((deprecated("esp_dma_is_buffer_aligned is deprecated, please use esp_dma_is_buffer_alignment_satisfied")));
#ifdef __cplusplus
}

Wyświetl plik

@ -1,4 +1,4 @@
set(srcs "test_app_main.c")
set(srcs "test_app_main.c" "test_dma_utils.c")
if(CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED)
list(APPEND srcs "test_async_memcpy.c")

Wyświetl plik

@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "unity.h"
#include "esp_log.h"
#include "esp_dma_utils.h"
#include "esp_private/esp_cache_private.h"
#include "esp_private/gdma.h"
#include "soc/soc_caps.h"
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
static const char *TAG = "test_dma_utils";
#if CONFIG_SPIRAM
/**
* To test the API logic is correct, here we simply use max value under default sdkconfig
*/
#if CONFIG_IDF_TARGET_ESP32P4
#define TEST_BUFFER_PSRAM_ALIGNMENT 64
#else
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define TEST_BUFFER_PSRAM_ALIGNMENT 4
#else
#define TEST_BUFFER_PSRAM_ALIGNMENT 32
#endif
#endif
TEST_CASE("test esp_dma_capable_malloc for PSRAM", "[dma_utils]")
{
size_t test_size = 0;
void *test_ptr = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = MALLOC_CAP_SPIRAM,
.dma_alignment_bytes = 4,
};
//------ psram ------//
//aligned
test_size = TEST_BUFFER_PSRAM_ALIGNMENT;
ESP_LOGI(TAG, "to alloc 0x%zx", test_size);
TEST_ESP_OK(esp_dma_capable_malloc(test_size, &dma_mem_info, &test_ptr, &actual_size));
ESP_LOGI(TAG, "get test_ptr: %p, actual_size: 0x%zx", test_ptr, actual_size);
TEST_ASSERT((uint32_t)test_ptr % TEST_BUFFER_PSRAM_ALIGNMENT == 0);
TEST_ASSERT(test_size == actual_size);
free(test_ptr);
//unaligned
test_size = TEST_BUFFER_PSRAM_ALIGNMENT + TEST_BUFFER_PSRAM_ALIGNMENT / 2;
ESP_LOGI(TAG, "to alloc 0x%zx", test_size);
TEST_ESP_OK(esp_dma_capable_malloc(test_size, &dma_mem_info, &test_ptr, &actual_size));
ESP_LOGI(TAG, "get test_ptr: %p, actual_size: 0x%zx", test_ptr, actual_size);
TEST_ASSERT((uint32_t)test_ptr % TEST_BUFFER_PSRAM_ALIGNMENT == 0);
TEST_ASSERT(ALIGN_UP_BY(test_size, TEST_BUFFER_PSRAM_ALIGNMENT) == actual_size);
free(test_ptr);
}
#endif
TEST_CASE("test esp_dma_is_buffer_alignment_satisfied", "[dma_utils]")
{
size_t test_size = 64;
void *test_ptr = NULL;
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = 4,
};
TEST_ESP_OK(esp_dma_capable_malloc(test_size, &dma_mem_info, &test_ptr, NULL));
ESP_LOGI(TAG, "test_ptr %p", test_ptr);
bool is_aligned = esp_dma_is_buffer_alignment_satisfied(test_ptr, test_size, dma_mem_info);
TEST_ASSERT(is_aligned);
is_aligned = esp_dma_is_buffer_alignment_satisfied(test_ptr + 3, test_size, dma_mem_info);
TEST_ASSERT(!is_aligned);
}

Wyświetl plik

@ -218,10 +218,6 @@ esp_err_t esp_cache_get_alignment(uint32_t flags, size_t *out_alignment)
}
data_cache_line_size = cache_hal_get_cache_line_size(cache_level, CACHE_TYPE_DATA);
if (data_cache_line_size == 0) {
//default alignment
data_cache_line_size = 4;
}
*out_alignment = data_cache_line_size;

Wyświetl plik

@ -47,6 +47,8 @@ extern "C" {
#define GDMA_LL_AHB_PAIRS_PER_GROUP 1 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
///////////////////////////////////// Common /////////////////////////////////////////
/**

Wyświetl plik

@ -47,6 +47,8 @@ extern "C" {
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
///////////////////////////////////// Common /////////////////////////////////////////
/**

Wyświetl plik

@ -99,6 +99,8 @@ extern "C" {
// TODO: Workaround for C5-beta3 only. C5-mp can still vectorized channels into an array in gdma_struct.h
#define GDMA_LL_CHANNEL_GET_REG_ADDR(dev, ch) ((volatile gdma_chn_reg_t*[]){&dev->channel0, &dev->channel1, &dev->channel2}[(ch)])
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
///////////////////////////////////// Common /////////////////////////////////////////
/**

Wyświetl plik

@ -50,6 +50,8 @@ extern "C" {
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \
[GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \

Wyświetl plik

@ -50,6 +50,8 @@ extern "C" {
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \
[GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \

Wyświetl plik

@ -45,6 +45,9 @@
#define GDMA_LL_AHB_MAX_CRC_BIT_WIDTH 32 // Max CRC bit width supported by AHB GDMA
#define GDMA_LL_AXI_MAX_CRC_BIT_WIDTH 16 // Max CRC bit width supported by AXI GDMA
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
#define GDMA_LL_AXI_DESC_ALIGNMENT 8
#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \
(uint32_t[2][GDMA_ETM_EVENT_MAX]){ \
{ \

Wyświetl plik

@ -60,6 +60,8 @@ extern "C" {
#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups
#define GDMA_LL_AHB_PAIRS_PER_GROUP 5 // Number of GDMA pairs in each AHB group
#define GDMA_LL_AHB_DESC_ALIGNMENT 4
///////////////////////////////////// Common /////////////////////////////////////////
/**
@ -336,7 +338,7 @@ static inline uint32_t gdma_ll_rx_get_prefetched_desc_addr(gdma_dev_t *dev, uint
*/
static inline void gdma_ll_rx_set_weight(gdma_dev_t *dev, uint32_t channel, uint32_t weight)
{
dev->channel[channel].in.wight.rx_weight = weight;
dev->channel[channel].in.weight.rx_weight = weight;
}
/**
@ -595,7 +597,7 @@ static inline uint32_t gdma_ll_tx_get_prefetched_desc_addr(gdma_dev_t *dev, uint
*/
static inline void gdma_ll_tx_set_weight(gdma_dev_t *dev, uint32_t channel, uint32_t weight)
{
dev->channel[channel].out.wight.tx_weight = weight;
dev->channel[channel].out.weight.tx_weight = weight;
}
/**

Wyświetl plik

@ -7,25 +7,6 @@
#include "hal/hal_utils.h"
#include "hal/assert.h"
/**
* @brief helper function, calculate the Greatest Common Divisor
* @note gcd(a, b) = gcd(b, a % b)
* @param a bigger value
* @param b smaller value
* @return result of gcd(a, b)
*/
__attribute__((always_inline))
static inline uint32_t _gcd(uint32_t a, uint32_t b)
{
uint32_t c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
__attribute__((always_inline))
static inline uint32_t _sub_abs(uint32_t a, uint32_t b)
{
@ -45,7 +26,7 @@ uint32_t hal_utils_calc_clk_div_frac_fast(const hal_utils_clk_info_t *clk_info,
// Carry bit if the decimal is greater than 1.0 - 1.0 / ((max_fract - 1) * 2)
if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract - 1) * 2) {
// Calculate the Greatest Common Divisor, time complexity O(log n)
uint32_t gcd = _gcd(clk_info->exp_freq_hz, freq_error);
uint32_t gcd = hal_utils_gcd(clk_info->exp_freq_hz, freq_error);
// divide by the Greatest Common Divisor to get the accurate fraction before normalization
div_denom = clk_info->exp_freq_hz / gcd;
div_numer = freq_error / gcd;

Wyświetl plik

@ -23,7 +23,7 @@ typedef enum {
} hal_utils_div_round_opt_t;
/**
* @brief Clock infomation
* @brief Clock information
*
*/
typedef struct {
@ -53,7 +53,7 @@ typedef struct {
* @note Speed first algorithm, Time complexity O(log n).
* About 8~10 times faster than the accurate algorithm
*
* @param[in] clk_info The clock infomation
* @param[in] clk_info The clock information
* @param[out] clk_div The clock division with integral and fractal part
* @return
* - 0: Failed to get the result because the division is out of range
@ -66,7 +66,7 @@ uint32_t hal_utils_calc_clk_div_frac_fast(const hal_utils_clk_info_t *clk_info,
* @note Accuracy first algorithm, Time complexity O(n).
* About 1~hundreds times more accurate than the fast algorithm
*
* @param[in] clk_info The clock infomation
* @param[in] clk_info The clock information
* @param[out] clk_div The clock division with integral and fractal part
* @return
* - 0: Failed to get the result because the division is out of range
@ -77,12 +77,12 @@ uint32_t hal_utils_calc_clk_div_frac_accurate(const hal_utils_clk_info_t *clk_in
/**
* @brief Calculate the clock division without fractal part
*
* @param[in] clk_info The clock infomation
* @param[in] clk_info The clock information
* @param[out] int_div The clock integral division
* @return
* - 0: Failed to get the result because the division is out of range,
* but parameter `int_div` will still be assigned to min/max division that given in `clk_info`,
* incase the caller still want to use the min/max division in this case.
* in case the caller still want to use the min/max division in this case.
* - others: The real output clock frequency
*/
uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, uint32_t *int_div);
@ -102,6 +102,52 @@ static inline uint8_t hal_utils_bitwise_reverse8(uint8_t n)
return n;
}
/**
* @brief Helper function to calculate the GCD between two numbers using the Euclidean algorithm.
* Calculate the Greatest Common Divisor (GDC) of two unsigned numbers
*
* @param num_1 First number
* @param num_2 Second number
* @return GCD of 'a' and 'b'
*/
__attribute__((always_inline))
static inline uint32_t hal_utils_gcd(uint32_t num_1, uint32_t num_2)
{
uint32_t a, b, rem;
// Always mod larger number by smaller number
if (num_1 > num_2) {
a = num_1;
b = num_2;
} else {
b = num_2;
a = num_1;
}
rem = a % b;
while (rem != 0) {
a = b;
b = rem;
rem = a % b;
}
return b;
}
/**
* @brief Get the least common multiple of two integer
*
* @param[in] Integer A
* @param[in] Integer B
*
* @return LCM of A and B
*/
__attribute__((always_inline))
static inline uint32_t hal_utils_calc_lcm(uint32_t a, uint32_t b)
{
a = a == 0 ? 1 : a;
b = b == 0 ? 1 : b;
return (a * b / hal_utils_gcd(a, b));
}
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -46,7 +46,7 @@
#define AES_DMA_INTR_TRIG_LEN 2000
/* With buffers in PSRAM (worst condition) we still achieve a speed of 4 MB/s
thus a 2 second timeout value should be suffient for even very large buffers.
thus a 2 second timeout value should be sufficient for even very large buffers.
*/
#define AES_WAIT_INTR_TIMEOUT_MS 2000
@ -98,7 +98,7 @@ void esp_aes_intr_alloc(void)
static StaticSemaphore_t op_sem_buf;
op_complete_sem = xSemaphoreCreateBinaryStatic(&op_sem_buf);
// Static semaphore creation is unlikley to fail but still basic sanity
// Static semaphore creation is unlikely to fail but still basic sanity
assert(op_complete_sem != NULL);
}
}
@ -164,7 +164,7 @@ static int esp_aes_dma_wait_complete(bool use_intr, crypto_dma_desc_t *output_de
}
/* Output buffers in external ram needs to be 16-byte aligned and DMA cant access input in the iCache mem range,
/* Output buffers in external ram needs to be 16-byte aligned and DMA can't access input in the iCache mem range,
reallocate them into internal memory and encrypt in chunks to avoid
having to malloc too big of a buffer
@ -276,7 +276,11 @@ static inline void dma_desc_append(crypto_dma_desc_t **head, crypto_dma_desc_t *
static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size)
{
void *ptr = NULL;
esp_dma_calloc(num, size, caps, &ptr, actual_size);
esp_dma_mem_info_t dma_mem_info = {
.extra_heap_caps = caps,
.dma_alignment_bytes = DMA_DESC_MEM_ALIGN_SIZE,
};
esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size);
return ptr;
}

Wyświetl plik

@ -7,9 +7,12 @@
#pragma once
#include "hal/dma_types.h"
#include "soc/gdma_channel.h"
#include "soc/soc_caps.h"
#if SOC_GDMA_SUPPORTED
#include "soc/gdma_channel.h"
#include "hal/gdma_ll.h"
#endif /* SOC_GDMA_SUPPORTED */
#ifdef __cplusplus
extern "C"
@ -22,17 +25,17 @@ extern "C"
#if (SOC_AES_GDMA) || (SOC_SHA_GDMA)
#if (SOC_GDMA_TRIG_PERIPH_AES0_BUS == SOC_GDMA_BUS_AHB) || (SOC_GDMA_TRIG_PERIPH_SHA0_BUS == SOC_GDMA_BUS_AHB)
#define DMA_DESC_MEM_ALIGN_SIZE 4
#define DMA_DESC_MEM_ALIGN_SIZE GDMA_LL_AHB_DESC_ALIGNMENT
typedef dma_descriptor_align4_t crypto_dma_desc_t;
#elif (SOC_GDMA_TRIG_PERIPH_AES0_BUS == SOC_GDMA_BUS_AXI) || (SOC_GDMA_TRIG_PERIPH_SHA0_BUS == SOC_GDMA_BUS_AXI)
#define DMA_DESC_MEM_ALIGN_SIZE 8
#define DMA_DESC_MEM_ALIGN_SIZE GDMA_LL_AXI_DESC_ALIGNMENT
typedef dma_descriptor_align8_t crypto_dma_desc_t;
#else
#error "As we support a shared crypto GDMA layer for the AES and the SHA peripheral, both the peripherals must use the same GDMA bus"
#endif /* (SOC_GDMA_TRIG_PERIPH_AES0_BUS == SOC_GDMA_BUS_AHB) || (SOC_GDMA_TRIG_PERIPH_AES0_BUS == SOC_GDMA_BUS_AHB) */
#elif (SOC_AES_CRYPTO_DMA) || (SOC_SHA_CRYPTO_DMA)
#define DMA_DESC_MEM_ALIGN_SIZE 4
#define DMA_DESC_MEM_ALIGN_SIZE GDMA_LL_AHB_DESC_ALIGNMENT
typedef dma_descriptor_align4_t crypto_dma_desc_t;
#endif /* (SOC_AES_GDMA) && (SOC_SHA_GDMA) */

Wyświetl plik

@ -28,6 +28,7 @@
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "sd_pwr_ctrl.h"
#include "esp_dma_utils.h"
#ifdef __cplusplus
extern "C" {
@ -79,7 +80,7 @@ typedef struct {
uint32_t erase_size_au: 16; /*!< Erase size for the purpose of timeout calculation, in multiples of allocation unit */
uint32_t cur_bus_width: 2; /*!< SD current bus width */
uint32_t discard_support: 1; /*!< SD discard feature support */
uint32_t fule_support: 1; /*!< SD FULE (Full User Area Logical Erase) feature support */
uint32_t fule_support: 1; /*!< SD FILE (Full User Area Logical Erase) feature support */
uint32_t erase_timeout: 6; /*!< Timeout (in seconds) for erase of a single allocation unit */
uint32_t erase_offset: 2; /*!< Constant timeout offset (in seconds) for any erase operation */
uint32_t reserved: 20; /*!< reserved for future expansion */
@ -209,6 +210,7 @@ typedef struct {
esp_err_t (*set_input_delay)(int slot, sdmmc_delay_phase_t delay_phase); /*!< set input delay phase */
void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */
sd_pwr_ctrl_handle_t pwr_ctrl_handle; /*!< Power control handle */
esp_err_t (*get_dma_info)(int slot, esp_dma_mem_info_t *dma_mem_info); /*!< host function to dma memory information*/
} sdmmc_host_t;
/**

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -326,9 +326,11 @@ esp_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr)
{
size_t datalen = 8;
esp_err_t err = ESP_FAIL;
uint32_t *buf = NULL;
void *buf = NULL;
size_t actual_size = 0;
err = esp_dma_malloc(datalen, 0, (void *)&buf, &actual_size);
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
err = esp_dma_capable_malloc(datalen, &dma_mem_info, &buf, &actual_size);
if (err != ESP_OK) {
return err;
}
@ -401,7 +403,9 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
esp_err_t err = ESP_OK;
size_t block_size = card->csd.sector_size;
if (esp_dma_is_buffer_aligned(src, block_size * block_count, ESP_DMA_BUF_LOCATION_INTERNAL)) {
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (esp_dma_is_buffer_alignment_satisfied(src, block_size * block_count, dma_mem_info)) {
err = sdmmc_write_sectors_dma(card, src, start_block, block_count, block_size * block_count);
} else {
// SDMMC peripheral needs DMA-capable buffers. Split the write into
@ -409,7 +413,7 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
// DMA-capable buffer.
void *tmp_buf = NULL;
size_t actual_size = 0;
err = esp_dma_malloc(block_size, 0, &tmp_buf, &actual_size);
err = esp_dma_capable_malloc(block_size, &dma_mem_info, &tmp_buf, &actual_size);
if (err != ESP_OK) {
return err;
}
@ -519,7 +523,9 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
esp_err_t err = ESP_OK;
size_t block_size = card->csd.sector_size;
if (esp_dma_is_buffer_aligned(dst, block_size * block_count, ESP_DMA_BUF_LOCATION_INTERNAL)) {
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (esp_dma_is_buffer_alignment_satisfied(dst, block_size * block_count, dma_mem_info)) {
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count);
} else {
// SDMMC peripheral needs DMA-capable buffers. Split the read into
@ -527,7 +533,7 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
// DMA-capable buffer.
void *tmp_buf = NULL;
size_t actual_size = 0;
err = esp_dma_malloc(block_size, 0, &tmp_buf, &actual_size);
err = esp_dma_capable_malloc(block_size, &dma_mem_info, &tmp_buf, &actual_size);
if (err != ESP_OK) {
return err;
}

Wyświetl plik

@ -340,7 +340,10 @@ esp_err_t sdmmc_allocate_aligned_buf(sdmmc_card_t* card)
if (card->host.flags & SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF) {
void* buf = NULL;
size_t actual_size = 0;
esp_err_t ret = esp_dma_malloc(SDMMC_IO_BLOCK_SIZE, 0, &buf, &actual_size);
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
esp_err_t ret = esp_dma_capable_malloc(SDMMC_IO_BLOCK_SIZE, &dma_mem_info, &buf, &actual_size);
if (ret != ESP_OK) {
return ret;
}

Wyświetl plik

@ -277,7 +277,9 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func,
.blklen = SDMMC_IO_BLOCK_SIZE /* TODO: read max block size from CIS */
};
if (unlikely(datalen > 0 && !esp_dma_is_buffer_aligned(datap, buflen, ESP_DMA_BUF_LOCATION_AUTO))) {
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (unlikely(datalen > 0 && !esp_dma_is_buffer_alignment_satisfied(datap, buflen, dma_mem_info))) {
if (datalen > SDMMC_IO_BLOCK_SIZE || card->host.dma_aligned_buffer == NULL) {
// User gives unaligned buffer while `SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF` not set.
return ESP_ERR_INVALID_ARG;
@ -300,7 +302,7 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func,
return ESP_ERR_INVALID_SIZE;
}
if (datalen == SDMMC_IO_BLOCK_SIZE) {
count = 0; // See 5.3.1 SDIO simplifed spec
count = 0; // See 5.3.1 SDIO simplified spec
} else {
count = datalen;
}
@ -386,7 +388,9 @@ esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function,
esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
uint32_t addr, void* dst, size_t size)
{
if (unlikely(!esp_dma_is_buffer_aligned(dst, size, ESP_DMA_BUF_LOCATION_INTERNAL))) {
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (unlikely(!esp_dma_is_buffer_alignment_satisfied(dst, size, dma_mem_info))) {
return ESP_ERR_INVALID_ARG;
}
return sdmmc_io_rw_extended(card, function, addr,
@ -397,7 +401,9 @@ esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function,
esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function,
uint32_t addr, const void* src, size_t size)
{
if (unlikely(!esp_dma_is_buffer_aligned(src, size, ESP_DMA_BUF_LOCATION_INTERNAL))) {
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
if (unlikely(!esp_dma_is_buffer_alignment_satisfied(src, size, dma_mem_info))) {
return ESP_ERR_INVALID_ARG;
}
return sdmmc_io_rw_extended(card, function, addr,

Wyświetl plik

@ -28,7 +28,9 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
esp_err_t err = ESP_OK;
uint8_t* ext_csd = NULL;
size_t actual_size = 0;
err = esp_dma_malloc(EXT_CSD_MMC_SIZE, 0, (void *)&ext_csd, &actual_size);
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
return err;
@ -255,7 +257,9 @@ esp_err_t sdmmc_init_mmc_check_ext_csd(sdmmc_card_t* card)
/* ensure EXT_CSD buffer is available before starting any SD-card operation */
uint8_t* ext_csd = NULL;
size_t actual_size = 0;
esp_err_t err = esp_dma_malloc(EXT_CSD_MMC_SIZE, 0, (void *)&ext_csd, &actual_size);
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
esp_err_t err = esp_dma_capable_malloc(EXT_CSD_MMC_SIZE, &dma_mem_info, (void *)&ext_csd, &actual_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
return err;

Wyświetl plik

@ -91,7 +91,9 @@ esp_err_t sdmmc_init_sd_ssr(sdmmc_card_t* card)
*/
uint32_t* sd_ssr = NULL;
size_t actual_size = 0;
err = esp_dma_calloc(1, SD_SSR_SIZE, 0, (void *)&sd_ssr, &actual_size);
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
err = esp_dma_capable_calloc(1, SD_SSR_SIZE, &dma_mem_info, (void *)&sd_ssr, &actual_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: could not allocate sd_ssr", __func__);
return err;
@ -239,7 +241,9 @@ esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card)
size_t actual_size = 0;
sdmmc_switch_func_rsp_t *response = NULL;
esp_err_t err = esp_dma_malloc(sizeof(*response), 0, (void *)&response, &actual_size);
esp_dma_mem_info_t dma_mem_info;
card->host.get_dma_info(card->host.slot, &dma_mem_info);
esp_err_t err = esp_dma_capable_malloc(sizeof(*response), &dma_mem_info, (void *)&response, &actual_size);
assert(actual_size == sizeof(*response));
if (err != ESP_OK) {
return err;

Wyświetl plik

@ -161,7 +161,7 @@ typedef volatile struct gdma_dev_s {
uint32_t reserved12 : 20;
};
uint32_t val;
} wight;
} weight;
uint32_t reserved_40;
union {
struct {
@ -321,7 +321,7 @@ typedef volatile struct gdma_dev_s {
uint32_t reserved12 : 20;
};
uint32_t val;
} wight;
} weight;
uint32_t reserved_a0;
union {
struct {

Wyświetl plik

@ -1040,11 +1040,18 @@ static void port_obj_free(port_t *port)
void *frame_list_alloc(size_t frame_list_len)
{
void *frame_list = heap_caps_aligned_calloc(USB_DWC_FRAME_LIST_MEM_ALIGN, frame_list_len, sizeof(uint32_t), MALLOC_CAP_DMA);
esp_err_t ret;
void *frame_list = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = USB_DWC_FRAME_LIST_MEM_ALIGN,
};
ret = esp_dma_capable_calloc(frame_list_len, sizeof(uint32_t), &dma_mem_info, &frame_list, &actual_size);
assert(ret == ESP_OK);
// Both Frame List start address and size should be already cache aligned so this is only a sanity check
if (frame_list) {
if (!esp_dma_is_buffer_aligned(frame_list, frame_list_len * sizeof(uint32_t), ESP_DMA_BUF_LOCATION_AUTO)) {
if (!esp_dma_is_buffer_alignment_satisfied(frame_list, actual_size, dma_mem_info)) {
// This should never happen
heap_caps_free(frame_list);
frame_list = NULL;
@ -1065,10 +1072,17 @@ void *transfer_descriptor_list_alloc(size_t list_len, size_t *list_len_bytes_out
*list_len_bytes_out = list_len * sizeof(usb_dwc_ll_dma_qtd_t);
#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void *qtd_list = heap_caps_aligned_calloc(USB_DWC_QTD_LIST_MEM_ALIGN, *list_len_bytes_out, 1, MALLOC_CAP_DMA);
esp_err_t ret;
void *qtd_list = NULL;
size_t actual_size = 0;
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = USB_DWC_QTD_LIST_MEM_ALIGN,
};
ret = esp_dma_capable_calloc(*list_len_bytes_out, 1, &dma_mem_info, &qtd_list, &actual_size);
assert(ret == ESP_OK);
if (qtd_list) {
if (!esp_dma_is_buffer_aligned(qtd_list, *list_len_bytes_out * sizeof(usb_dwc_ll_dma_qtd_t), ESP_DMA_BUF_LOCATION_AUTO)) {
if (!esp_dma_is_buffer_alignment_satisfied(qtd_list, actual_size, dma_mem_info)) {
// This should never happen
heap_caps_free(qtd_list);
qtd_list = NULL;

Wyświetl plik

@ -266,8 +266,10 @@ urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size)
urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT);
void *data_buffer;
size_t real_size;
esp_dma_malloc(data_buffer_size, 0, &data_buffer, &real_size);
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = 4,
};
esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size);
TEST_ASSERT_NOT_NULL_MESSAGE(urb, "Failed to allocate URB");
TEST_ASSERT_NOT_NULL_MESSAGE(data_buffer, "Failed to allocate transfer buffer");

Wyświetl plik

@ -14,7 +14,11 @@ urb_t *urb_alloc(size_t data_buffer_size, int num_isoc_packets)
urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT);
void *data_buffer;
size_t real_size;
esp_dma_malloc(data_buffer_size, 0, &data_buffer, &real_size);
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = 4,
};
//TODO: IDF-9639
esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size);
if (urb == NULL || data_buffer == NULL) {
goto err;
}

Wyświetl plik

@ -106,8 +106,8 @@ Memory Allocation Helper
cache memory synchronization is usually considered when DMA is involved. ESP-IDF provides an API to do memory allocation that can meet the alignment requirement from both the cache and the DMA.
- :cpp:func:`esp_dma_malloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA.
- :cpp:func:`esp_dma_calloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. The initialized value in the memory is set to zero.
- :cpp:func:`esp_dma_capable_malloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA.
- :cpp:func:`esp_dma_capable_calloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. The initialized value in the memory is set to zero.
You can also use :c:macro:`ESP_DMA_MALLOC_FLAG_PSRAM` to allocate from the PSRAM.

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
@ -447,12 +447,16 @@ void app_main(void)
// it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
lv_color_t *buf1 = NULL;
lv_color_t *buf2 = NULL;
uint32_t malloc_flags = 0;
esp_dma_mem_info_t dma_mem_info = {
.dma_alignment_bytes = 4,
#if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
malloc_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
.extra_heap_caps = MALLOC_CAP_SPIRAM,
#else
.extra_heap_caps = MALLOC_CAP_INTERNAL,
#endif // CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM
ESP_ERROR_CHECK(esp_dma_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), malloc_flags, (void *)&buf1, NULL));
ESP_ERROR_CHECK(esp_dma_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), malloc_flags, (void *)&buf2, NULL));
};
ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf1, NULL));
ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf2, NULL));
assert(buf1);
assert(buf2);
ESP_LOGI(TAG, "buf1@%p, buf2@%p", buf1, buf2);