本文基于RT-Thread驱动框架,系统介绍了NS800RT7P65的CAN/CAN-FD驱动测试方案,包含23个环回测试(覆盖多波特率、DLC变化、数据完整性、扩展帧、稳定性及非阻塞发送等核心路径)和6个MSH交互命令(支持经典CAN与CAN-FD的TX/RX/Monitor三种模式)。所有环回测试无需外部硬件,真实设备对测已验证标准帧、扩展帧及FD帧的收发正确性,为开发者提供了完整的驱动验证与调试工具链。
目录
- 引言与背景
- 硬件环境
- 软件配置
- 驱动架构概述
- 环回模式测试
- 真实设备对测
- 测试结果与日志
- 常见问题与总结
- 免费试用报名
1 引言与背景
1.1 概述
NS800RT7P65 是 纳芯微(NOVOSENSE)推出的 NSSine™系列 MCU,片内集成了 FLEXCAN 控制器,支持 CAN 2.0B 和 CAN-FD (ISO 11898-1:2015) 协议。
本文档基于 RT-Thread 设备驱动框架,介绍如何对 NS800RT7P65 BSP 中的 CAN/CAN-FD 驱动进行系统化测试。整套测试代码位于 applications/test_can.c,涵盖:
- 13 个经典 CAN 环回测试 — 覆盖设备打开/关闭、多波特率、DLC 变化、数据完整性、模式切换、扩展帧、稳定性、压力、非阻塞发送、错误处理
- 10 个 CAN-FD 环回测试 — 覆盖 FD 使能/禁用、扩展 DLC (12~64 字节)、64 字节数据完整性、帧元数据验证、FD↔Classic 模式切换、独立数据段波特率、混合帧、FD 稳定性、FD 压力、FD 非阻塞发送
- 6 个真实设备 MSH 命令 — 经典 CAN 和 CAN-FD 的 TX / RX / Monitor 三种工作模式
所有环回测试不需要外部 CAN 硬件即可运行;真实设备测试需要配合 USB-CAN 分析仪或另一个 CAN 节点。
1.2 测试目标
2 硬件环境
2.1 开发平台
2.2 CAN 引脚接线
NS800 CAN-FD 接口 (canfd1) 与 USB-CAN 分析仪的连接方式如下:
NS800 开发板 USB-CAN 分析仪───────────── ──────────────GPIO_4 (PA4) ──── CAN_TX ──── CAN_HGPIO_10(PA10) ──── CAN_RX ──── CAN_LGND ──── 开发板 GND注意:如果 USB-CAN 分析仪是 TTL 电平接口(如 CANable、USB2CAN),可直接连 PA4/PA10;如果是标准 CAN 总线接口(DB9),需要外接 CAN 收发器(如 TJA1050/SN65HVD230)。
2.3 串口连接
调试信息和测试输出通过串口打印:
NS800 开发板 USB-TTL 模块 ───────────── ──────────── GPIO_12 (PA12) ──── UART_TX ──── RXGPIO_13(PA13) ──── UART_RX ──── TX GND ──── ──── GND波特率: 115200, 数据位: 8, 校验: 无, 停止位: 1.
3 软件配置
3.1 menuconfig 配置
在 BSP 目录下执行 menuconfig,确认以下配置项已启用:
RT-Thread Kernel └── [*] Using RT-Thread CAN subsystem └── [*] Using CAN-FD support
RT-Thread Components └── Device Drivers └── [*] Using CAN └── [*] Using CAN-FD support └── [*] Using CAN hardware filter
Hardware Drivers Config └── On-chip Peripheral └── [*] Enable CANFD13.2 关键宏定义
启用上述配置后,rtconfig.h 中应包含:
#define RT_USING_CAN#define RT_CAN_USING_CANFD#define RT_CAN_USING_HDR#define BSP_USING_CANFD13.3 测试代码集成
将 test_can.c 放入 applications/ 目录,并在 SConscript 或 IDE 工程中添加编译。测试代码通过 MSH 命令导出,无需修改 main.c。
4 驱动架构概述
4.1 配置RT-Thread CAN 设备框架
RT-Thread 的 CAN 驱动遵循标准设备模型,应用程序通过以下 5 个接口与 CAN 设备交互:
rt_device_t dev = rt_device_find("canfd1"); // 1. 查找设备rt_device_control(dev, RT_DEVICE_CTRL_CONFIG, &cfg); // 2. 配置参数rt_device_open(dev, RT_DEVICE_FLAG_INT_TX | ...); // 3. 打开设备rt_device_write(dev, 0, &tx_msg, sizeof(tx_msg)); // 4. 发送帧rt_device_read(dev, 0, &rx_msg, sizeof(rx_msg)); // 5. 接收帧(ISR 回调触发)4.2 核心数据结构
structrt_can_msg{ rt_uint32_t id; // CAN ID (11-bit or 29-bit) rt_uint32_t ide; // RT_CAN_STDID or RT_CAN_EXTID rt_uint32_t rtr; // RT_CAN_DTR (data) or RTR (remote) rt_uint8_t len; // DLC code (0-8 for classic, 0-15 for FD) rt_uint8_t data[64]; // Payload (8 bytes classic, up to 64 FD) rt_int32_t hdr_index; // Hardware mailbox index (-1 = don't care) rt_uint8_t fd_frame; // 1 = CAN-FD frame, 0 = classic rt_uint8_t brs; // 1 = bit-rate switching enabled rt_uint8_t nonblocking; // 1 = non-blocking send};4.3 测试代码架构
test_can.c 分为五个层次:
┌─────────────────────────────────────────────┐│ MSH Commands(10 exports) │ ← 用户入口│ can_test, can_test_tx, can_test_fd_rx ... │├─────────────────────────────────────────────┤│ Suite Runners │ ← 测试编排│ can_test_run_all, can_test_fd_run_all ... │├─────────────────────────────────────────────┤│ Test Functions(23 test cases) │ ← 测试逻辑│ test_can_loopback_basic, test_can_fd_... │├─────────────────────────────────────────────┤│ Helper Functions │ ← 通用操作│ can_test_open, can_test_send_and_recv ... │├─────────────────────────────────────────────┤│ RT-Thread CAN Device Framework │ ← OS 层│ rt_device_*() APIs │└─────────────────────────────────────────────┘5 环回模式测试
环回模式 (Loopback Mode) 下,CAN 控制器内部将 TX 信号直接回送到 RX,无需外部接线即可完成自发自收验证。
5.1 核心测试辅助函数
以下两个函数是所有测试用例的基础:
打开 CAN 设备(经典 CAN 模式)
staticrt_err_tcan_test_open(rt_uint32_t baud, rt_uint32_t mode){ rt_err_t ret; structcan_configurecfg = CANDEFAULTCONFIG; g_can_dev = rt_device_find(CAN_DEV_NAME); // 查找设备 if (g_can_dev == RT_NULL) return -RT_ERROR; cfg.baud_rate = baud; // 波特率 cfg.mode = mode; // LOOPBACK / NORMAL / LISTEN cfg.privmode = RT_CAN_MODE_NOPRIV; cfg.ticks = 50; // 50 个时间量子 rt_device_control(g_can_dev, RT_DEVICE_CTRL_CONFIG, &cfg); rt_device_open(g_can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX); rt_device_set_rx_indicate(g_can_dev, can_test_rx_callback); // 注册 RX 回调 return RT_EOK;}打开 CAN 设备(CAN-FD 模式)
staticrt_err_tcan_test_open_fd(rt_uint32_t baud, rt_uint32_t baud_fd, rt_uint8_t enable_fd, rt_uint32_t mode){ structcan_configurecfg = CANDEFAULTCONFIG; cfg.baud_rate = baud; cfg.mode = mode; cfg.enable_canfd = enable_fd; // 1 = 启用 FD cfg.baud_rate_fd = (baud_fd > 0) ? baud_fd : baud; // FD 数据段波特率 rt_device_control(g_can_dev, RT_DEVICE_CTRL_CONFIG, &cfg); rt_device_open(g_can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX); rt_device_set_rx_indicate(g_can_dev, can_test_rx_callback); return RT_EOK;}重要:与经典 CAN 的 can_test_open() 不同,FD 版本在 rt_device_open() 之后不调用 SET_MODE / SET_BAUD,因为 _can_config 已在 CONFIG 阶段完成控制器初始化;重复调用会在中断已开启的情况下触发软复位,导致 TX 失败。
发送并接收(环回核心原语)
staticrt_err_tcan_test_send_and_recv(struct rt_can_msg *tx_msg, struct rt_can_msg *rx_msg, rt_int32_t timeout_tick){ rt_uint32_t cb_count_before = g_rx_callback_count; // 1. 排空残留 RX 消息 while (rt_sem_trytake(&g_can_rx_sem) == RT_EOK) { structrt_can_msgdummy; rx_msg->hdr_index = -1; rt_device_read(g_can_dev, 0, &dummy, sizeof(dummy)); } // 2. 阻塞发送 rt_device_write(g_can_dev, 0, tx_msg, sizeof(*tx_msg)); // 3. 等待 RX 中断回调 rt_sem_take(&g_can_rx_sem, timeout_tick); // 4. 读出接收帧 rx_msg->hdr_index = -1; rt_device_read(g_can_dev, 0, rx_msg, sizeof(*rx_msg)); return RT_EOK;}RX 回调通过信号量与主线程同步:
staticrt_err_tcan_test_rx_callback(rt_device_t dev, rt_size_t size){ g_rx_callback_count++; rt_sem_release(&g_can_rx_sem);return RT_EOK;}5.2 经典 CAN 环回测试 (Test 1-13)
数据完整性测试示例
测试 5 使用函数指针表实现 10 种数据模式,避免每种模式重复写循环:
staticconstcan_data_pattern_t s_patterns[] = { {"All zeros", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {"All ones", {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, {"Walking ones", {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}}, {"Walking zeros", {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}}, {"Alternating 0x55AA", {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}}, // ... 共 10 种};for (i = 0; i < PATTERN_COUNT; i++) { can_test_prepare_msg(&tx_msg, 0x400 + i, RT_CAN_STDID, 8, s_patterns[i].data); can_test_send_and_recv(&tx_msg, &rx_msg, RX_WAIT_TICK); can_test_result(test_name, can_test_compare_msg(&tx_msg, &rx_msg, RT_FALSE) == RT_EOK);}稳定性测试统计输出
测试 10 运行 1000 包后会打印详细统计:
--- Stability Statistics ---Total TX : 1000Success : 1000Failures : 0Timeouts : 0Data Mismatch : 0Duration : 5234 ticks (~5234 ms)Packet loss rate: 0%5.3 CAN-FD 环回测试 (Test 14-23)
CAN-FD DLC 转换
CAN-FD 的 DLC 码与字节数的对应关系遵循 ISO 11898-1 标准,测试代码中实现了本地转换函数:
// DLC 码 → 实际字节数staticrt_uint8_tcan_test_dlc_to_len(rt_uint8_t dlc){ staticconstrt_uint8_t dlc2len[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, // DLC 0-8: 直接映射 12, 16, 20, 24, 32, 48, 64 // DLC 9-15: FD 长帧 }; return dlc2len[dlc & 0x0FU];}FD 帧元数据验证
测试 17 验证 4 种元数据组合:
// 组合 1: FD=1, BRS=1 (标准 ID)can_test_prepare_msg_fd(&tx_msg, 0x200, RT_CAN_STDID, 8, data, 1, 1);// 组合 2: FD=0, BRS=0 (经典帧在 FD 模式下)can_test_prepare_msg_fd(&tx_msg, 0x201, RT_CAN_STDID, 8, data, 0, 0);// 组合 3: FD=1, BRS=1 + 扩展 ID + 64 字节can_test_prepare_msg_fd(&tx_msg, 0x1ABCDEF, RT_CAN_EXTID, 15, data_64, 1, 1);// 组合 4: FD=1, BRS=0can_test_prepare_msg_fd(&tx_msg, 0x202, RT_CAN_STDID, 8, data, 1, 0);6 真实设备对测
真实设备测试需要将 CAN 模式切换为 NORMAL,并连接外部 CAN 节点(PC 端 USB-CAN 分析仪或另一个 MCU 节点)。
6.1 经典 CAN — MSH 命令
6.1.1 can_test_tx — 发送帧
msh /> can_test_tx <count> <can_id> [baud] [dlc]
ID 大于 0x7FF 时自动识别为扩展帧 (29-bit)。
使用示例:
# 发送 10 帧标准帧,ID=0x123, 500Kbps, 8 字节msh /> can_test_tx 100x1235000008# 发送 5 帧扩展帧,ID=0x1ABCDEF, 1Mbps, 8 字节msh /> can_test_tx 50x1ABCDEF10000008输出示例:
=== CAN TX Test ===Count: 10, ID: 0x123, Baud: 500000, DLC: 8... sending ...--- TX Complete: 10/10 sent in 55 ms ---6.1.2 can_test_rx — 接收帧
msh /> can_test_rx <expected_count> [timeout_sec] [baud]
行为特性:
- 打开后先显示倒计时,每秒刷新一次
- 收到第一帧时停止倒计时,打印该帧详情
- 后续帧静默收集(不逐帧打印,避免串口 IO 影响实时性)
- 收满或超时后打印统计摘要
使用示例:
# 等待接收 20 帧,超时 30 秒,波特率 500Kmsh /> can_test_rx 2030500000输出示例:
=== CAN RX Test ===Device: canfd1, Baud: 500000Expecting 20 frames, timeout: 30 secondsWaiting for first frame... timeout in: 30s ... timeout in: 29s ... >>> First frame at 2s: ID=0x123 LEN=8 DATA=0001020304050607 (silently collecting remaining...) DONE.========================================RX Complete: 20/20 frames receivedElapsed: 15 secondsTotal frames: 20Last frame: ID=0x123 LEN=8 DATA=0013020304050607========================================msh /> can_test_monitor [duration_sec] [baud]6.1.3 can_test_monitor — 总线监听
以 LISTEN 模式(只收不发)静默统计总线上的所有帧,每 5 秒输出一次状态行。
输出示例:
=== CAN Bus Monitor ===Device: canfd1, Baud: 500000, Duration: 30 secondsListening.............[5s/30] 47 frames, 25s left..........[10s/30] 95 frames, 20s left...========================================Bus Monitor CompleteDuration : 30 secondsTotal frames : 280Frame rate : 9 fps========================================6.2 CAN-FD — MSH 命令
6.2.1 can_test_fd_tx — 发送 CAN-FD 帧
msh /> can_test_fd_tx <count> <id> [baud] [baud_fd] [dlc] [text]
使用示例:
# 发送 10 帧 FD,ID=0x123,仲裁 500K,数据段 2M,64 字节msh /> can_test_fd_tx 100x123500000200000015# 发送 5 帧 FD,ID=0x100,仲裁和数据段均为 1M,DLC=8(8 字节),ASCII 文本msh /> can_test_fd_tx 50x100100000008 text输出示例:
=== CAN-FD TX Test ===Count: 10, ID: 0x123, Baud: 500000/2000000, DLC: 15 (64 bytes)FD=1 BRS=1, BINARY mode... sending ...--- FD TX Complete: 10/10 sent in 55 ms ---6.2.2 can_test_fd_rx — 接收 CAN-FD 帧
msh /> can_test_fd_rx <expected_count> [timeout_sec] [baud] [baud_fd]行为与 can_test_rx 一致,额外统计 FD 帧和非 FD 帧的数量。
输出示例:
=== CAN-FD RX Test ===Device: canfd1, Baud: 500000/2000000Expecting 10 frames, timeout: 30 secondsWaiting for first frame... >>> First frame at 3s: ID=0x123 FD=1 BRS=1 DLC=15(64B) DATA=00010203 ... (silently collecting remaining...) DONE.========================================RX Complete: 10/10 frames receivedElapsed: 12 secondsTotal frames: 10FD frames : 10Non-FD frames: 0Last frame: ID=0x123 FD=1 BRS=1 DLC=15(64B) DATA=00090203 ...========================================6.2.3 can_test_fd_monitor — CAN-FD 总线监听
msh /> can_test_fd_monitor [duration_sec] [baud] [baud_fd]在 can_test_monitor 的基础上增加了 FD 帧和 BRS 帧的分类统计:
[5s/30] 22 frames (FD:18 BRS:18), 25s left[10s/30] 45 frames (FD:36 BRS:36), 20s left...FD frames : 72 (80.0%)Non-FD frames: 18BRS frames : 726.3 真实设备对测流程建议
经典 CAN 收发对测:
[PC 端 USB-CAN 分析仪] [NS800 开发板] 发送 20 帧 can_test_rx 20 30 500000 等待接收 can_test_tx 10 0x123 500000 8 验证收到的帧 验证收到的帧CAN-FD 收发对测:
[PC 端 USB-CAN 分析仪] [NS800 开发板] 发送 10 帧 FD (2Mbps 数据段) can_test_fd_rx 10 30 500000 2000000 等待接收 can_test_fd_tx 5 0x123 500000 2000000 15 验证 FD 标志位 验证 fd_frame=1, brs=17 测试结果与日志
7.1 环回测试完整输出示例
运行 can_test 后的典型输出(截取关键部分):
*********************************************** NS800RT7P65 CAN Driver Test Suite ** Device: canfd1 ***********************************************======================================== 1. Open/Close Basic Test======================================== [PASS] Device find [PASS] Device open [PASS] Device close [PASS] Device re-open======================================== 3. Baud Rate Scan Test======================================== [PASS] Baud rate 1M [PASS] Baud rate 800K [PASS] Baud rate 500K [PASS] Baud rate 250K [PASS] Baud rate 125K [PASS] Baud rate 100K [PASS] Baud rate 50K [PASS] Baud rate 20K [PASS] Baud rate 10K======================================== 10. Long Duration Stability Test (1000 packets)======================================== Sending 1000 packets... Progress: 100/1000 (failures: 0) Progress: 200/1000 (failures: 0) ... Progress: 1000/1000 (failures: 0) [PASS] Stability: 1000 packets --- Stability Statistics --- Total TX : 1000 Success : 1000 Failures : 0 Timeouts : 0 Data Mismatch : 0 Duration : 5234 ticks (~5234 ms) Packet loss rate: 0%======================================== CAN Test Summary======================================== Total : 31 Pass : 31 Fail : 0 Skip : 0======================================== Result: ALL TESTS PASSED========================================7.2 真实设备测试 — 经典 CAN 验证结果
7.3 真实设备测试 — CAN-FD 验证结果
关于 FD 接收的波特率配置:CAN 位同步是边沿驱动的,接收方跟随发送方的信号沿采样。baud_fd 配置主要决定本机 TX 的数据段速率,对 RX 影响有限——即使本地配置 500K,只要收发器硬件支持 2M,也能正确接收 PC 发来的 2M FD 数据段。
8 常见问题与总结
8.1 常见问题
Q1: 环回测试部分失败,但不是全部失败?
NS800 FLEXCAN 控制器的内部环回模式可能存在硬件限制,尤其在连续快速收发场景下。不影响 NORMAL 模式的真实总线通信。建议以 NORMAL 模式下的真实设备对测结果为最终判定依据。
Q2: TX 发送成功但 PC 端收不到?
检查以下几点:
- CAN 收发器:确保 PA4/PA10 外接了 CAN 收发器芯片,仅靠 GPIO 电平无法驱动 CAN 总线
- 终端电阻:CAN 总线两端需要 120Ω 终端电阻
- 波特率匹配:分析仪和开发板波特率必须一致
- 共地:开发板和 CAN 分析仪需要共地
Q3: 扩展帧 (29-bit ID) 接收不到?
NS800 FLEXCAN 控制器中,IDE 位比较是不可屏蔽的——标准帧 RX Mailbox 只匹配标准帧,扩展帧 RX Mailbox 只匹配扩展帧。本驱动已配置两个 RX Mailbox:
如果两个 MB 都被占用或配置错误,某些帧类型将无法接收。
Q4: 发送时 TX ID 始终是 0x78?
这是原始驱动中的一个已知缺陷:FLEXCANDRV_SetTxMsg() 只拷贝数据到 mailbox 的数据区,不更新 ID 字和 CS 字。修复方式是在每次发送前显式调用:
FLEXCANDRV_SetMsgId(msgBufPtr, msg_id, is_ext_id);FLEXCANDRV_SetMsgDLC(msgBufPtr, dlc);FLEXCANDRV_SetFDEnable(msgBufPtr, isFd);当前版本的 drv_can.c 已包含此修复。
8.2 驱动已知限制
8.3 测试命令速查表
8.4 总结
本文档描述的测试方案覆盖了 NS800RT7P65 CAN/CAN-FD 驱动的全部功能路径:
- 23 个环回测试 验证了设备开/关、多波特率、DLC 变化、数据完整性、模式切换、过滤器、扩展 ID、稳定性、压力、非阻塞发送等核心功能
- 6 个 MSH 交互命令 提供了真实总线环境下的收发和监听能力
- 所有经典 CAN 和 CAN-FD 的 标准帧/扩展帧 TX/RX 在真实设备对测中均已验证通过
开发者可通过 can_test_quick 快速确认驱动基本功能,通过 can_test / can_test_fd 进行完整回归测试,通过 can_test_tx / can_test_rx 系列命令与外部 CAN 设备进行互操作调试。
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。