10BASE-T1S Arduino 开源库架构分析(一):架构概览与开源评估

系列导读

本系列三篇文章对 Arduino 官方 10BASE-T1S 库进行完整的软件架构分析,目标是为后续移植到竞品 T1S 芯片提供技术基线:

  1. 架构概览与开源评估(本篇)— 分层设计、编译平台、许可证分析
  2. 协议栈深度分析 — OA TC6 SPI 协议帧结构、数据流、PLCA
  3. 移植实战指南 — 抽象边界、可复用模块、移植 checklist

10BASE-T1S 技术背景

10BASE-T1S 是 IEEE 802.3cg-2019 定义的单对线以太网标准,核心特性:

特性 10BASE-T1S 传统 100BASE-TX
线对数 1 对 2 对
速率 10 Mbps 100 Mbps
拓扑 多点总线(multi-drop) 点对点
最大节点数 8(PLCA 模式) 2
线缆长度 25m(mixing segment) 100m
碰撞处理 PLCA 确定性轮询 N/A(全双工)

关键 trade-off:牺牲速率换取布线简化和多点接入能力,适合汽车/工业传感器网络场景,一根双绞线串联多个节点。

PLCA(Physical Layer Collision Avoidance)是 10BASE-T1S 的核心机制:Node ID 0 作为协调器,按固定顺序给每个节点分配发送时隙,避免 CSMA/CD 的随机退避延迟。

项目概览

属性
名称 Arduino_10BASE_T1S
版本 0.1.1
维护者 Arduino (Alexander Entinger)
许可证 MPL-2.0(顶层)
仓库 https://github.com/arduino-libraries/Arduino_10BASE_T1S
目标芯片 Microchip LAN8650 / LAN8651 MAC-PHY
分类 Communication

这是 Arduino 官方维护的库,通过 Arduino Library Manager 分发,提供从 SPI 驱动到 UDP socket 的完整协议栈。

软件架构分层

graph TB
    subgraph "Application Layer"
        A1["Arduino Sketch (UDP_Client / UDP_Server)"]
        A2["Arduino_10BASE_T1S_UDP"]
    end

    subgraph "Network Layer"
        B1["lwIP TCP/IP Stack"]
        B2["UDP PCB / ARP / ICMP / IPv4"]
    end

    subgraph "Protocol Layer"
        C1["libtc6 v3.1.3"]
        C2["OA TC6 SPI Protocol"]
        C3["Credit Mgmt / Chunk Framing"]
    end

    subgraph "HAL Layer"
        D1["TC6_Io"]
        D2["SPI + GPIO (CS/RESET/IRQ)"]
    end

    subgraph "Hardware"
        E1["LAN8650/8651 MAC-PHY"]
        E2["10BASE-T1S PHY Twisted Pair"]
    end

    A1 --> A2
    A2 --> B1
    B1 --> B2
    B2 --> C1
    C1 --> C2
    C2 --> C3
    C3 --> D1
    D1 --> D2
    D2 --> E1
    E1 --> E2

各层职责

Application Layer — 用户代码接口,继承 Arduino 标准 UDP 基类,提供 beginPacket() / write() / endPacket() / parsePacket() 标准 API。

Network Layer — 完整的 lwIP 嵌入式 TCP/IP 协议栈,处理 ARP、ICMP、IPv4 路由、UDP 多路复用。MTU 设为 1536 字节。

Protocol Layer — Microchip 提供的 libtc6 库,实现 Open Alliance TC6 SPI 协议:将以太网帧拆分为 64 字节 chunk,附加 4 字节 header/footer,通过 SPI 全双工传输,管理 TX/RX credit 流控。

HAL LayerTC6_Io 类封装 Arduino SPI 接口,配置 24MHz 时钟、Mode 0、MSB-first,控制 CS/RESET/IRQ 三根 GPIO。

类关系

classDiagram
    class Arduino_10BASE_T1S_PHY_Interface {
        <<abstract>>
        +begin()
        +service()
        +getPlcaStatus()
        +enablePlca()
    }

    class TC6_Arduino_10BASE_T1S {
        -TC6_Io& io
        -netif lwip_netif
        +begin(ip, mask, gw, mac, plca, mac_settings)
        +service()
        +digitalWrite(dio, val)
    }

    class TC6_Io {
        -HardwareSPI& spi
        -int cs_pin, reset_pin, irq_pin
        +begin()
        +spiTransaction(pTx, pRx, len)
        +onInterrupt()
    }

    class Arduino_10BASE_T1S_UDP {
        -udp_pcb* pcb
        -list~UdpRxPacket~ rx_pkt_list
        +begin(port)
        +beginPacket(ip, port)
        +write(buf, len)
        +endPacket()
        +parsePacket()
        +read(buf, len)
    }

    Arduino_10BASE_T1S_PHY_Interface <|-- TC6_Arduino_10BASE_T1S
    TC6_Arduino_10BASE_T1S --> TC6_Io
    Arduino_10BASE_T1S_UDP --> TC6_Arduino_10BASE_T1S

典型使用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 实例化 PHY(宏展开为 TC6_Io + TC6_Arduino_10BASE_T1S 对象)
Arduino_10BASE_T1S_PHY_TC6(SPI, CS_PIN, RESET_PIN, IRQ_PIN);
Arduino_10BASE_T1S_UDP udp_client;

void setup() {
pinMode(IRQ_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQ_PIN),
[]() { t1s_io.onInterrupt(); }, FALLING);

t1s_io.begin();
t1s_phy.begin(ip_addr, network_mask, gateway,
mac_addr, t1s_plca_settings, t1s_default_mac_settings);
udp_client.begin(UDP_CLIENT_PORT);
}

void loop() {
t1s_phy.service(); // 必须高频调用,驱动 SPI 收发和 lwIP 定时器
// ... UDP 收发逻辑
}

编译平台与 CI 矩阵

支持的架构

库声明支持 5 种 Arduino 架构:samd, renesas_uno, renesas_portenta, mbed_giga, mbed_portenta

CI 构建矩阵(7 块板卡)

FQBN 架构 MCU
arduino:samd:arduino_zero_native SAMD ATSAMD21G18 (Cortex-M0+)
arduino:samd:arduino_zero_edbg SAMD ATSAMD21G18 (Cortex-M0+)
arduino:renesas_uno:minima Renesas UNO RA4M1 (Cortex-M4)
arduino:renesas_uno:unor4wifi Renesas UNO RA4M1 (Cortex-M4)
arduino:renesas_portenta:portenta_c33 Renesas Portenta RA6M5 (Cortex-M33)
arduino:mbed_giga:giga Mbed GIGA STM32H747 (Cortex-M7)
arduino:mbed_portenta:envie_m7 Mbed Portenta STM32H747 (Cortex-M7)

板卡引脚映射

1
2
3
4
5
6
7
8
9
10
11
12
// Arduino Zero / UNO R4 系列(Uno form factor)
static int const CS_PIN = 9;
static int const RESET_PIN = 6;
static int const IRQ_PIN = 2;

// Portenta C33(Pro Demo kit on MID carrier)
static int const CS_PIN = 25;
static int const RESET_PIN = 6;
static int const IRQ_PIN = 2;

// GIGA / Portenta C33 使用 SPI1 而非默认 SPI
Arduino_10BASE_T1S_PHY_TC6(SPI1, CS_PIN, RESET_PIN, IRQ_PIN);

编译命令

1
arduino-cli compile -b arduino:renesas_uno:unor4wifi -v examples/UDP_Client -u -p /dev/ttyACM0

开源状态分析

这个库并非完全开源,由三个不同许可证的组件构成:

组件 许可证 是否开源 移植影响
Arduino 封装层 MPL-2.0 ✅ 完全开源,可修改分发 可自由修改复用
Microchip libtc6 Microchip 专有许可 ⚠️ 源码可见,专利受限 需评估专利风险
lwIP 协议栈 BSD (3-clause) ✅ 完全开源 可自由复用
Linux 内核驱动 GPL-2.0+ ✅ 完全开源 仅限 Linux 环境

Microchip libtc6 的许可证关键条款:

“No license or other rights, whether express or implied, are granted under any patent or other intellectual property rights of Microchip or any third party.”

这意味着:源码可以阅读和学习,但如果竞品芯片也需要实现 OA TC6 协议,直接复用 Microchip 的 libtc6 二进制可能存在专利风险。如果竞品芯片自身提供 TC6 协议实现,或者根据 Open Alliance 规范独立实现,则不受此限制。

测试方法分析

现有测试手段

测试类型 是否具备 说明
单元测试 无任何 test 目录或测试框架
集成测试 无自动化集成测试
HIL(硬件在环) 无自动化硬件测试
CI 编译验证 7 块板卡 × 全部 example 编译通过
Arduino Lint 库结构和代码规范检查
Spell Check codespell 拼写检查

实际验证方案

项目依赖手动硬件测试,典型测试拓扑:

graph LR
    A["Arduino UNO R4 WiFi\n(UDP Client, Node 1)"] -->|"单对双绞线\n10BASE-T1S"| B["Multi-drop Bus"]
    C["Arduino UNO R4 WiFi\n(UDP Server, Node 0)"] -->|"单对双绞线"| B
    D["EVB-LAN8670-USB\n(Linux Host, Node 0)"] -->|"单对双绞线"| B
  • Arduino 侧:运行 UDP_Client / UDP_Server example,通过 Serial 观察收发日志
  • Linux 侧:EVB-LAN8670-USB 加载内核模块,配置 IP,用 tcpdump 抓包验证
  • PLCA 状态监控:代码中每秒读取 PLCA status 寄存器,检测是否回退到 CSMA/CD

测试覆盖的局限性

  1. 无回归测试保障 — 修改代码后只能确认编译通过,无法确认功能正确
  2. 无性能基线 — 无吞吐量/延迟的自动化测量
  3. PLCA 多节点场景 — CI 无法验证实际多节点竞争行为
  4. 错误恢复路径 — 未自动验证 SPI 错误、线缆断开等异常场景

这对移植工作意味着:移植后的验证完全依赖手动硬件测试,需要自建 UDP echo 测试环境。

小结

Arduino 10BASE-T1S 库是一个架构清晰的四层设计,核心依赖 Microchip libtc6 实现 OA TC6 SPI 协议。对于移植到竞品芯片:

  • lwIP 和 Arduino UDP 封装层可直接复用
  • HAL 层(TC6_Io)需要适配新的 SPI 接口
  • 协议层是否可复用取决于竞品是否兼容 OA TC6
  • 测试需要自建,因为原项目无自动化测试基础设施

下一篇将深入 OA TC6 SPI 协议的帧结构和数据流实现细节。