Zephyr CRC 子系统
概述 链接到标题
Zephyr 的 CRC 子系统为数据完整性验证提供丰富的 CRC 算法软件实现,并支持硬件加速。可通过简单的 API 调用计算 CRC,也可以使用 “update” 函数处理流数据。本文从 CRC 子系统实现架构角度,介绍其实现原理和机制,不涉及实际的 CRC 软件算法和硬件驱动分析。
CRC 算法支持 链接到标题
Zephyr CRC 子系统对外的 API 在 zephyr/include/zephyr/sys/crc.h,enum crc_type 描述了其支持的 CRC 类型,每种类型的作用和对应的 crc 函数如下:
CRC4:4 位 CRC 算法(参考crc4),常用于极短数据字段或私有嵌入式协议。CRC4_TI:TI 变体的 4 位 CRC 算法(参考crc4_ti),常用于 TI 芯片相关通信或控制协议。CRC7_BE:大端模式的 7 位 CRC 算法(参考crc7_be),常用于 SD / MMC 卡命令帧校验。CRC8:8 位 CRC 算法(参考crc8),常用于传感器、I²C / SPI 等简单通信。CRC8_CCITT:CCITT 标准的 8 位 CRC 算法(参考crc8_ccitt),常用于通信协议和嵌入式链路层。CRC8_ROHC:ROHC 标准的 8 位 CRC 算法(参考crc8_rohc),常用于蜂窝网络中的 IP 头压缩。CRC16:16 位 CRC 算法(参考crc16),常用于工业控制和通用数据校验。CRC16_ANSI:ANSI 标准的 16 位 CRC 算法(参考crc16_ansi),常用于 Modbus 等工业现场总线。CRC16_CCITT:CCITT 标准的 16 位 CRC 算法(参考crc16_ccitt),常用于电信系统和数据链路层。CRC16_ITU_T:ITU-T 标准的 16 位 CRC 算法(参考crc16_itu_t),常用于 HDLC、串行通信协议。CRC24_PGP:PGP 标准的 24 位 CRC 算法(参考crc24_pgp),常用于 OpenPGP 消息完整性校验。CRC32_C:Castagnoli 多项式的 32 位 CRC 算法(参考crc32_c),常用于存储、网络和内核数据校验。CRC32_IEEE:IEEE 标准的 32 位 CRC 算法(参考crc32_ieee),常用于以太网、文件格式和压缩数据。CRC32_K_4_2:CRC32-C(Koopman)更新算法的 32 位 CRC(参考crc32_k_4_2_update),常用于支持 SSE4.2 的高性能网络、存储和内核路径。
实现架构 链接到标题
Zephyr 有完善的 CRC 软件实现,当硬件支持 CRC 时,会优先使用硬件加速。其架构如下:

本文以 Zephyr CRC 子系统实现架构为主,CRC 的软件实现是多项式算法,这类技术基础不在本文介绍范围内。
核心函数 链接到标题
在 zephyr/include/zephyr/sys/crc.h 中声明了所有 CRC 子系统的函数,除了上一节列出的函数外还有 crc32_ieee_update、crc24_pgp_update 两个函数,用于处理流数据。
另外提供一个函数 crc_by_type 会根据 enum crc_type 选择执行不同的 crc 函数。
软件实现 链接到标题
在 zephyr/subsys/crc 下提供这些算法函数的软件实现:
crc24_sw.ccrc32k_4_2_sw.ccrc4_sw.ccrc8_sw.ccrc16_sw.ccrc32c_sw.ccrc32_sw.ccrc7_sw.c
硬件加速机制 链接到标题
在有硬件 CRC 时,硬件 CRC 的函数会覆盖软件 CRC 的,这通过弱化软件实现 crc 算法函数的符号来实现,例如:
uint8_t __weak crc7_be(uint8_t seed, const uint8_t *src, size_t len)
以上软件实现 crc 的函数都用 __weak 进行修饰。
硬件实现 链接到标题
在 zephyr/subsys/crc/crc_hardware.c 中通过调用 crc 驱动实现相应的 crc 算法函数,例如:
uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len)
{
int ret;
struct crc_ctx ctx = {
.type = CRC7_BE,
.polynomial = CRC7_BE_POLY,
.seed = seed,
.reversed = 0,
};
ret = crc_operation(crc_dev, &ctx, src, len);
if (ret != 0) {
__ASSERT_MSG_INFO("CRC operation failed: %d", ret);
return 0;
}
return ctx.result & 0x7F;
}
当对应的硬件实现函数被编译时,软件算法的弱符号将不会被链接使用。
CRC 硬件驱动 链接到标题
CRC 驱动接口 链接到标题
crc_operation 是通过 crc driver 标准接口 zephyr/include/zephyr/drivers/crc.h 实现:
static int crc_operation(const struct device *const dev, struct crc_ctx *ctx, const uint8_t *src,
size_t len)
{
int ret;
if (!device_is_ready(crc_dev)) {
return -ENODEV;
}
ret = crc_begin(crc_dev, ctx);
if (ret != 0) {
return ret;
}
ret = crc_update(crc_dev, ctx, src, len);
if (ret != 0) {
return ret;
}
ret = crc_finish(crc_dev, ctx);
if (ret != 0) {
return ret;
}
return 0;
}
驱动接口向下就是 Zephyr 中各支持 CRC 的芯片驱动实现,按照标准的 Zephyr 驱动架构实现并注册以下内容:
__subsystem struct crc_driver_api {
crc_api_begin begin;
crc_api_update update;
crc_api_finish finish;
};
支持的硬件平台 链接到标题
实际的 crc 驱动实现在 zephyr/drivers/crc,目前 Zephyr 只实现了这 4 类芯片的硬件 crc:
zephyr_library_sources_ifdef(CONFIG_CRC_DRIVER_NXP crc_nxp.c)
zephyr_library_sources_ifdef(CONFIG_CRC_DRIVER_NXP_LPC crc_nxp_lpc.c)
zephyr_library_sources_ifdef(CONFIG_CRC_DRIVER_RENESAS_RA crc_renesas_ra.c)
zephyr_library_sources_ifdef(CONFIG_CRC_DRIVER_SF32LB crc_sf32lb.c)
这些选项不用去做 Kconfig 配置,在 Devicetree 配置后就会自动选中。
硬件加速生效机制 链接到标题
在 Zephyr 中无需直接通过 Kconfig 配置启用对应的硬件驱动,在 Devicetree 中配置 zephyr,crc 属性,就会启用硬件加速。以思澈 SF32LB 为例说明其如何通过 Devicetree 让硬件加速生效。
在 zephyr/boards/sifli/sf32lb52_devkit_lcd/sf32lb52_devkit_lcd.dts 中有如下片段,说明启用了硬件 CRC:
/ {
chosen {
zephyr,crc = &crc;
};
}
&crc {
status = "okay";
};
在 zephyr/subsys/crc/Kconfig 中发现有 DT_CHOSEN_Z_CRC 选项存在(由 zephyr,crc 生成)就会选中 CRC_HW_HANDLER 和 CRC_DRIVER:
config CRC_HW_HANDLER
bool "CRC Hardware Accelerator"
default y if $(dt_chosen_enabled,$(DT_CHOSEN_Z_CRC))
select CRC_DRIVER
help
Enable use of CRC hardware
在 zephyr/subsys/crc/CMakeLists.txt 中根据 CONFIG_CRC_HW_HANDLER 将 CRC 硬件驱动 crc_hardware.c 添加到构建中
zephyr_library_sources_ifdef(CONFIG_CRC_HW_HANDLER crc_hardware.c)
在 zephyr/drivers/crc/Kconfig 中会判断 CRC_DRIVER 存在,就会将支持的硬件 CRC 驱动 Kconfig 加入
source "drivers/crc/Kconfig.nxp"
source "drivers/crc/Kconfig.renesas_ra"
source "drivers/crc/Kconfig.sf32lb"
在 zephyr/boards/sifli/sf32lb52_devkit_lcd/sf32lb52_devkit_lcd.dts 中,crc 被 enable,脚本处理 DeviceTree 时就会生成 DT_HAS_SIFLI_SF32LB_CRC_ENABLED Kconfig 选项,zephyr/drivers/crc/Kconfig.sf32lb 中会根据这个选项来启用 CRC_DRIVER_SF32LB 和相关支持的硬件 CRC Kconfig 选项。
config CRC_DRIVER_SF32LB
bool "SiFli SF32LB CRC driver"
depends on DT_HAS_SIFLI_SF32LB_CRC_ENABLED
default y
select CRC_DRIVER_HAS_CRC8
select CRC_DRIVER_HAS_CRC8_ROHC
select CRC_DRIVER_HAS_CRC8_CCITT
select CRC_DRIVER_HAS_CRC16
select CRC_DRIVER_HAS_CRC16_REFLECT
select CRC_DRIVER_HAS_CRC16_ANSI
select CRC_DRIVER_HAS_CRC16_CCITT
select CRC_DRIVER_HAS_CRC16_ITU_T
select CRC_DRIVER_HAS_CRC32_IEEE
select CRC_DRIVER_HAS_CRC32_C
select CRC_DRIVER_HAS_CRC32_K_4_2
help
在 zephyr/drivers/crc/CMakeLists.txt 中根据 CONFIG_CRC_DRIVER_SF32LB 将 CRC 驱动 crc_sf32lb.c 添加到构建中
zephyr_library_sources_ifdef(CONFIG_CRC_DRIVER_SF32LB crc_sf32lb.c)
在 zephyr/subsys/crc/Kconfig 中会根据 zephyr/drivers/crc/Kconfig.sf32lb 中定义的支持的硬件 CRC 算法,选中编译对应 Kconfig 选项,zephyr/subsys/crc/crc_hardware.c 中会根据这些选项,选中编译对应的硬件实现函数,来实现对软件实现弱符号的覆盖,例如 CRC_DRIVER_HAS_CRC8 会选中 CRC8
config CRC8
bool "CRC-8 (Generic)"
depends on CRC_DRIVER_HAS_CRC8
default y
help
Implements a generic CRC-8 algorithm. Useful for small data integrity
checks such as checksums and simple communication protocols.
在 zephyr/subsys/crc/crc_hardware.c 中会根据 CONFIG_CRC8``的实现函数crc8,来实现对软件实现弱符号crc8`的覆盖。
#ifdef CONFIG_CRC8
uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
bool reversed)
{
uint8_t flag_reversed;
int ret;
if (reversed) {
flag_reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT;
}
struct crc_ctx ctx = {
.type = CRC8,
.polynomial = polynomial,
.seed = initial_value,
.reversed = flag_reversed,
};
ret = crc_operation(crc_dev, &ctx, src, len);
if (ret != 0) {
__ASSERT_MSG_INFO("CRC operation failed: %d", ret);
return 0;
}
return ctx.result;
}
#endif
而其它没有被覆盖的CRC算法依然使用软件实现。