mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
doc(crc): async CRC driver programming guide
This commit is contained in:
+2
-1
@@ -378,7 +378,8 @@ conditional_include_dict = {
|
||||
'SOC_DIG_SIGN_SUPPORTED': ['api-reference/peripherals/ds.rst'],
|
||||
'SOC_ECDSA_SUPPORTED': ['api-reference/peripherals/ecdsa.rst'],
|
||||
'SOC_HMAC_SUPPORTED': ['api-reference/peripherals/hmac.rst'],
|
||||
'SOC_ASYNC_MEMCPY_SUPPORTED': ['api-reference/system/async_memcpy.rst'],
|
||||
'SOC_GDMA_SUPPORT_CRC': ['api-reference/peripherals/async_crc.rst'],
|
||||
'SOC_ASYNC_MEMCPY_SUPPORTED': ['api-reference/peripherals/async_memcpy.rst'],
|
||||
'CONFIG_IDF_TARGET_ARCH_XTENSA': XTENSA_DOCS,
|
||||
'CONFIG_IDF_TARGET_ARCH_RISCV': RISCV_DOCS,
|
||||
'SOC_TEMP_SENSOR_SUPPORTED': TEMP_SENSOR_DOCS,
|
||||
|
||||
@@ -96,6 +96,7 @@ INPUT = \
|
||||
$(PROJECT_PATH)/components/esp_driver_dac/include/driver/dac_cosine.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_dac/include/driver/dac_oneshot.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_dac/include/driver/dac_types.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_dma/include/esp_async_crc.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_dma/include/esp_async_memcpy.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_gpio/include/driver/dedic_gpio.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_gpio/include/driver/gpio.h \
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
============================
|
||||
Asynchronous CRC (Async CRC)
|
||||
============================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
This document introduces the features of the Asynchronous CRC (Async CRC) driver in ESP-IDF. The table of contents is as follows:
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The Async CRC driver provides hardware-accelerated CRC calculation using the General DMA peripheral. It supports both AHB-GDMA and AXI-GDMA backends, offering flexible CRC computation with configurable polynomial, initial value, bit reversal options, and final XOR processing.
|
||||
|
||||
Key capabilities include:
|
||||
|
||||
- Hardware-accelerated CRC calculation using General DMA
|
||||
- Support for 8-bit, 16-bit, and 32-bit CRC algorithms
|
||||
- Asynchronous API with callback notifications
|
||||
- Blocking API with timeout support
|
||||
- Request queuing with configurable backlog size
|
||||
- Support for both AHB and AXI DMA backends
|
||||
|
||||
Application scenarios include:
|
||||
|
||||
- Data integrity verification for communication protocols
|
||||
- File and firmware checksum calculation
|
||||
- Network packet validation
|
||||
- Storage data verification
|
||||
|
||||
Quick Start
|
||||
===========
|
||||
|
||||
This section provides a concise overview of how to use the Async CRC driver. Through practical examples, it demonstrates how to initialize the driver, configure CRC parameters, and perform both asynchronous and blocking CRC calculations.
|
||||
|
||||
The typical usage flow for async CRC is as follows:
|
||||
|
||||
.. blockdiag::
|
||||
:scale: 100%
|
||||
:caption: Async CRC driver's general usage flow (click to enlarge)
|
||||
: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="Wait for callback"];
|
||||
process [label="Process result"];
|
||||
uninstall [label="esp_async_crc_uninstall"];
|
||||
|
||||
install -> calc -> wait -> process;
|
||||
process -> calc [folded];
|
||||
calc -> uninstall [folded];
|
||||
}
|
||||
|
||||
Creating and Installing the Driver
|
||||
----------------------------------
|
||||
|
||||
First, you need to install the Async CRC driver. The driver supports both AHB-GDMA and AXI-GDMA backends, depending on your chip's capabilities:
|
||||
|
||||
.. code:: c
|
||||
|
||||
async_crc_handle_t crc_hdl = NULL;
|
||||
async_crc_config_t config = {
|
||||
.backlog = 8, // Maximum pending requests in queue
|
||||
.dma_burst_size = 16, // DMA burst size in bytes
|
||||
};
|
||||
|
||||
// Install with AHB-GDMA backend (if available)
|
||||
ESP_ERROR_CHECK(esp_async_crc_install_gdma_ahb(&config, &crc_hdl));
|
||||
|
||||
// Or install with AXI-GDMA backend (if available)
|
||||
// ESP_ERROR_CHECK(esp_async_crc_install_gdma_axi(&config, &crc_hdl));
|
||||
|
||||
.. note::
|
||||
|
||||
**Choosing Between AHB-GDMA and AXI-GDMA Backends**
|
||||
|
||||
The backend choice depends on your chip's capabilities and performance requirements:
|
||||
|
||||
- **AHB-GDMA**: Available on most ESP chips. Connects to the AHB bus, suitable for general-purpose DMA operations. Best for:
|
||||
|
||||
- Standard performance requirements
|
||||
- Compatibility across most ESP chip variants
|
||||
|
||||
- **AXI-GDMA**: Available on higher-end ESP chips with AXI bus support. Provides higher bandwidth and better performance for memory-intensive operations. Best for:
|
||||
|
||||
- High-throughput CRC calculations
|
||||
- Processing large amounts of data
|
||||
- Applications requiring maximum performance
|
||||
- Accessing external memory (PSRAM) with better efficiency
|
||||
|
||||
When creating a driver instance, you need to configure:
|
||||
|
||||
- **backlog**: Maximum number of pending CRC requests that can be queued. Higher values use more memory but provide better throughput for bursty workloads.
|
||||
- **dma_burst_size**: DMA transfer burst size in bytes.
|
||||
|
||||
The driver handle ``crc_hdl`` is an opaque pointer that you use for all subsequent operations.
|
||||
|
||||
Performing Asynchronous CRC Calculation
|
||||
---------------------------------------
|
||||
|
||||
The async API allows you to queue CRC calculations without blocking:
|
||||
|
||||
.. 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;
|
||||
// Further process the CRC result
|
||||
// e.g., send to a task via queue, log it, etc.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure CRC parameters for CRC-32
|
||||
async_crc_params_t params = {
|
||||
.width = 32,
|
||||
.polynomial = 0x04C11DB7,
|
||||
.init_value = 0xFFFFFFFF,
|
||||
.final_xor_value = 0xFFFFFFFF,
|
||||
.reverse_input = true,
|
||||
.reverse_output = true,
|
||||
};
|
||||
|
||||
// Start async CRC calculation
|
||||
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));
|
||||
|
||||
The callback function is invoked in interrupt context when the CRC calculation completes. The callback receives:
|
||||
|
||||
- **crc_hdl**: The driver handle
|
||||
- **edata**: Event data containing the CRC result
|
||||
- **cb_args**: User-defined argument passed during ``esp_async_crc_calc``
|
||||
|
||||
Performing Blocking CRC Calculation
|
||||
-----------------------------------
|
||||
|
||||
For simpler use cases or when async operations are not required, use the blocking 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);
|
||||
|
||||
// Blocking CRC with 1000ms timeout
|
||||
ESP_ERROR_CHECK(esp_crc_calc_blocking(crc_hdl, data, data_len, ¶ms, 1000, &crc_result));
|
||||
|
||||
printf("CRC result: 0x%08X\n", crc_result);
|
||||
|
||||
The blocking API supports:
|
||||
|
||||
- **timeout_ms >= 0**: Wait for specified milliseconds
|
||||
- **timeout_ms < 0**: Wait indefinitely
|
||||
|
||||
Uninstalling the Driver
|
||||
------------------------
|
||||
|
||||
When the driver is no longer needed:
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(esp_async_crc_uninstall(crc_hdl));
|
||||
|
||||
The uninstall function returns :c:macro:`ESP_ERR_INVALID_STATE` if there are pending operations or if the CRC engine is busy. Ensure all operations complete before uninstalling.
|
||||
|
||||
CRC Parameter Configuration
|
||||
============================
|
||||
|
||||
The Async CRC driver supports flexible CRC algorithm configuration through the :cpp:type:`async_crc_params_t` structure.
|
||||
|
||||
CRC Width
|
||||
---------
|
||||
|
||||
The :cpp:member:`async_crc_params_t::width` field specifies the CRC bit width:
|
||||
|
||||
- **8**: 8-bit CRC (e.g., CRC-8, CRC-8/MAXIM)
|
||||
- **16**: 16-bit CRC (e.g., CRC-16/CCITT, CRC-16/IBM)
|
||||
- **32**: 32-bit CRC (e.g., CRC-32, CRC-32/BZIP2)
|
||||
|
||||
Polynomial
|
||||
----------
|
||||
|
||||
The :cpp:member:`async_crc_params_t::polynomial` field specifies the CRC polynomial in hexadecimal format. Common polynomial values include:
|
||||
|
||||
- CRC-32: ``0x04C11DB7``
|
||||
- CRC-16/CCITT: ``0x1021``
|
||||
- CRC-16/IBM: ``0x8005``
|
||||
- CRC-8/MAXIM: ``0x31``
|
||||
|
||||
Initial Value
|
||||
-------------
|
||||
|
||||
The :cpp:member:`async_crc_params_t::init_value` field sets the initial CRC value before processing. Common initial values:
|
||||
|
||||
- ``0xFFFFFFFF`` for CRC-32
|
||||
- ``0x0000`` for many CRC-16 variants
|
||||
- ``0x00`` for many CRC-8 variants
|
||||
|
||||
Final XOR Value
|
||||
---------------
|
||||
|
||||
The :cpp:member:`async_crc_params_t::final_xor_value` field specifies a value to XOR with the final CRC result. This is commonly ``0xFFFFFFFF`` for CRC-32 but can be ``0x0000`` for some variants.
|
||||
|
||||
Bit Reversal Options
|
||||
--------------------
|
||||
|
||||
- :cpp:member:`async_crc_params_t::reverse_input` If true, reverses the bit order of each input byte before processing
|
||||
- :cpp:member:`async_crc_params_t::reverse_output` If true, reverses the bit order of the final CRC result before applying the final XOR
|
||||
|
||||
These options affect the reflection settings for different CRC algorithms.
|
||||
|
||||
Common CRC Configurations
|
||||
-------------------------
|
||||
|
||||
The following table lists common CRC configurations:
|
||||
|
||||
+----------------+----------+---------------+---------------+------------------+---------------+---------------+
|
||||
| CRC Algorithm | Width | Polynomial | Initial Value | Final XOR | Reverse Input | Reverse Output|
|
||||
+================+==========+===============+===============+==================+===============+===============+
|
||||
| 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 |
|
||||
+----------------+----------+---------------+---------------+------------------+---------------+---------------+
|
||||
|
||||
Thread Safety
|
||||
=============
|
||||
|
||||
The Async CRC driver is designed to be thread-safe and can be used from multiple tasks. The driver features a **race-free Finite State Machine (FSM)** architecture that ensures thread safety and proper handling of concurrent CRC requests.
|
||||
|
||||
Thread Safety Guarantees
|
||||
------------------------
|
||||
|
||||
- All public APIs can be called from different tasks simultaneously
|
||||
- The driver uses atomic operations and critical sections for internal state protection
|
||||
- Request queuing ensures that concurrent calls are properly serialized
|
||||
|
||||
ISR Context Restrictions
|
||||
------------------------
|
||||
|
||||
Neither the async API nor the blocking API can be called from interrupt context. Specifically:
|
||||
|
||||
- :cpp:func:`esp_async_crc_calc`: Involves memory allocation/free, DMA preparations, and logging functions that are not ISR-safe
|
||||
- :cpp:func:`esp_crc_calc_blocking`: Uses synchronization primitives that may block
|
||||
|
||||
Callback Restrictions
|
||||
---------------------
|
||||
|
||||
The callback function (:cpp:type:`async_crc_isr_cb_t`) is executed in interrupt context. Therefore:
|
||||
|
||||
- Do **not** perform blocking operations (e.g., ``vTaskDelay``, ``xQueueSend`` with timeout)
|
||||
- Keep execution time minimal to avoid impacting system interrupt latency
|
||||
- Do **not** allocate memory using ``malloc`` or similar functions
|
||||
- Use only ISR-safe FreeRTOS APIs (e.g., ``xQueueSendFromISR``, ``xSemaphoreGiveFromISR``)
|
||||
- Return ``true`` if the callback wakes a high-priority task
|
||||
|
||||
Example of callback using queue:
|
||||
|
||||
.. 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;
|
||||
// Send result to a task via ISR-safe queue
|
||||
xQueueSendFromISR(queue, &edata->crc_result, &high_task_awoken);
|
||||
return high_task_awoken == pdTRUE;
|
||||
}
|
||||
|
||||
Buffer Requirements
|
||||
===================
|
||||
|
||||
The Async CRC driver has specific requirements for data buffers.
|
||||
|
||||
Memory Type
|
||||
-----------
|
||||
|
||||
Data buffers can be in internal memory (DRAM/IRAM) or external memory (PSRAM, Flash). The driver automatically handles both:
|
||||
|
||||
.. code:: c
|
||||
|
||||
// Internal RAM
|
||||
static char internal_data[] = "Data in internal RAM";
|
||||
esp_async_crc_calc(crc_hdl, internal_data, strlen(internal_data), ¶ms, callback, NULL);
|
||||
|
||||
// External Flash
|
||||
static const char *flash_data = "Data in external Flash";
|
||||
esp_async_crc_calc(crc_hdl, flash_data, strlen(flash_data), ¶ms, callback, NULL);
|
||||
|
||||
Performance Considerations
|
||||
==========================
|
||||
|
||||
Backlog Configuration
|
||||
---------------------
|
||||
|
||||
The ``backlog`` configuration affects performance:
|
||||
|
||||
- **Small backlog** (4-8): Lower memory usage, may cause backpressure under high load
|
||||
- **Large backlog** (16+): Better throughput for bursty workloads, higher memory usage
|
||||
|
||||
Choose based on your application's memory constraints and workload pattern.
|
||||
|
||||
DMA Burst Size
|
||||
--------------
|
||||
|
||||
The ``dma_burst_size`` affects DMA transfer efficiency:
|
||||
|
||||
- Larger burst sizes can improve throughput
|
||||
- Typical values: 16, 32, 64 bytes
|
||||
|
||||
The optimal value depends on your chip's DMA controller capabilities.
|
||||
|
||||
API Reference
|
||||
=============
|
||||
|
||||
Async CRC Driver Functions
|
||||
--------------------------
|
||||
|
||||
.. include-build-file:: inc/esp_async_crc.inc
|
||||
@@ -69,7 +69,7 @@ Other Peripheral Events
|
||||
:SOC_SYSTIMER_SUPPORT_ETM: - You can call :cpp:func:`esp_systick_new_etm_alarm_event` to get the ETM event from RTOS Systick, one per CPU core.
|
||||
:SOC_SYSTIMER_SUPPORT_ETM: - Refer to :doc:`/api-reference/system/esp_timer` for how to get the ETM event handle from esp_timer.
|
||||
:SOC_TIMER_SUPPORT_ETM: - Refer to :ref:`gptimer-etm-event-and-task` for how to get the ETM event handle from GPTimer.
|
||||
:SOC_GDMA_SUPPORT_ETM: - Refer to :doc:`/api-reference/system/async_memcpy` for how to get the ETM event handle from async memcpy.
|
||||
:SOC_GDMA_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/async_memcpy` for how to get the ETM event handle from async memcpy.
|
||||
:SOC_MCPWM_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/mcpwm` for how to get the ETM event handle from MCPWM.
|
||||
:SOC_ANA_CMPR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/ana_cmpr` for how to get the ETM event handle from analog comparator.
|
||||
:SOC_TEMPERATURE_SENSOR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/temp_sensor` for how to get the ETM event handle from temperature sensor.
|
||||
|
||||
@@ -8,6 +8,8 @@ Peripherals API
|
||||
|
||||
:SOC_ADC_SUPPORTED: adc/index
|
||||
:SOC_ANA_CMPR_SUPPORTED: ana_cmpr
|
||||
:SOC_GDMA_SUPPORT_CRC: async_crc
|
||||
:SOC_ASYNC_MEMCPY_SUPPORTED: async_memcpy
|
||||
:SOC_BITSCRAMBLER_SUPPORTED: bitscrambler
|
||||
:SOC_MIPI_CSI_SUPPORTED: camera_driver
|
||||
:SOC_CLK_TREE_SUPPORTED: clk_tree
|
||||
|
||||
@@ -37,7 +37,6 @@ System API
|
||||
sleep_modes
|
||||
soc_caps
|
||||
system_time
|
||||
:SOC_ASYNC_MEMCPY_SUPPORTED: async_memcpy
|
||||
:esp32: himem
|
||||
ulp
|
||||
wdts
|
||||
|
||||
@@ -23,6 +23,7 @@ api-reference/wifi/esp_smartconfig api-reference/network/esp_smartc
|
||||
api-reference/wifi/esp_wifi api-reference/network/esp_wifi
|
||||
api-reference/system/tcpip_adapter migration-guides/tcpip-adapter
|
||||
api-reference/system/esp_pthread api-reference/system/pthread
|
||||
api-reference/system/async_memcpy api-reference/peripherals/async_memcpy
|
||||
api-reference/storage/spi_flash api-reference/peripherals/spi_flash/index
|
||||
api-reference/storage/spi_flash_concurrency api-reference/peripherals/spi_flash/spi_flash_concurrency
|
||||
api-reference/storage/spi_flash_override_driver api-reference/peripherals/spi_flash/spi_flash_override_driver
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
====================
|
||||
异步 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, ¶ms, 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);
|
||||
|
||||
// 阻塞 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**:无限期等待
|
||||
|
||||
卸载驱动程序
|
||||
------------
|
||||
|
||||
当不再需要驱动程序时:
|
||||
|
||||
.. 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), ¶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 驱动程序函数
|
||||
---------------------
|
||||
|
||||
.. include-build-file:: inc/esp_async_crc.inc
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
异步内存复制
|
||||
========================
|
||||
============
|
||||
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
@@ -69,7 +69,7 @@ GPIO **边沿** 事件是最常见的事件类型,任何 GPIO 管脚均可触
|
||||
:SOC_SYSTIMER_SUPPORT_ETM: - 调用 :cpp:func:`esp_systick_new_etm_alarm_event` 可以从 RTOS Systick 获取 ETM 事件句柄,每个 CPU 核心可以获取一个事件句柄。
|
||||
:SOC_SYSTIMER_SUPPORT_ETM: - 要了解如何从 esp_timer 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/system/esp_timer`。
|
||||
:SOC_TIMER_SUPPORT_ETM: - 要了解如何从 GPTimer 获取 ETM 事件句柄,请参阅 :ref:`gptimer-etm-event-and-task`。
|
||||
:SOC_GDMA_SUPPORT_ETM: - 要了解如何从 async memcpy 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/system/async_memcpy`。
|
||||
:SOC_GDMA_SUPPORT_ETM: - 要了解如何从 async memcpy 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/async_memcpy`。
|
||||
:SOC_MCPWM_SUPPORT_ETM: - 要了解如何从 MCPWM 中获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/mcpwm`。
|
||||
:SOC_ANA_CMPR_SUPPORT_ETM: - 要了解如何从模拟比较器获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/ana_cmpr`。
|
||||
:SOC_TEMPERATURE_SENSOR_SUPPORT_ETM: - 要了解如何从温度传感器获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/temp_sensor`。
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
:SOC_ADC_SUPPORTED: adc/index
|
||||
:SOC_ANA_CMPR_SUPPORTED: ana_cmpr
|
||||
:SOC_GDMA_SUPPORT_CRC: async_crc
|
||||
:SOC_ASYNC_MEMCPY_SUPPORTED: async_memcpy
|
||||
:SOC_BITSCRAMBLER_SUPPORTED: bitscrambler
|
||||
:SOC_CLK_TREE_SUPPORTED: clk_tree
|
||||
:SOC_DAC_SUPPORTED: dac
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
sleep_modes
|
||||
soc_caps
|
||||
system_time
|
||||
:SOC_ASYNC_MEMCPY_SUPPORTED: async_memcpy
|
||||
:esp32: himem
|
||||
ulp
|
||||
wdts
|
||||
|
||||
Reference in New Issue
Block a user