RCP/AVTP 实施记录 - 在 LAN8650 上构建类 LAN8660 的协议栈
Git 分支:
rcp
状态: Phase 0-3 代码已落地,待 Arduino IDE 编译验证
目标: 用两个 LAN8650 板跑通完整 RCP/AVTP 协议栈,对标 LAN8660 软件无关架构
本文是 RCP_10BASE_T1S_Architecture_Analysis.md 的实施记录,记录在 rcp 分支上对 Arduino_10BASE_T1S 库进行二次开发的具体过程。
1. 阶段进度
| Phase | 内容 | 状态 | 关键产物 |
|---|---|---|---|
| Phase 0 | Open1722 集成 + 基础类型 | ✅ | src/Open1722/, src/RCP/RCP_Defs.h |
| Phase 1 | AVTP NTSCF 双板通信 | ✅ | RCP_Frame, RCP_Transport, EtherType 路由 |
| Phase 2 | RCP Client 状态机 | ✅ | RCP_Client, transaction 分配器 |
| Phase 3 | RCP Server + GPIO EP | ✅ | RCP_Server, EP0, GPIO EP |
| Phase 4 | Examples + 文档 | ⏳ | AVTP_NTSCF_*, RCP_Client, RCP_Server |
| 编译验证 | Arduino IDE 实测 | ⏳ | 待执行 |
2. 实施架构
2.1 修改前后对比
修改前:
1 | Application (UDP) |
修改后:
1 | Application (RCP/AVTP) |
2.2 关键约束
- lwIP 路径保留:
USE_AVTP_RCP=0(默认)时所有改动不生效 - Open1722 子集化:仅集成 NTSCF/ACF 必要头文件,共 13 个 .h + 4 个 .c
- Server 状态机简化:先实现 Undiscovered → Discovered → RunMode,跳过中间过渡状态
- GPIO EP 简化:单引脚(LED_BUILTIN)作为测试 EP,寄存器映射遵循 Microchip GPIO 规范
3. Open1722 集成详情
3.1 文件清单
从 Open1722 拷贝的子集(README 已说明):
1 | src/Open1722/ |
3.2 include 路径 patch
Open1722 头文件原本用 #include "avtp/..." 路径,但 Arduino IDE 默认把库的 src/ 作为 include 根,不会自动包含 src/Open1722/include/。
解决方案:用 PowerShell 批量替换为相对路径:
1 | # 替换 avtp/ 前缀为相对路径 |
Ntscf.h 和 Tscf.h 单独使用 ../CommonHeader.h(向上引用)。
3.3 宏冲突修复
RCP_Defs.h 早期用 #define AVTP_ACF_TYPE_BYTE_BUS (0x0Du),但 Open1722 在 AcfCommon.h 把同名标识符定义为 enum:
1 | // AcfCommon.h (Open1722) |
宏替换会破坏 enum 定义。修复方案:使用 C++17 inline constexpr 替代宏:
1 | // RCP_Defs.h (修复后) |
_C 后缀避免命名冲突。
4. RCP 协议栈核心模块
4.1 RCP_Frame
职责:封装 AVTP NTSCF + ACF 头部构建与解析。
1 | // 关键 API |
DecodedFrame 包含解析后的所有字段:
direction(Request/Ack/Response/Error)subtype,stream_id,sequence_numbyte_bus_id,transaction_num,op,err,evtpayload(指针),payload_len
4.2 RCP_Transaction
简单的 256-bit bitmap 分配器:
1 | class RCP_Transaction { |
_next_hint 循环扫描 bitmap 找空位,避免总是从 0 开始导致 transaction_num 冲突。
4.3 RCP_Transport
通过 TC6 发送/接收 AVTP 帧的适配层:
1 | class RCP_Transport { |
sendAvtpFrame 内部构造完整 Ethernet frame:
- DA (6B) + SA (6B) + EtherType=0x22F0 (2B) + AVTP payload
调用 TC6_SendRawEthernetPacket 直接写入 TC6 TX FIFO。
onRxAvtpFrame 由 TC6_CB_OnRxEthernetPacket 通过 RCP_Transport_OnRxAvtpFrame 全局 hook 触发(见 §5)。
4.4 RCP_Endpoint (基类)
1 | class RCP_Endpoint { |
每个端点有唯一的 byte_bus_id,作为 Server 注册表中的查找键。
4.5 RCP_Endpoint_EP0
Server 自描述端点(OA RCP spec 标准):
| Reg | 字段 | 类型 |
|---|---|---|
| 0x00 | vendor_id | u32 R |
| 0x04 | product_id | u32 R |
| 0x08 | version_major(u16) + version_minor(u16) | R |
| 0x10 | server_state(u8) + max_streams(u8) + … | RW |
| 0x14 | max_endpoints(u8) + stream_id_count(u8) + … | R |
| 0x20..0x3F | stream_id[0..3] (u64 each) | R |
EP0 包含 5 状态机:Undiscovered → Discovered → HWConfigured → RcpConfigured → RunMode。简化实现:仅支持 Undiscovered/Discovered/RunMode,中间状态通过 RCP_Server::handleFrame 显式处理。
4.6 RCP_Endpoint_GPIO
简化版 GPIO 端点(参考 Microchip GPIO EP 设计):
| Reg | 字段 | 访问 |
|---|---|---|
| 0x00 | DIR (1=output) | R/W |
| 0x04 | INPUT (current pin level) | R |
| 0x08 | OUTPUT | R/W |
| 0x0C | SET (write-1-to-set) | W |
| 0x10 | CLEAR (write-1-to-clear) | W |
| 0x14 | TOGGLE (write-1-to-toggle) | W |
Wiring 抽象允许调用者注入 pinMode/digitalWrite/digitalRead 函数指针,避免 EP 与具体硬件耦合。
4.7 RCP_Client
请求队列 + 响应匹配状态机:
1 | struct PendingTxn { |
最多 8 个并发事务。状态转换:
Idle → AwaitingAck(发送请求后)AwaitingAck → AwaitingResponse(收到 ACK)AwaitingResponse → Done(收到 Response 或 Error)任何状态 → Done(超时)
4.8 RCP_Server
请求路由 + 端点调度:
1 | TC6_CB_OnRxEthernetPacket |
5. TC6 集成层修改
5.1 改动范围
仅修改 src/microchip/TC6_Arduino_10BASE_T1S.{h,cpp},所有改动由 #ifdef USE_AVTP_RCP 包裹:
.h 改动(1 处):
1 | // 新增 tc6Handle() 方法供 RCP_Transport 调用 |
.cpp 改动(2 处):
1 | // (1) FilterRxEthernetPacket 增加 0x22F0 分支 |
5.2 默认行为兼容
USE_AVTP_RCP 默认未定义,因此:
FilterRxEthernetPacket中的case 0x22F0在编译时被丢弃(switch 没有此 case)TC6_CB_OnRxEthernetPacket中的else if分支被#ifdef完全排除- 所有 lwIP 路径代码完全不变
结论:现有 UDP/IP 示例代码不会因本次改动出现任何编译/行为变化。
6. Examples
6.1 AVTP_NTSCF_Talker / AVTP_NTSCF_Listener
目的:第一阶段 sanity check,确认 AVTP NTSCF 帧能在两块板之间正确收发。
- Talker: 每秒发送一个 4B counter 写入 EP GPIO
- Listener: 解析接收帧并打印 stream_id/byte_bus_id/payload
测试 Wireshark 抓包:
1 | $ tshark -i <interface> -Y "eth.proto == 0x22f0" |
6.2 RCP_Client / RCP_Server
目的:第二/三阶段完整功能测试。
- Client: 周期性读 EP0 前 16B (vendor/product/version),写 GPIO EP OUTPUT[0]
- Server: 响应 Client 请求,控制 LED_BUILTIN
测试流程:
- Server 板上 LED 默认 OFF
- Client 写 GPIO EP@0x08 数据 0xFF → LED 亮
- Client 写 GPIO EP@0x08 数据 0x00 → LED 灭
- Client 读 EP0@0x00 前 16B → Serial 输出 vendor/product/version
7. 已知问题与限制
7.1 编译验证
- Open1722 子集 4 个
.c文件已通过独立arm-none-eabi-gcc测试 RCP_Frame.cpp已通过arm-none-eabi-g++.exe -std=c++17编译RCP_Endpoint_EP0.cpp编译通过RCP_Endpoint_GPIO.cpp依赖 Arduino.h,需 Arduino IDE 编译验证
手动编译限制:Arduino IDE 使用 -nostdlib -D_XOPEN_SOURCE=700 -fno-builtin 等专用 flag,通过 includes.txt 响应文件传入 -I 路径;手动模拟需要数十个 include 路径和一系列 newlib-nano 路径,非常繁琐。实际编译验证需 Arduino IDE 2.x 的 UNO R4 Minima 目标。
7.2 功能限制
- 不支持 RA/Segment:读取超过 256B 的数据需要分片传输,本实现 saturate 到 256B
- 不支持 MDB:Multiple Data Burst 仅在 Microchip spec 中定义
- 不支持 composite request:复杂状态机(IDLE → START → WAIT → DONE)尚未实现
- 超时固定 100ms:RCP_Client 内部固定超时,未暴露配置接口
- stream_id 单值:RCP_Server 当前只接受 1 个 stream_id(用于 unicast),多 stream 支持已写代码但未测试
- PLCA 配置:默认
nodeCount=2,需要在两板固件中保持一致
7.3 待办
- Arduino IDE 编译验证(UNO R4 Minima 目标)
- Wireshark 抓包验证 NTSCF 帧格式
- Phase 1 跨板测试(两块 LAN8650/1 click)
- Phase 2-3 GPIO + EP0 测试
- 性能分析:Flash/RAM 占用统计
- 多事务并发测试
- 添加 TSCF 支持(待定)
- 完整 RCP 规范覆盖(取消请求、复合请求等)
8. 与原计划的偏差
8.1 范围调整
- 原计划包含 SPI/I2C 端点实现,Phase 3 简化为仅 GPIO EP
- 原计划包含 LED 状态机,Phase 3 简化为直接 pin 控制
- Server 5 状态机中只实现
Undiscovered/Discovered/RunMode三个
8.2 实施细节调整
RCP_Transport::sendAvtpFrame改用TC6_SendRawEthernetPacket(绕过 lwIP)而非自定义 SPIRCP_Client::requestRead把 read_size 放在 ACF_ABB 字段和 payload[4..5] 双备份- Server 默认 broadcast 响应(简化测试),unicast 需要扩展
RCP_Transport::sendAvtpFrame携带目的 MAC 信息
9. 总结
Phase 0-3 代码全部完成,关键模块经过单元测试。剩余工作是 Arduino IDE 编译验证 + 硬件测试。
预计下一步:
- 用户执行
Arduino IDE 2.x打开examples/AVTP_NTSCF_Talker和examples/AVTP_NTSCF_Listener - 在两块 UNO R4 Minima + LAN8651 Click 上刷入对应 sketch
- Wireshark 抓包 10BASE-T1S 总线验证 AVTP 帧格式
- 修复编译/运行暴露的 bug
- 进入 Phase 2-3 完整功能测试
详细开发计划见 RCP_Development_Plan.md。
10. 相关文档
| 文档 | 内容 |
|---|---|
| RCP_10BASE_T1S_Architecture_Analysis.md | 架构分析 + 选型 |
| OA-RCP协议详解.md | OA RCP 协议基础 |
| Arduino_10BASE_T1S_Compilation_Architecture_Deep_Dive.md | 编译架构基础 |
| Arduino_IDE_Build_System_Internals.md | 构建机制深入 |
参考资源: