Merge branch 'fix/fix_gdma_crc_stuck_with_large_input' into 'master'

fix(gdma): fix crc stuck with large input

Closes IDF-15738

See merge request espressif/esp-idf!49163
This commit is contained in:
Chen Ji Chang
2026-06-05 16:30:34 +08:00
4 changed files with 145 additions and 48 deletions

View File

@@ -60,6 +60,9 @@ typedef struct {
/**
* @brief Install async CRC driver, with AHB-GDMA as the backend
*
* @note The GDMA backend reserves one M2M trigger ID and one paired TX/RX GDMA channel.
* TX feeds the CRC calculator, while RX drains the M2M data path.
*
* @param[in] config Configuration of async CRC
* @param[out] crc_hdl Returned driver handle
* @return
@@ -75,6 +78,9 @@ esp_err_t esp_async_crc_install_gdma_ahb(const async_crc_config_t *config, async
/**
* @brief Install async CRC driver, with AXI-GDMA as the backend
*
* @note The GDMA backend reserves one M2M trigger ID and one paired TX/RX GDMA channel.
* TX feeds the CRC calculator, while RX drains the M2M data path.
*
* @param[in] config Configuration of async CRC
* @param[out] crc_hdl Returned driver handle
* @return

View File

@@ -20,6 +20,7 @@
ESP_LOG_ATTR_TAG(TAG, "async_crc_gdma");
#define CRC_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095
#define CRC_DMA_RX_SINK_BUFFER_SIZE 32
__attribute__((always_inline))
static inline uint32_t bit_reverse32(uint32_t val)
@@ -34,7 +35,7 @@ static inline uint32_t bit_reverse32(uint32_t val)
/// @brief Transaction object for async CRC
typedef struct async_crc_transaction {
gdma_link_list_handle_t link_list; // DMA link list for user buffer
gdma_link_list_handle_t tx_link_list; // DMA link list for user buffer
const void *data; // User data buffer pointer
size_t size; // Size of data buffer
async_crc_params_t params; // CRC parameters (polynomial, init value, etc.)
@@ -47,10 +48,13 @@ typedef struct async_crc_transaction {
typedef struct {
async_crc_context_t parent; // Parent IO interface
gdma_channel_handle_t tx_channel; // GDMA TX channel handle
gdma_channel_handle_t rx_channel; // GDMA RX channel handle used to drain M2M data
portMUX_TYPE spin_lock; // Spinlock for synchronization
_Atomic async_crc_fsm_t fsm; // driver state machine, changing state should be atomic
size_t tx_int_mem_alignment; // Required DMA buffer alignment for internal TX memory
size_t tx_ext_mem_alignment; // Required DMA buffer alignment for external TX memory
uint8_t *rx_sink_buffer; // Sink buffer used to drain the M2M RX path
gdma_link_list_handle_t rx_link_list; // Self-loop DMA link list for the RX sink buffer, shared by all crc transactions
uint32_t gdma_bus_id; // GDMA bus id (AHB, AXI, etc.)
uint32_t num_trans_objs; // number of transaction objects
async_crc_transaction_t *transaction_pool; // transaction object pool
@@ -77,17 +81,25 @@ static esp_err_t async_crc_gdma_destroy_context(async_crc_gdma_context_t *crc_gd
if (crc_gdma->transaction_pool) {
for (uint32_t i = 0; i < crc_gdma->num_trans_objs; i++) {
async_crc_transaction_t* trans = &crc_gdma->transaction_pool[i];
if (trans->link_list) {
gdma_del_link_list(trans->link_list);
if (trans->tx_link_list) {
gdma_del_link_list(trans->tx_link_list);
}
}
free(crc_gdma->transaction_pool);
}
// Delete GDMA channel
if (crc_gdma->rx_link_list) {
gdma_del_link_list(crc_gdma->rx_link_list);
}
free(crc_gdma->rx_sink_buffer);
// Delete GDMA channels
if (crc_gdma->tx_channel) {
gdma_disconnect(crc_gdma->tx_channel);
gdma_del_channel(crc_gdma->tx_channel);
}
if (crc_gdma->rx_channel) {
gdma_disconnect(crc_gdma->rx_channel);
gdma_del_channel(crc_gdma->rx_channel);
}
free(crc_gdma);
return ESP_OK;
}
@@ -113,39 +125,76 @@ esp_err_t esp_async_crc_install_gdma_template(const async_crc_config_t *config,
crc_gdma->transaction_pool = heap_caps_calloc(trans_queue_len, sizeof(async_crc_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE(crc_gdma->transaction_pool, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction pool");
// Create TX channel for CRC calculation with optimized allocation strategy
// Create a paired M2M channel. TX feeds the CRC calculator and RX drains the data path.
gdma_channel_alloc_config_t dma_chan_alloc_cfg = {
.intr_priority = config->intr_priority,
};
ESP_GOTO_ON_ERROR(new_channel_func(&dma_chan_alloc_cfg, &crc_gdma->tx_channel, NULL),
ESP_GOTO_ON_ERROR(new_channel_func(&dma_chan_alloc_cfg, &crc_gdma->tx_channel, &crc_gdma->rx_channel),
err, TAG, "alloc DMA channel failed");
gdma_reset(crc_gdma->tx_channel);
gdma_reset(crc_gdma->rx_channel);
// get a free DMA trigger ID for CRC calculation, and connect it to the allocated channel
gdma_trigger_t m2m_trigger = {
.bus_id = gdma_bus_id,
};
gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0);
uint32_t free_m2m_id_mask = 0;
gdma_get_free_m2m_trig_id_mask(crc_gdma->tx_channel, &free_m2m_id_mask);
m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask);
ESP_GOTO_ON_ERROR(gdma_connect(crc_gdma->tx_channel, m2m_trigger), err, TAG, "connect DMA channel failed");
ESP_GOTO_ON_ERROR(gdma_connect(crc_gdma->tx_channel, m2m_trigger), err, TAG, "connect TX DMA channel failed");
ESP_GOTO_ON_ERROR(gdma_connect(crc_gdma->rx_channel, m2m_trigger), err, TAG, "connect RX DMA channel failed");
gdma_strategy_config_t strategy_cfg = {
gdma_strategy_config_t tx_strategy_cfg = {
.owner_check = true,
.auto_update_desc = true,
.eof_till_data_popped = false,
.eof_till_data_popped = true,
};
gdma_apply_strategy(crc_gdma->tx_channel, &strategy_cfg);
gdma_apply_strategy(crc_gdma->tx_channel, &tx_strategy_cfg);
gdma_strategy_config_t rx_strategy_cfg = {
// The RX sink uses a single self-loop descriptor, whose owner bit is
// overwritten by hardware after each received block.
.owner_check = false,
};
gdma_apply_strategy(crc_gdma->rx_channel, &rx_strategy_cfg);
// Configure DMA transfer
gdma_transfer_config_t transfer_cfg = {
.max_data_burst_size = config->dma_burst_size,
.access_ext_mem = true, // allow to copy data from external memory
};
ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->tx_channel, &transfer_cfg), err, TAG, "config DMA transfer failed");
ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->tx_channel, &transfer_cfg), err, TAG, "config TX DMA transfer failed");
ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->rx_channel, &transfer_cfg), err, TAG, "config RX DMA transfer failed");
// Get buffer alignment required by GDMA channel
gdma_get_alignment_constraints(crc_gdma->tx_channel, &crc_gdma->tx_int_mem_alignment, &crc_gdma->tx_ext_mem_alignment);
size_t rx_int_mem_alignment = 0;
gdma_get_alignment_constraints(crc_gdma->rx_channel, &rx_int_mem_alignment, NULL);
size_t rx_buffer_size = (rx_int_mem_alignment > CRC_DMA_RX_SINK_BUFFER_SIZE) ?
rx_int_mem_alignment : CRC_DMA_RX_SINK_BUFFER_SIZE;
crc_gdma->rx_sink_buffer = heap_caps_aligned_calloc(rx_int_mem_alignment, 1, rx_buffer_size,
MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE(crc_gdma->rx_sink_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for RX sink buffer");
size_t item_alignment = (gdma_bus_id == SOC_GDMA_BUS_AXI) ? GDMA_LL_AXI_DESC_ALIGNMENT : GDMA_LL_AHB_DESC_ALIGNMENT;
// The RX side only drains the M2M stream for the TX CRC calculator. A single
// self-loop descriptor is enough because the sink buffer contents are ignored.
gdma_link_list_config_t rx_link_cfg = {
.item_alignment = item_alignment,
.num_items = 1,
.flags = {
.items_in_ext_mem = false,
},
};
ESP_GOTO_ON_ERROR(gdma_new_link_list(&rx_link_cfg, &crc_gdma->rx_link_list), err, TAG, "failed to create RX DMA link list");
gdma_buffer_mount_config_t rx_buf_mount_config = {
.buffer = crc_gdma->rx_sink_buffer,
.buffer_alignment = rx_int_mem_alignment,
.length = rx_buffer_size,
.flags = {
.mark_final = GDMA_FINAL_LINK_TO_HEAD,
},
};
ESP_GOTO_ON_ERROR(gdma_link_mount_buffers(crc_gdma->rx_link_list, 0, &rx_buf_mount_config, 1, NULL),
err, TAG, "failed to mount RX sink buffer to DMA link list");
// Register EOF callback for completion detection
gdma_tx_event_callbacks_t cbs = {
@@ -239,12 +288,14 @@ static void try_start_pending_transaction(async_crc_gdma_context_t *crc_gdma)
// crc config validation is done in the async_crc_prepare_transaction
// so no need to check the return value here
gdma_config_crc_calculator(crc_gdma->tx_channel, &crc_cfg);
gdma_reset(crc_gdma->rx_channel);
gdma_reset(crc_gdma->tx_channel);
atomic_store(&crc_gdma->fsm, CRC_FSM_RUN);
crc_gdma->current_transaction = trans;
// Start DMA operation for CRC calculation
gdma_start(crc_gdma->tx_channel, gdma_link_get_head_addr(trans->link_list));
// Start RX first so the M2M data path has a sink before TX feeds the CRC calculator.
gdma_start(crc_gdma->rx_channel, gdma_link_get_head_addr(crc_gdma->rx_link_list));
gdma_start(crc_gdma->tx_channel, gdma_link_get_head_addr(trans->tx_link_list));
return;
}
@@ -281,7 +332,7 @@ static esp_err_t async_crc_prepare_transaction(async_crc_gdma_context_t *crc_gdm
"Data buffer not aligned to %zu bytes", buffer_alignment);
// Calculate number of DMA nodes needed
size_t num_dma_nodes = esp_dma_calculate_node_count(trans->size, buffer_alignment, CRC_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
size_t tx_num_dma_nodes = esp_dma_calculate_node_count(trans->size, buffer_alignment, CRC_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
// Get descriptor alignment based on GDMA bus type
size_t item_alignment = (crc_gdma->gdma_bus_id == SOC_GDMA_BUS_AXI) ? GDMA_LL_AXI_DESC_ALIGNMENT : GDMA_LL_AHB_DESC_ALIGNMENT;
@@ -289,13 +340,13 @@ static esp_err_t async_crc_prepare_transaction(async_crc_gdma_context_t *crc_gdm
// Create DMA link list for the buffer
gdma_link_list_config_t link_cfg = {
.item_alignment = item_alignment,
.num_items = num_dma_nodes,
.num_items = tx_num_dma_nodes,
.flags = {
.check_owner = true,
.items_in_ext_mem = false,
},
};
ESP_RETURN_ON_ERROR(gdma_new_link_list(&link_cfg, &trans->link_list), TAG, "failed to create DMA link list");
ESP_RETURN_ON_ERROR(gdma_new_link_list(&link_cfg, &trans->tx_link_list), TAG, "failed to create TX DMA link list");
// Mount the user buffer to the DMA link list
gdma_buffer_mount_config_t buf_mount_config[1] = {
@@ -309,7 +360,7 @@ static esp_err_t async_crc_prepare_transaction(async_crc_gdma_context_t *crc_gdm
}
}
};
ESP_RETURN_ON_ERROR(gdma_link_mount_buffers(trans->link_list, 0, buf_mount_config, 1, NULL), TAG, "failed to mount buffer to DMA link list");
ESP_RETURN_ON_ERROR(gdma_link_mount_buffers(trans->tx_link_list, 0, buf_mount_config, 1, NULL), TAG, "failed to mount buffer to DMA link list");
// write back the source data if it's behind the cache
size_t cache_line_size = esp_cache_get_line_size_by_addr(trans->data);
@@ -333,6 +384,8 @@ static bool async_crc_gdma_eof_callback(gdma_channel_handle_t dma_chan, gdma_eve
// Capture to local var before CAS in case user clears crc_gdma->current_transaction
async_crc_transaction_t *current_trans = crc_gdma->current_transaction;
gdma_stop(crc_gdma->rx_channel);
// Get CRC result from DMA peripheral
uint32_t crc_result;
gdma_crc_get_result(crc_gdma->tx_channel, &crc_result);
@@ -405,9 +458,9 @@ static esp_err_t async_crc_gdma_calc(async_crc_context_t *ctx, const void *data,
ESP_RETURN_ON_FALSE(trans, ESP_ERR_INVALID_STATE, TAG, "no free node in the idle queue");
// clean up the transaction configuration comes from the last one
if (trans->link_list) {
gdma_del_link_list(trans->link_list);
trans->link_list = NULL;
if (trans->tx_link_list) {
gdma_del_link_list(trans->tx_link_list);
trans->tx_link_list = NULL;
}
// Store transaction data

View File

@@ -31,14 +31,14 @@ typedef struct {
static void test_async_crc_various_poly(async_crc_handle_t driver)
{
static const char test_input_string[] __attribute__((aligned(16))) = "GDMACRC::TEST::X";
static const char test_input_string[] __attribute__((aligned(16))) = "GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::END!";
// CRC online: https://www.lddgo.net/en/encrypt/crc
static test_crc_case_t crc_test_cases[] = {
{
.crc_bit_width = 8,
.init_value = 0x00,
.poly_hex = 0x07,
.expected_result = 0x1C,
.expected_result = 0x08,
},
{
.crc_bit_width = 8,
@@ -47,13 +47,13 @@ static void test_async_crc_various_poly(async_crc_handle_t driver)
.reverse_data_mask = true,
.reverse_result = true,
.final_xor = 0x1F,
.expected_result = 0xC8,
.expected_result = 0x1F,
},
{
.crc_bit_width = 16,
.init_value = 0xFFFF,
.poly_hex = 0x1021,
.expected_result = 0x7563,
.expected_result = 0x0ED7,
},
{
.crc_bit_width = 16,
@@ -62,7 +62,7 @@ static void test_async_crc_various_poly(async_crc_handle_t driver)
.reverse_data_mask = true,
.reverse_result = true,
.final_xor = 0xABCD,
.expected_result = 0xD5B9,
.expected_result = 0x055C,
}
};
uint32_t result = 0;
@@ -128,7 +128,7 @@ static bool test_async_crc_result_cb(async_crc_handle_t crc_hdl, async_crc_event
static void test_async_crc_calc_with_callback(async_crc_handle_t driver)
{
static const char test_input_string[] __attribute__((aligned(16))) = "GDMACRC::TEST::X";
static const char test_input_string[] __attribute__((aligned(16))) = "GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::END!";
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
crc_async_user_context_t user_ctx = {
.sem = sem,
@@ -143,8 +143,8 @@ static void test_async_crc_calc_with_callback(async_crc_handle_t driver)
TEST_ESP_OK(esp_async_crc_calc(driver, test_input_string, strlen(test_input_string), &params, test_async_crc_result_cb, &user_ctx));
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(100)));
printf("CRC Result: 0x%"PRIx32", Expected: 0xE69A\r\n", user_ctx.crc_result);
TEST_ASSERT_EQUAL(0xE69A, user_ctx.crc_result);
printf("CRC Result: 0x%"PRIx32", Expected: 0x4372\r\n", user_ctx.crc_result);
TEST_ASSERT_EQUAL(0x4372, user_ctx.crc_result);
vSemaphoreDelete(sem);
}
@@ -172,7 +172,7 @@ TEST_CASE("async_crc calculation with callback", "[async_crc]")
static void test_async_crc_multiple_requests(async_crc_handle_t driver)
{
static const char test_input_string[] __attribute__((aligned(16))) = "GDMACRC::TEST::X";
static const char test_input_string[] __attribute__((aligned(16))) = "GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::END!";
SemaphoreHandle_t sem = xSemaphoreCreateCounting(TEST_ASYNC_CRC_BENCH_COUNTS, 0);
crc_async_user_context_t user_ctx = {
.sem = sem,
@@ -192,7 +192,7 @@ static void test_async_crc_multiple_requests(async_crc_handle_t driver)
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(100)));
}
printf("CRC Result of request 0x%"PRIx32"\r\n", user_ctx.crc_result);
TEST_ASSERT_EQUAL(0x069A43E6, user_ctx.crc_result);
TEST_ASSERT_EQUAL(0x6D9BD7D5, user_ctx.crc_result);
vSemaphoreDelete(sem);
};

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -33,33 +33,43 @@ static test_crc_case_t crc_test_cases[] = {
.crc_bit_width = 8,
.init_value = 0x00,
.poly_hex = 0x07,
.expected_result = 0x1C,
.expected_result = 0x08,
},
[1] = {
.crc_bit_width = 8,
.init_value = 0x00,
.poly_hex = 0x07,
.reverse_data_mask = true, // refin = true
.expected_result = 0xB9,
.expected_result = 0xCE,
},
// CRC16, x^16+x^12+x^5+1
[2] = {
.crc_bit_width = 16,
.init_value = 0xFFFF,
.poly_hex = 0x1021,
.expected_result = 0x7563,
.expected_result = 0x0ED7,
},
// CRC32, x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
[3] = {
.crc_bit_width = 32,
.init_value = 0xFFFFFFFF,
.poly_hex = 0x04C11DB7,
.expected_result = 0x069A43E6,
.expected_result = 0x6D9BD7D5,
}
};
static bool test_gdma_crc_calculation_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
BaseType_t high_task_wakeup = pdFALSE;
SemaphoreHandle_t semaphore = (SemaphoreHandle_t)user_data;
if (event_data->flags.normal_eof) {
xSemaphoreGiveFromISR(semaphore, &high_task_wakeup);
}
return high_task_wakeup;
}
// CRC online: https://www.lddgo.net/en/encrypt/crc
static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_num_crc_algorithm)
static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, gdma_channel_handle_t rx_chan, int test_num_crc_algorithm)
{
// Note, burst size should be at least 16 when accessing encrypted external memory
gdma_transfer_config_t transfer_cfg = {
@@ -67,30 +77,41 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu
.access_ext_mem = true,
};
TEST_ESP_OK(gdma_config_transfer(tx_chan, &transfer_cfg));
TEST_ESP_OK(gdma_config_transfer(rx_chan, &transfer_cfg));
SemaphoreHandle_t semaphore = xSemaphoreCreateBinary();
uint32_t crc_result = 0;
static const char test_input_string[] __attribute__((aligned(SOC_MEMSPI_ENCRYPTION_ALIGNMENT))) = "GDMACRC::TEST::X";
static const char test_input_string[] __attribute__((aligned(SOC_MEMSPI_ENCRYPTION_ALIGNMENT))) = "GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::GDMACRC::TEST::LONGSTRING::REPEAT::END!";
size_t input_data_size = strlen(test_input_string);
TEST_ASSERT_EQUAL((uintptr_t)test_input_string % SOC_MEMSPI_ENCRYPTION_ALIGNMENT, 0);
// this test case also test the GDMA can fetch data from MSPI Flash
TEST_ASSERT_TRUE(esp_ptr_in_drom(test_input_string));
printf("Calculate CRC value for string: \"%s\"\r\n", test_input_string);
uint8_t *rx_buffer = NULL;
rx_buffer = heap_caps_calloc(1, strlen(test_input_string), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(rx_buffer);
gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0);
// get a free DMA trigger ID
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_tx_event_callbacks_t tx_cbs = {
.on_trans_eof = test_gdma_crc_calculation_callback,
};
TEST_ESP_OK(gdma_register_tx_event_callbacks(tx_chan, &tx_cbs, semaphore));
size_t sram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
size_t alignment = MAX(sram_cache_line_size, 8);
dma_descriptor_align8_t *tx_descs = heap_caps_aligned_calloc(alignment, 1, sizeof(dma_descriptor_align8_t),
MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(tx_descs);
tx_descs->buffer = (void *)test_input_string;
tx_descs->dw0.size = input_data_size + 1; // +1 for '\0'
tx_descs->dw0.length = input_data_size;
@@ -98,9 +119,18 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu
tx_descs->dw0.suc_eof = 1;
tx_descs->next = NULL;
dma_descriptor_align8_t *rx_descs = heap_caps_aligned_calloc(alignment, 1, sizeof(dma_descriptor_align8_t),
MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(rx_descs);
rx_descs->buffer = (void *)rx_buffer;
rx_descs->dw0.size = input_data_size;
rx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
rx_descs->next = NULL;
if (sram_cache_line_size) {
// do write-back for the buffer because it's in the cache
TEST_ESP_OK(esp_cache_msync((void *)tx_descs, sizeof(dma_descriptor_align8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED));
TEST_ESP_OK(esp_cache_msync((void *)rx_descs, sizeof(dma_descriptor_align8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED));
}
for (int i = 0; i < test_num_crc_algorithm; i++) {
@@ -111,34 +141,42 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu
.reverse_data_mask = crc_test_cases[i].reverse_data_mask,
};
TEST_ESP_OK(gdma_config_crc_calculator(tx_chan, &crc_config));
TEST_ESP_OK(gdma_reset(rx_chan));
TEST_ESP_OK(gdma_start(rx_chan, (intptr_t)rx_descs));
TEST_ESP_OK(gdma_reset(tx_chan));
TEST_ESP_OK(gdma_start(tx_chan, (intptr_t)tx_descs));
// simply wait for the transfer done
vTaskDelay(pdMS_TO_TICKS(100));
// wait for the transfer done
xSemaphoreTake(semaphore, pdMS_TO_TICKS(100));
TEST_ESP_OK(gdma_crc_get_result(tx_chan, &crc_result));
printf("CRC Result: 0x%"PRIx32"\r\n", crc_result);
TEST_ASSERT_EQUAL(crc_test_cases[i].expected_result, crc_result);
}
free(tx_descs);
free(rx_descs);
free(rx_buffer);
vSemaphoreDelete(semaphore);
}
TEST_CASE("GDMA CRC Calculation", "[GDMA][CRC]")
{
gdma_channel_handle_t tx_chan = NULL;
gdma_channel_handle_t rx_chan = NULL;
gdma_channel_alloc_config_t tx_chan_alloc_config = {
};
#if SOC_HAS(AHB_GDMA)
printf("Test CRC calculation for AHB GDMA\r\n");
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan, NULL));
test_gdma_crc_calculation(tx_chan, 4);
TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan, &rx_chan));
test_gdma_crc_calculation(tx_chan, rx_chan, 4);
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif // SOC_HAS(AHB_GDMA)
#if SOC_HAS(AXI_GDMA)
printf("Test CRC calculation for AXI GDMA\r\n");
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan, NULL));
test_gdma_crc_calculation(tx_chan, 3);
TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan, &rx_chan));
test_gdma_crc_calculation(tx_chan, rx_chan, 3);
TEST_ESP_OK(gdma_del_channel(tx_chan));
TEST_ESP_OK(gdma_del_channel(rx_chan));
#endif // SOC_HAS(AXI_GDMA)
}