跳转到主要内容

NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

本文基于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 测试目标

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

2 硬件环境

2.1 开发平台

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

2.2 CAN 引脚接线

NS800 CAN-FD 接口 (canfd1) 与 USB-CAN 分析仪的连接方式如下:

NS800 开发板                USB-CAN 分析仪
─────────────               ──────────────
GPIO_4  (PA4)  ──── CAN_TX ──── CAN_H
GPIO_10(PA10) ──── CAN_RX ──── CAN_L
GND ──── 开发板 GND

注意:如果 USB-CAN 分析仪是 TTL 电平接口(如 CANable、USB2CAN),可直接连 PA4/PA10;如果是标准 CAN 总线接口(DB9),需要外接 CAN 收发器(如 TJA1050/SN65HVD230)。

2.3 串口连接

调试信息和测试输出通过串口打印:

NS800 开发板                USB-TTL 模块
 ─────────────               ────────────
 GPIO_12 (PA12) ──── UART_TX ──── RX
GPIO_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 CANFD1

3.2 关键宏定义

启用上述配置后,rtconfig.h 中应包含:

#define RT_USING_CAN
#define RT_CAN_USING_CANFD
#define RT_CAN_USING_HDR
#define BSP_USING_CANFD1

3.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)

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

数据完整性测试示例

测试 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      : 1000
Success       : 1000
Failures      : 0
Timeouts      : 0
Data Mismatch : 0
Duration      : 5234 ticks (~5234 ms)
Packet loss rate: 0%

5.3 CAN-FD 环回测试 (Test 14-23)

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

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=0
can_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]
Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

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]
Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

行为特性:

  • 打开后先显示倒计时,每秒刷新一次
  • 收到第一帧时停止倒计时,打印该帧详情
  • 后续帧静默收集(不逐帧打印,避免串口 IO 影响实时性)
  • 收满或超时后打印统计摘要

使用示例:

# 等待接收 20 帧,超时 30 秒,波特率 500K
msh /> can_test_rx 2030500000

输出示例:

=== CAN RX Test ===
Device: canfd1, Baud: 500000
Expecting 20 frames, timeout: 30 seconds
Waiting 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 received
Elapsed: 15 seconds
Total frames: 20
Last 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 seconds
Listening...
..........
[5s/30] 47 frames, 25s left
..........
[10s/30] 95 frames, 20s left
...
========================================
Bus Monitor Complete
Duration     : 30 seconds
Total frames : 280
Frame 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]
Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

使用示例:

# 发送 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/2000000
Expecting 10 frames, timeout: 30 seconds
Waiting 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 received
Elapsed: 12 seconds
Total frames: 10
FD frames   : 10
Non-FD frames: 0
Last 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: 18
BRS frames   : 72

6.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=1

7 测试结果与日志

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 验证结果

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

7.3 真实设备测试 — CAN-FD 验证结果

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/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:

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

如果两个 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 驱动已知限制

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

8.3 测试命令速查表

Image
NS800RT7P65D 上基于 RT-Thread 的CAN/CAN-FD 驱动测试应用

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 设备进行互操作调试。

来源:RT-Thread操作系统

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。