异步 CRC (Async CRC)
本文档介绍了 ESP-IDF 中异步 CRC (Async CRC) 驱动程序的功能。目录如下:
概述
异步 CRC 驱动程序提供使用通用 DMA 外设的硬件加速 CRC 计算。它支持 AHB-GDMA 和 AXI-GDMA 后端,提供灵活的 CRC 计算,支持可配置的多项式、初始值、位反转选项和最终 XOR 处理。
主要功能包括:
使用通用 DMA 进行硬件加速的 CRC 计算
支持 8 位、16 位和 32 位 CRC 算法
带回调通知的异步 API
支持超时的阻塞 API
支持可配置积压大小的请求队列
支持 AHB 和 AXI DMA 后端
应用场景包括:
通信协议的数据完整性验证
文件和固件校验和计算
网络数据包验证
存储数据验证
快速开始
本节简要介绍如何使用异步 CRC 驱动程序。通过实际示例,演示如何初始化驱动程序、配置 CRC 参数以及执行异步和阻塞 CRC 计算。
异步 CRC 的典型使用流程如下:
异步 CRC 驱动程序的一般使用流程(点击放大)
创建和安装驱动程序
首先,您需要安装异步 CRC 驱动程序。该驱动程序根据芯片的功能支持 AHB-GDMA 和 AXI-GDMA 后端:
async_crc_handle_t crc_hdl = NULL;
async_crc_config_t config = {
.backlog = 8, // 队列中最大挂起请求数
.dma_burst_size = 16, // DMA 突发传输大小(字节)
};
// 使用 AHB-GDMA 后端安装(如果可用)
ESP_ERROR_CHECK(esp_async_crc_install_gdma_ahb(&config, &crc_hdl));
// 或使用 AXI-GDMA 后端安装(如果可用)
// ESP_ERROR_CHECK(esp_async_crc_install_gdma_axi(&config, &crc_hdl));
备注
选择 AHB-GDMA 和 AXI-GDMA 后端
后端选择取决于芯片的功能和性能要求:
AHB-GDMA:大多数 ESP 芯片均可使用。连接到 AHB 总线,适用于通用 DMA 操作。最适合:
标准性能要求
大多数 ESP 芯片变体的兼容性
AXI-GDMA:在支持 AXI 总线的高端 ESP 芯片上可用。为内存密集型操作提供更高的带宽和更好的性能。最适合:
高吞吐量 CRC 计算
处理大量数据
需要最大性能的应用
更高效地访问外部存储器(PSRAM)
创建驱动程序实例时,您需要配置:
backlog:可排队等待的最大 CRC 请求数。较高的值使用更多内存,但在突发工作负载下提供更好的吞吐量。
dma_burst_size:DMA 传输突发大小(字节)。
驱动程序句柄 crc_hdl 是一个不透明指针,用于所有后续操作。
执行异步 CRC 计算
异步 API 允许您在不阻塞的情况下排队 CRC 计算:
static bool crc_complete_callback(async_crc_handle_t crc_hdl, async_crc_event_data_t *edata, void *cb_args)
{
uint32_t result = edata->crc_result;
// 进一步处理 CRC 结果
// 例如,发送到任务队列,记录日志等。
return false;
}
// 配置 CRC-32 的 CRC 参数
async_crc_params_t params = {
.width = 32,
.polynomial = 0x04C11DB7,
.init_value = 0xFFFFFFFF,
.final_xor_value = 0xFFFFFFFF,
.reverse_input = true,
.reverse_output = true,
};
// 启动异步 CRC 计算
const char *data = "Hello, World!";
size_t data_len = strlen(data);
ESP_ERROR_CHECK(esp_async_crc_calc(crc_hdl, data, data_len, ¶ms, crc_complete_callback, NULL));
CRC 计算完成时会在中断上下文中调用回调函数。回调接收:
crc_hdl:驱动程序句柄
edata:包含 CRC 结果的事件数据
cb_args:在
esp_async_crc_calc期间传递的用户定义参数
执行阻塞 CRC 计算
对于更简单的使用场景或不需要异步操作的情况,请使用阻塞 API:
uint32_t crc_result = 0;
async_crc_params_t params = {
.width = 32,
.polynomial = 0x04C11DB7,
.init_value = 0xFFFFFFFF,
.final_xor_value = 0xFFFFFFFF,
.reverse_input = true,
.reverse_output = true,
};
const char *data = "Hello, World!";
size_t data_len = strlen(data);
// 阻塞 CRC,1000ms 超时
ESP_ERROR_CHECK(esp_crc_calc_blocking(crc_hdl, data, data_len, ¶ms, 1000, &crc_result));
printf("CRC 结果: 0x%08X\n", crc_result);
阻塞 API 支持:
timeout_ms >= 0:等待指定的毫秒数
timeout_ms < 0:无限期等待
卸载驱动程序
当不再需要驱动程序时:
ESP_ERROR_CHECK(esp_async_crc_uninstall(crc_hdl));
如果存在挂起的操作或 CRC 引擎正忙,卸载函数将返回 ESP_ERR_INVALID_STATE。请在卸载前确保所有操作已完成。
CRC 参数配置
异步 CRC 驱动程序通过 async_crc_params_t 结构支持灵活的 CRC 算法配置。
CRC 宽度
async_crc_params_t::width 字段指定 CRC 位宽度:
8:8 位 CRC(如 CRC-8、CRC-8/MAXIM)
16:16 位 CRC(如 CRC-16/CCITT、CRC-16/IBM)
32:32 位 CRC(如 CRC-32、CRC-32/BZIP2)
多项式
async_crc_params_t::polynomial 字段以十六进制格式指定 CRC 多项式。常见的多项式值包括:
CRC-32:
0x04C11DB7CRC-16/CCITT:
0x1021CRC-16/IBM:
0x8005CRC-8/MAXIM:
0x31
初始值
async_crc_params_t::init_value 字段设置处理前的初始 CRC 值。常见的初始值:
0xFFFFFFFF用于 CRC-320x0000用于许多 CRC-16 变体0x00用于许多 CRC-8 变体
最终 XOR 值
async_crc_params_t::final_xor_value 字段指定在与最终 CRC 结果进行异或之前的值。这通常是 CRC-32 的 0xFFFFFFFF,但对于某些变体可以是 0x0000。
位反转选项
async_crc_params_t::reverse_input如果为 true,在处理前反转每个输入字节的位顺序async_crc_params_t::reverse_output如果为 true,在应用最终 XOR 之前反转最终 CRC 结果的位顺序
这些选项影响不同 CRC 算法的反射设置。
常见 CRC 配置
下表列出了常见的 CRC 配置:
CRC 算法 |
位宽 |
多项式 |
初始值 |
最终 XOR 值 |
反转输入 |
反转输出 |
|---|---|---|---|---|---|---|
CRC-32 |
32 |
0x04C11DB7 |
0xFFFFFFFF |
0xFFFFFFFF |
true |
true |
CRC-16/CCITT |
16 |
0x1021 |
0x0000 |
0x0000 |
false |
false |
CRC-16/IBM |
16 |
0x8005 |
0x0000 |
0x0000 |
true |
true |
CRC-8/MAXIM |
8 |
0x31 |
0x00 |
0x00 |
true |
true |
线程安全
异步 CRC 驱动程序设计为线程安全的,可以从多个任务中使用。该驱动程序采用 无竞争有限状态机(FSM) 架构,确保线程安全并正确处理并发 CRC 请求。
线程安全保证
所有公共 API 可以同时从不同任务调用
驱动程序对内部状态使用原子操作和临界区保护
请求队列确保并发调用被正确串行化
ISR 上下文限制
异步 API 和阻塞 API 都不能从中断上下文调用。具体来说:
esp_async_crc_calc():涉及内存分配/释放、DMA 准备工作和非 ISR 安全的日志函数esp_crc_calc_blocking():使用可能阻塞的同步原语
回调限制
回调函数(async_crc_isr_cb_t)在中断上下文中执行。因此:
不要执行阻塞操作(如
vTaskDelay、带超时的xQueueSend)保持执行时间最小化,以免影响系统中断延迟
不要使用
malloc或类似函数分配内存只使用 ISR 安全的 FreeRTOS API(如
xQueueSendFromISR,xSemaphoreGiveFromISR)如果回调唤醒了高优先级任务,返回
true
使用队列的回调示例:
static bool crc_callback(async_crc_handle_t crc_hdl, async_crc_event_data_t *edata, void *cb_args)
{
QueueHandle_t queue = (QueueHandle_t)cb_args;
BaseType_t high_task_awoken = pdFALSE;
// 通过 ISR 安全队列将结果发送到任务
xQueueSendFromISR(queue, &edata->crc_result, &high_task_awoken);
return high_task_awoken == pdTRUE;
}
缓冲区要求
异步 CRC 驱动程序对数据缓冲区有特定要求。
内存类型
数据缓冲区可以来自内部存储区域(DRAM/IRAM)或外部存储区域(PSRAM, Flash)中。驱动程序自动处理两者:
// 内部 RAM
static char internal_data[] = "Data in internal RAM";
esp_async_crc_calc(crc_hdl, internal_data, strlen(internal_data), ¶ms, callback, NULL);
// 外部 Flash
static const char *flash_data = "Data in external Flash";
esp_async_crc_calc(crc_hdl, flash_data, strlen(flash_data), ¶ms, callback, NULL);
性能注意事项
积压配置
backlog 配置影响性能:
小积压(4-8):内存使用量较低,高负载下可能会产生背压
大积压(16+):突发工作负载的吞吐量更好,内存使用量更高
根据应用的内存约束和工作负载模式进行选择。
DMA 突发大小
dma_burst_size 影响 DMA 传输效率:
较大的突发大小可以提高吞吐量
典型值:16、32、64 字节
最佳值取决于芯片的 DMA 控制器功能。
API 参考
异步 CRC 驱动程序函数
Header File
This header file can be included with:
#include "esp_async_crc.h"
This header file is a part of the API provided by the
esp_driver_dmacomponent. To declare that your component depends onesp_driver_dma, add the following to your CMakeLists.txt:REQUIRES esp_driver_dma
or
PRIV_REQUIRES esp_driver_dma
Functions
-
esp_err_t esp_async_crc_uninstall(async_crc_handle_t crc_hdl)
Uninstall async CRC driver.
- 参数:
crc_hdl -- [in] Handle of async CRC driver that returned from install functions
- 返回:
ESP_OK: Uninstall async CRC driver successfully
ESP_ERR_INVALID_ARG: Uninstall async CRC driver failed because of invalid argument
ESP_FAIL: Uninstall async CRC driver failed because of other error
-
esp_err_t esp_async_crc_calc(async_crc_handle_t crc_hdl, const void *data, size_t size, const async_crc_params_t *params, async_crc_isr_cb_t cb_isr, void *cb_args)
Send an asynchronous CRC calculation request.
备注
The callback function is invoked in interrupt context, never do blocking jobs in the callback.
- 参数:
crc_hdl -- [in] Handle of async CRC driver that returned from install functions
data -- [in] Pointer to data buffer for CRC calculation
size -- [in] Size of data in bytes
params -- [in] CRC calculation parameters
cb_isr -- [in] Callback function, which got invoked in interrupt context. Set to NULL can bypass the callback.
cb_args -- [in] User defined argument to be passed to the callback function
- 返回:
ESP_OK: Send CRC calculation request successfully
ESP_ERR_INVALID_ARG: Send CRC calculation request failed because of invalid argument
ESP_ERR_INVALID_STATE: CRC driver is not in proper state to accept new requests
ESP_FAIL: Send CRC calculation request failed because of other error
-
esp_err_t esp_crc_calc_blocking(async_crc_handle_t crc_hdl, const void *data, size_t size, const async_crc_params_t *params, int32_t timeout_ms, uint32_t *result)
Blocking CRC calculation function with timeout.
备注
This function is blocking and should not be called from interrupt context.
- 参数:
crc_hdl -- [in] Handle of async CRC driver that returned from install functions
data -- [in] Pointer to data buffer for CRC calculation
size -- [in] Size of data in bytes
params -- [in] CRC calculation parameters
timeout_ms -- [in] Timeout in milliseconds:
< 0: Wait forever (no timeout)0: Return immediately (poll once)> 0: Wait up to specified milliseconds
result -- [out] Pointer to store CRC calculation result
- 返回:
ESP_OK: Calculate CRC successfully
ESP_ERR_INVALID_ARG: Calculate CRC failed because of invalid argument
ESP_ERR_INVALID_STATE: Function called from ISR context or driver in invalid state
ESP_ERR_TIMEOUT: Operation timed out
ESP_FAIL: Calculate CRC failed because of other error
Structures
-
struct async_crc_event_data_t
Async CRC event data.
Public Members
-
uint32_t crc_result
CRC calculation result
-
uint32_t crc_result
-
struct async_crc_config_t
Type of async CRC configuration.
-
struct async_crc_params_t
CRC calculation parameters.
Type Definitions
-
typedef struct async_crc_context_t *async_crc_handle_t
Async CRC driver handle.
-
typedef bool (*async_crc_isr_cb_t)(async_crc_handle_t crc_hdl, async_crc_event_data_t *edata, void *cb_args)
Type of async CRC interrupt callback function.
备注
User can call OS primitives (semaphore, mutex, etc) in the callback function. Keep in mind, if any OS primitive wakes high priority task up, the callback should return true.
备注
This callback function is invoked in interrupt context (ISR). The following restrictions apply:
Do not perform blocking operations (e.g., vTaskDelay, xQueueSend with non-zero timeout)
Keep execution time minimal to avoid impacting system interrupt latency
Avoid calling non-ISR-safe FreeRTOS functions
Do not allocate memory or perform heavy computations
Use only ISR-safe APIs (xQueueSendFromISR, xSemaphoreGiveFromISR, etc.)
- Param crc_hdl:
Handle of async CRC
- Param edata:
Event data object, which contains related data for this event
- Param cb_args:
User defined arguments, passed from esp_async_crc_calc function
- Return:
Whether a high priority task is woken up by the callback function
