Files
esp-idf/docs/zh_CN/api-reference/peripherals/async_crc.rst
2026-02-27 10:56:25 +08:00

347 lines
11 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

====================
异步 CRC (Async CRC)
====================
:link_to_translation:`en:[English]`
本文档介绍了 ESP-IDF 中异步 CRC (Async CRC) 驱动程序的功能。目录如下:
.. contents::
:local:
:depth: 2
概述
====
异步 CRC 驱动程序提供使用通用 DMA 外设的硬件加速 CRC 计算。它支持 AHB-GDMA 和 AXI-GDMA 后端,提供灵活的 CRC 计算,支持可配置的多项式、初始值、位反转选项和最终 XOR 处理。
主要功能包括:
- 使用通用 DMA 进行硬件加速的 CRC 计算
- 支持 8 位、16 位和 32 位 CRC 算法
- 带回调通知的异步 API
- 支持超时的阻塞 API
- 支持可配置积压大小的请求队列
- 支持 AHB 和 AXI DMA 后端
应用场景包括:
- 通信协议的数据完整性验证
- 文件和固件校验和计算
- 网络数据包验证
- 存储数据验证
快速开始
========
本节简要介绍如何使用异步 CRC 驱动程序。通过实际示例,演示如何初始化驱动程序、配置 CRC 参数以及执行异步和阻塞 CRC 计算。
异步 CRC 的典型使用流程如下:
.. blockdiag::
:scale: 100%
:caption: 异步 CRC 驱动程序的一般使用流程(点击放大)
:align: center
blockdiag {
default_fontsize = 14;
node_width = 250;
node_height = 80;
class emphasis [color = pink, style = dashed];
install [label="esp_async_crc_install_gdma_*"];
calc [label="esp_async_crc_calc"];
wait [label="等待回调"];
process [label="处理结果"];
uninstall [label="esp_async_crc_uninstall"];
install -> calc -> wait -> process;
process -> calc [folded];
calc -> uninstall [folded];
}
创建和安装驱动程序
------------------
首先,您需要安装异步 CRC 驱动程序。该驱动程序根据芯片的功能支持 AHB-GDMA 和 AXI-GDMA 后端:
.. code:: c
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));
.. note::
**选择 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 计算:
.. code:: c
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, &params, crc_complete_callback, NULL));
CRC 计算完成时会在中断上下文中调用回调函数。回调接收:
- **crc_hdl**:驱动程序句柄
- **edata**:包含 CRC 结果的事件数据
- **cb_args**:在 ``esp_async_crc_calc`` 期间传递的用户定义参数
执行阻塞 CRC 计算
-----------------
对于更简单的使用场景或不需要异步操作的情况,请使用阻塞 API
.. code:: c
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);
// 阻塞 CRC1000ms 超时
ESP_ERROR_CHECK(esp_crc_calc_blocking(crc_hdl, data, data_len, &params, 1000, &crc_result));
printf("CRC 结果: 0x%08X\n", crc_result);
阻塞 API 支持:
- **timeout_ms >= 0**:等待指定的毫秒数
- **timeout_ms < 0**:无限期等待
卸载驱动程序
------------
当不再需要驱动程序时:
.. code:: c
ESP_ERROR_CHECK(esp_async_crc_uninstall(crc_hdl));
如果存在挂起的操作或 CRC 引擎正忙,卸载函数将返回 :c:macro:`ESP_ERR_INVALID_STATE`。请在卸载前确保所有操作已完成。
CRC 参数配置
============
异步 CRC 驱动程序通过 :cpp:type:`async_crc_params_t` 结构支持灵活的 CRC 算法配置。
CRC 宽度
---------
:cpp:member:`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
多项式
--------
:cpp:member:`async_crc_params_t::polynomial` 字段以十六进制格式指定 CRC 多项式。常见的多项式值包括:
- CRC-32: ``0x04C11DB7``
- CRC-16/CCITT: ``0x1021``
- CRC-16/IBM: ``0x8005``
- CRC-8/MAXIM: ``0x31``
初始值
---------
:cpp:member:`async_crc_params_t::init_value` 字段设置处理前的初始 CRC 值。常见的初始值:
- ``0xFFFFFFFF`` 用于 CRC-32
- ``0x0000`` 用于许多 CRC-16 变体
- ``0x00`` 用于许多 CRC-8 变体
最终 XOR 值
-----------
:cpp:member:`async_crc_params_t::final_xor_value` 字段指定在与最终 CRC 结果进行异或之前的值。这通常是 CRC-32 的 ``0xFFFFFFFF``,但对于某些变体可以是 ``0x0000``
位反转选项
-----------
- :cpp:member:`async_crc_params_t::reverse_input` 如果为 true在处理前反转每个输入字节的位顺序
- :cpp:member:`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 都不能从中断上下文调用。具体来说:
- :cpp:func:`esp_async_crc_calc`:涉及内存分配/释放、DMA 准备工作和非 ISR 安全的日志函数
- :cpp:func:`esp_crc_calc_blocking`:使用可能阻塞的同步原语
回调限制
--------
回调函数(:cpp:type:`async_crc_isr_cb_t`)在中断上下文中执行。因此:
- 不要执行阻塞操作(如 ``vTaskDelay``、带超时的 ``xQueueSend``
- 保持执行时间最小化,以免影响系统中断延迟
- 不要使用 ``malloc`` 或类似函数分配内存
- 只使用 ISR 安全的 FreeRTOS API``xQueueSendFromISR``, ``xSemaphoreGiveFromISR``
- 如果回调唤醒了高优先级任务,返回 ``true``
使用队列的回调示例:
.. code:: c
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中。驱动程序自动处理两者
.. code:: c
// 内部 RAM
static char internal_data[] = "Data in internal RAM";
esp_async_crc_calc(crc_hdl, internal_data, strlen(internal_data), &params, callback, NULL);
// 外部 Flash
static const char *flash_data = "Data in external Flash";
esp_async_crc_calc(crc_hdl, flash_data, strlen(flash_data), &params, callback, NULL);
性能注意事项
============
积压配置
--------
``backlog`` 配置影响性能:
- 小积压4-8内存使用量较低高负载下可能会产生背压
- 大积压16+):突发工作负载的吞吐量更好,内存使用量更高
根据应用的内存约束和工作负载模式进行选择。
DMA 突发大小
------------
``dma_burst_size`` 影响 DMA 传输效率:
- 较大的突发大小可以提高吞吐量
- 典型值16、32、64 字节
最佳值取决于芯片的 DMA 控制器功能。
应用示例
========
- :example:`peripherals/dma/async_crc` 演示了如何通过交互式控制台 CLI 使用异步 CRC 驱动程序。
API 参考
========
异步 CRC 驱动程序函数
---------------------
.. include-build-file:: inc/esp_async_crc.inc