Skip to content

rt-async-amp:面向异构多核 SoC 的 AMP 双内核实时系统技术报告

由于面向吞吐与通用性的设计取向,Linux 等通用操作系统难以提供实时任务所需的确定性;在异构多核 SoC 日益普及的背景下,实时补丁侵入性强、hypervisor 方案开销大,既有方案难以在保留通用软件生态的同时满足实时性需求。本报告介绍 rt-async-amp,一个面向异构多核 SoC 的 AMP 双内核系统:通用大核(AP)运行 Linux 兼容内核(StarryOS),实时小核(RP)运行自研的 Rust async RTOS(rt-async),两核经共享内存与硬件邮箱或核间中断协作。系统以进迭时空 K3 SoC 的 RT24 实时小核(CVA6/RV64GC)为目标平台,同时维护 QEMU 仿真验证路径。本系统有几个关键设计:首先,基于系统分解思想,将实时域从通用内核中剥离到独立小核,AP 侧通用内核基本保持原状;实时侧 RTOS 全部以 Rust 编写,无标准库依赖、无动态内存分配,以语言级类型安全与内存安全为基座,板级驱动经设备树运行时探测实例化,引脚复用与时钟使能在驱动 probe 前自动完成。其次,设计了覆盖内核态与用户态的跨核通信栈:共享内存通道库与跨核 RPC 提供双端对齐的传输与调用语义,共享内存窗口经双端设备树探测认领,用户态经 mmap 系统提供的设备文件,能在用户态实现零中断开销的双向通信;最后,构建工具链与设备树宏编译链配合环境配置文件统一了 QEMU 仿真与 K3 真板两者,并通过实际的机器人控制应用验证了系统的端到端可用性。


1. 动机:隔离,而不是改造

实时任务要求的不是平均延迟低,而是最坏延迟有上界。通用操作系统为吞吐和公平性设计:中断有关闭区间,调度器要服务上百个任务,锁有优先级反转,缺页、内存回收、时钟 tick 都会带来不可预测的停顿。这些机制对通用负载是优点,对实时负载全部是抖动来源——它们叠加之后,最坏延迟无法枚举,也就无法给出保证。

在通用内核上改善实时性有两条常见的路,各有边界。PREEMPT_RT 一类实时补丁把内核中主要的关中断区间和锁改成可抢占,确实能大幅压低延迟,但它侵入内核的各个子系统,必须跟着上游版本持续重做;而且最坏延迟仍受制于为吞吐设计的机制(调度器的负载均衡、内存管理的停滞区间等),给不出严格上界。Hypervisor 分区用虚拟化把实时虚拟机和通用虚拟机隔开,但虚拟化层自身带来固定的陷入/陷出开销和第二层调度,复杂度和开销都不低;RT24 这样的小核内存以百 KB 计、主频两百多 MHz,承载不起一个完整的虚拟化层。

本项目的做法是第三条路:把实时域整体搬到一颗独立小核,隔离而不是改造。AP 上的通用内核一行不改,软件生态原样保留;实时任务在 RP 上裸金属运行,没有调度噪声、没有页错误、没有动态内存,路径确定;两核之间只保留共享内存和门铃中断两种交互,交互的每一笔开销都可以单独测量、单独核算。K3 恰好提供了合适的硬件条件:RT24 小核有自己的 RCPU SRAM、mailbox 和中断控制器,与 AP 域只通过有限的硬件通路相连,把实时域放进去,两边互不打扰。

延伸阅读:本项目 RTOS 的前身与性能动机见《embassy_preempt 性能测试报告》

2. 系统总览:一颗芯片,两个内核

系统由三个部分组成:AP 大核域、共享资源、RP 实时小核域。

AP 大核域:StarryOS(Linux 兼容内核)与用户态程序。用户态程序目前有 rtsh(跨核 shell,见 §13)、robot-py(Python 扩展,见 §13)和 user-test-* 系列测试程序。跨核访问对用户态的呈现是一个设备文件 /dev/rt_shm:mmap 得到共享窗的映射,ioctl 触发门铃和等待。内核侧对这个设备的实现刻意保持薄——只做 mmap 与 ioctl 转发,不做协议处理,协议逻辑全部在用户态库中,换协议不必改内核。

共享资源:一块共享内存窗口和一对 mailbox 门铃。窗口物理基址 0xC080_0000、大小 0x19000,划分为全局头 0x100 加三个通道(各 0x8200)加余量 0x900;三个通道分别是 CH0 请求、CH1 响应、CH2 急停。门铃用 mailbox4(基址 0xCAC9_1000):AP 发 RP 收走 IRQ 69,RP 发 AP 收走 IRQ 217。除此之外两核没有其它交互通路。

RP 实时小核域:rt-async 执行器裸金属运行。固件从 SPL 握手接手后被拉起,设备树内嵌在固件 ELF 里,外设和共享窗都在运行时经设备树 probe 认领。probe 顺序有两条约束:pinctrl 控制器和 CCU 时钟控制器必须排在外设之前,这样任何外设驱动 probe 时,引脚复用和功能时钟已经配好——驱动自己不用关心这两件事。固件任务按优先级组织:机器人控制任务是 P1,RPC 分发 task_ipc 是 P2,magic 看门狗是 P3。

构建与部署:构建工具链 xtask 把环境当一等公民——qemu-plic(快速冒烟)、qemu-aia(AIA 中断架构仿真)、k3-com260(真板),产物按环境隔离在 build/<env>/ 下;设备树源用 cc 宏展开加 dtc 求值两级编译。真板部署分三步:opensbi.itb 烧入 opensbi MTD 分区(包含共享窗的 PMA 翻转,见 §8),固件打包成 esos.itb 烧入 esos 分区,AP 内核 starryos.uimg 由 U-Boot bootm 直接引导、不落 flash。

QEMU virt 双核与 K3 真板跑同一套协议库与固件代码,仿真里得到的结论在真板上同样成立。

延伸阅读:K3 的 FIT 单文件烧录与可编辑设备树见《K3 COM260 Kit 刷机流程:FIT 单文件烧录 + 可编辑设备树》;设备树 handoff 与驱动注册框架见《rt-async 驱动架构现代化:设备树 handoff + Driver Model》《K3 RT24 rcpu1:从 Chip 硬编码到 Board + Driver Model》

3. RT 内核:rt-async 执行器

rt-async 是一个独立 workspace 的 no_std 异步内核,模块划分为 executor(调度核心)、executor-macro(#[task] 过程宏)、futures(定时器等基础 future)、platform(板级契约层:Driver trait、Slot、设备树 probe)、timer。

调度上有四个要点:

  • N 级抢占:每个任务有静态优先级,就绪队列用优先级位图组织,选下一个任务是 O(1),与任务总数无关。高优先级任务就绪时立即抢占当前任务,抢占可以嵌套——执行器用优先级栈记录被抢占的层级,逐层恢复。
  • 定时器:定时器队列挂在 mtime 上,任务可以休眠到指定时刻或带超时等待;到点由定时器中断唤醒,按 deadline 排序插入。
  • 空闲进 WFI:没有就绪任务时执行 wfi 指令睡眠,等中断唤醒,空闲功耗和唤醒延迟都可预期。
  • 静态内存:任务控制块、栈、队列全部编译期静态分配,没有堆,也没有运行时的动态分配;共享状态用 static 加原子量或 Slot(单写槽)承载。

原子操作在 K3 上分两种代价相差悬殊的实现。K3 专属 target(atomic-cas: false)没有原生 RMW 指令,core 的原子操作经 portable-atomic 的 critical-section 回退实现——关中断后读改写,单次约 90ns;跨核共享窗上的原子操作不用 RMW(跨核 RMW 要经互连序列化,单次约 2.2µs),改为普通读写加显式 fence(见 §8)。两个数量级的差距形成了明确的使用原则:RP 本地的数据结构尽管用原子操作,跨核协议里的每一次 fence 都要有理由。

延伸阅读:执行器的架构设计与跨平台适配见《技术报告 2025-11》《技术报告 2026-04》;一次由锁与中断交互不当引起的死锁见《一次 AMP 死锁排查:spin::Mutex 不关中断与 ring buffer 直读》

4. 跨核通道:SPSC 环 + 块层

通道库 ov-channels 在共享窗上实现单生产者/单消费者环形队列,是全部跨核通信的地基。

窗口布局:全局头 0x100 放 magic(0x4F56)与协议版本(v2),双端建环时校验,防止两端布局不一致还继续跑。其后三个通道各占 0x8200:通道头部是环的读写索引等元数据,槽区从通道内偏移 0x100 开始,128 个槽、每槽 256B。窗口总占用 0x100 + 3 × 0x8200 = 0x18700,窗口申请 0x19000,留 0x900 余量。

发布协议:生产者先把整条消息写进槽,再以 Release 语义推进发布索引;消费者以 Acquire 语义读索引,看见索引就看见数据。索引由单写者推进,不需要跨核互斥——SPSC 的约束换来的是整个通道没有一个锁操作。跨核读必须带 fence:litmus 实验表明不带 fence 的普通读会被前端合并缓冲固定在陈旧值上(200 次中 0 次读到新值),不存在不花钱的刷新方式。

块层:短消息(≤251B 载荷)占一个槽,走单块路径。长消息拆成多块接续传送,首块标志字节的 bit7 是 CONT 标志,最多 8 块、合计载荷 ≤2028B。发送侧提供 try_send_raw 前缀写:先写长度字段、再写载荷,最后一并发布——接收方看到的要么是完整消息,要么是没有消息,不存在半条消息。

急停通道:CH2 与 CH0/CH1 的普通队列完全独立,urgent 消息不排队等前面的消息处理完,机器人急停(见 §13)走这条路。

两次跨核协议故障的排查(假死与死锁)指向同一类根源:中断原子性与协议标志位的状态机不完备、锁与中断的交互不当,详见延伸阅读。

延伸阅读:缓存属性、中断原子性、协议标志位三层排查一次跨核 IPC 假死见《一次 AMP IPC 挂死的三层排查》;锁引起的死锁见《一次 AMP 死锁排查》

5. 语义 RPC:四种形态 + 按名调用

RPC 库 ov-rpc 架在通道之上,把"函数调用"语义铺到跨核环境,四种形态覆盖不同的需要:

形态语义典型用途
call请求 + 阻塞等响应ECHO、PING、遥测查询
send单向发送,不等响应触发类命令
urgent急停,独立通道不排队机器人急停
acallhandler 立即返回,完成由高优先级任务稍后补发响应耗时的设备初始化与动作序列

acall 的完整流程:客户端照常发出请求并拿到一个响应 id(rid);服务端 handler 只入队或置标志就返回;真正的执行由 P1 高优先级任务完成,完成后带着 rid 把响应写回 CH1;客户端用 rid 匹配到等待者,唤醒调用方。这样耗时几秒的动作序列不会占住 RPC 分发任务,也不会影响其它请求的处理。

响应路径按"不做多余动作"实现:响应缓冲就地构造(MaybeUninit 包裹、不初始化用不到的字段),序列化原地完成,经前缀写一次发布。大响应走块层分块(8 块 ≤2028B)。错误路径做 poison 处理:通道进入错误状态后服务端拒绝新请求并返回明确错误码,客户端能感知故障并重建会话,不做静默重试——把错误暴露出来,不让它在暗处蔓延。

内核态与用户态用同一套 ABI(ioctl 常量定义在 rtshm-abi,与内核侧 tgoskits 的实现双仓对齐),协议库不需要为两种环境写两份。

6. 服务发现:INIT 一次往返,方法表自动对齐

跨核 RPC 最容易出错的地方是两端方法表不一致:固件加了方法、改了编号,客户端还按旧表调用,轻则参数错位,重则写坏通道。服务发现把这个问题从约定变成机制。

方法号 0 保留给 INIT,任何服务都占用不到它。客户端启动时发一条 INIT 请求,服务端在进入正常分发之前拦截 0 号,把编译期生成的服务描述符经响应通道发回:

text
[协议版本][描述符长度][方法数] + 每方法 [方法号][标志位][名称长度][名称]
标志位:bit0 单向(send)· bit1 急停(urgent)· bit2 异步完成(acall)

客户端解析后得到方法名到方法号的映射和每个方法的形态标志,此后全部调用按名查号,一次往返、之后不再重复。固件更新导致方法号变化时,客户端不用重新编译——重启后重新发现一次就对齐了。

rtsh 启动即做发现并列出方法表。当前机器人服务共 18 个方法:底盘与机械臂的控制、遥测、诊断,加两条 raw UART 读写(bring-up 排障用);其中 14(CHASSIS_INIT)、17(ARM_GRAB)、18(ARM_RELEASE)三个是 acall。

7. 请求发现:四条路径与弹性自旋

AP 发出请求后,RP 侧怎么"发现"这条请求,决定了延迟的量级。按 RP 的忙碌状态自然形成四条路径:

路径场景机制实测
D1 门铃唤醒冷路径:空闲超过自旋窗口(约 2s),RP 在 WFI 睡眠mailbox 中断 → trap + 调度 + 派发往返 236.9µs;门铃单次 3.46µs
D2 弹性自旋热路径:请求间隔 <2stask_ipc 轮询读索引,约 9.4µs/轮,不用门铃、不进内核往返 189µs
D3 批处理同一唤醒窗口内到达多条请求合并处理,摊薄唤醒成本
D4 防竞态门铃发出的瞬间对端恰好切到自旋处理循环收尾前再查一轮索引不丢消息

D1 与 D2 之间的切换是自适应的:请求来得密,task_ipc 保持自旋,省掉每条消息的中断和唤醒(这一段合计约 40µs,其中 mailbox 排空 3.6µs、trap+调度+派发 27.1µs);请求间隔拉大,自旋不再划算,任务回 WFI 睡眠,下一条请求由门铃唤醒。D4 处理的是一个窄窗口竞态:RP 决定去睡、门铃已经发出的瞬间,中断可能被错过——处理循环在收尾前再查一轮索引,把这种情况兜住。

W2 是这一方向的下一步:AP 收响应的方向同样改成用户态轮询,省掉 AP 侧的系统调用和内核唤醒,固件不用改。预演已实测 D2 往返 189→178µs(−11µs),待合入。

延伸阅读:四条路径的测量方法与归因见《K3 IPC 延迟归因与优化总结报告》

8. 共享窗一致性:固件改 PMA,软件不做缓存维护

共享窗要能当通信介质用,前提是两核看到的内存内容一致。K3 上这件事有一个平台级的坑,分三层说清楚。

问题:X100 这颗硅忽略 Svpbmt 页表位。软件无论在页表里把共享窗标成何种缓存属性,硬件一律按 cacheable 处理。于是 AP 写进窗口的数据(包括发布索引)先停在大核的缓存里,RP 直接读 SRAM 拿到的是旧值——发布的更新永远到不了对端,协议出错、环形队列卡死。这不是性能问题,是正确性问题;软件层改不了映射属性,唯一的入口是物理地址属性(PMA)。

证据:判窗工具 user-test-pbmt(AP 用户态)与 pbmt_probe(RP 固件)在内核态、用户态两路实测,PBMT 均不生效。排查期间还定性过一个相关缺陷(cbo.flush 静默丢发布,08-23 报告附录 B 有完整记录),随缓存属性方案的更换而消失。

当前方案:OpenSBI 固件在 final_init(每个 hart 各做一次)里定位覆盖窗口 [0xC080_0000, 0xC088_0000) 的 PMA 表项,把属性翻为 IO(0x22),实现物理非缓存;翻转前先清一遍窗、再做 sfence.vma,防止 SPL 阶段遗留的脏缓存行在翻转后乱序回写。物理非缓存之下,两核读写都直达 SRAM,软件不需要任何缓存维护指令——2026-08-26 起,内核 rt_shm 的同步点、用户态的 cbo 放行、FLUSH ioctl、somehal 的 senvcfg 设置全部移除,各层代码里不再出现缓存维护操作。

部署约束:板上必须刷这套定制的 opensbi.itb。官方固件下窗口是 cacheable 的,跨核协议不可用——这是硬性依赖,换官方固件协议就坏。QEMU 的 TCG 没有 dcache,仿真路径不需要处理这件事。X100 忽略 Svpbmt 已作为平台问题向厂商反馈。

延伸阅读:缓存属性误判引发跨核 IPC 假死的三层排查见《一次 AMP IPC 挂死的三层排查》;A4 缺陷完整记录见《K3 IPC 延迟归因与优化总结报告》附录 B;40pin UART 与核间通路等平台问题见《K3 平台开发问题反馈》

9. 端到端延迟:294 → 236.9 µs

延迟数字来自 2026-08-16 至 08-23 八天里约 20 轮真板测量,测量载体是 user-test-bench 的 dd 场景(AP 发起、RP 回显的 PING 往返),每轮 30 次采样。单条 PING 往返从最初的 294µs 降到 236.9µs,降了 19.5%。过程中 P1(自旋窗口)之后取过一次完整的分段基线 240.1µs;P3(fence 去冗余)在同一次启动内做 A/B 对比,246.9→236.9µs,确认每条消息省 10µs。

当前三个代表性数字:

指标数值说明
D1 门铃唤醒往返236.9 µs(最初 294 µs,−19.5%)真板实测 p50
D2 弹性自旋稳态189 µs间隔 <2s,不进内核
W2 双向轮询预演178 µs(−11µs)已实测,待合入

D1 的八段分解(µs;分段基线 240.1,当前 236.9,构成相同):

数值含义
send8.5AP 写槽发布
ddrain3.6mailbox 排空
ddisp27.1trap+调度+派发
dpre24.3发现前缀(set_busy + ch2 查)
drx45.6取包 try_recv
dserde38.0分发反序列化
S67.7服务尾 + 响应门铃
APret25.3AP 唤醒回收

这个分解不是估的:每一段都有插桩实测,八段相加与总延迟一致(闭环恒等式残差 30/30 = 0.0)。延迟不仅低,而且可复现——同一次启动内重复测量的标准差只有 0.16µs。

延伸阅读:每一段的测量方法、八天的完整优化过程(哪些措施有效、哪些被证伪及原因)见《K3 IPC 延迟归因与优化总结报告》

10. 微架构单价

把跨核路径上每种操作的单价单独测出来,优化就有了预算依据——一条消息还能快多少,把构成段乘以单价就能算出来;算不出余量的地方,就是硬件的边界。实测单价如下:

操作单价说明
fence2.2 µs/次,与冷热、地址无关四种测量方式结果一致(2198–2222ns);热路径 14 次/消息 ≈ 31µs;P3 去冗余后剩 4 次 ≈ 8.8µs,端到端实测每条消息 −10µs(A/B:246.9→236.9),顺序保证不变
门铃(mailbox MSI)3.46 µs/次单次触发成本;D1 唤醒链合计约 40µs
mtime 冷读24.5 µs(热读 106ns 的 231 倍)跨时钟域同步器重新锁定;间隔超过约 20µs 即冷;既占预算,也污染分段测量
mcycle CSR冷读 ~2.9ms,热读 17ns计数器冷热差距的极端对照
256B 槽写 / 块读6.3 µs / 1.2 µs写比读贵 5 倍
MSIP 写~54 µs经互连生效,是唤醒链的物理下限
本地原子~90 nscritical-section 回退;跨域原子 ~2.2µs
D2 自旋单轮9.4 µs/轮P3 前 18µs

两个单价值得展开。fence 恒定 2.2µs、与冷热和地址无关,说明它是互连访问的固定成本,软件只能减少次数、不能降低单价——P3 把热路径从 14 次减到 4 次就是这个逻辑。mtime 冷读 24.5µs 是最隐蔽的一笔:只要两次读之间隔了约 20µs 以上,跨时钟域同步器就要重新锁定;它一方面是生产路径的真实开销(一条消息 1-2 次、约 24µs),另一方面会让所有不加分辨的分段测量平白多出这段时间——归因报告里专门用一节处理它的干扰。

延伸阅读:每种单价的实测方法与数据表见《K3 IPC 延迟归因与优化总结报告》;fence 固定开销已作为平台问题反馈厂商,见《K3 平台开发问题反馈》

11. RP 侧单消息预算:约 91 µs

把 §10 的单价落到一条消息上:RP 处理一条消息约 91µs(dd 插桩实测、剥离插桩自身开销后;插桩每段要多付一次 mtime 冷读,约 24µs,不计入)。

分组数值构成
通道与门铃21.0 µs弹性前缀 11.0(set_busy、查急停通道)+ ch2 收尾 6.6 + 门铃 notify 3.4
取包与响应发送34.9 µs共享窗槽读/槽写,各带 4 次 fence(槽读 1.2µs、槽写 6.3µs)
分发11.0 µs方法匹配 + postcard 反序列化
生产计时开销24.0 µs处理路径读写 mtime 1-2 次,是当前实现的真实构成

14 次 fence 的分布:弹性前缀 4 次、取包 4 次、响应发送 4 次,其余在链路环节。每一微秒花在哪里都有实测数字;再往下压,剩余的空间属于硬件选项(更快的门铃通路、免共享窗的小消息直传),不属于软件未知项。

延伸阅读:逐项分解的原始测量见《K3 IPC 延迟归因与优化总结报告》

12. 实时性小结

把延迟相关的结论收拢成三句话:

  • 延迟有界且可复现。D1/D2 往返 236.9 / 189µs,同一次启动内重复测量的标准差 0.16µs;八段分解相加与总延迟一致,30 轮闭环残差全为零。数字不是采样运气,是系统性质。
  • 每一笔开销有出处。协议本体 fence ≈8.8µs(剩余 4 次/条)+ 数据搬运 ≈7.5µs + 任务模型固定开销 ≈27µs + 唤醒链物理下限 ~54µs;要继续压,压哪里、能压多少都算得出来。
  • 确定性来自结构。全程无动态内存(没有分配失败与整理停顿);D2 路径不进内核(没有系统调用与调度叠加);本地原子不进内核;跨核交互只有共享内存与门铃,两者都测过单价。

13. 应用验证:机器人控制端到端

系统在真板上控制一台带机械臂的小车,覆盖从 AP 用户态程序到 RP 固件再到执行器的完整链路。

执行器通道:底盘控制板走 Tt 二进制协议(帧头 AA 55 加长度与校验),RP 用 R_UART0(40pin 的 pin29/32,经板载电平转换 1.8V→3.3V)收发;机械臂是 ZP10S 舵机,ASCII 协议,经 AP 域 UART5 的 TX 引脚(pin3)逐字轮询下发,TX-only、帧级约 1.3ms。

任务模型:固件里两个 P1 任务各管一路执行器,都是 10ms 固定节拍(timer::after(10ms) 驱动)。task_chassis 每个节拍按优先级做三件事:处理挂起的底盘 INIT(INIT→CONFIG 两段带应答事务,ACK 后补发 acall 响应);有停车/刹车请求立即下发(优先于速度);速度设定值变化才下发(RPC handler 只写 setpoint 加脏标志就返回,实际下发在一个节拍内完成)。每 10 拍(100ms)做一轮遥测——编码器累计脉冲加实时转速,快照最多陈旧 100ms。task_arm 消费命令队列:单舵机角度、力矩释放/恢复、以及抓取/放开的多步序列(张开夹爪 → 0.5s → 夹取位姿 → 1s → 闭合 → 2s → 抬起,步间用 async sleep 对齐 AKA-00 的时序,抓取全程约 4.5s)。

实时边界:RPC 分发 task_ipc 是 P2,低于两个控制任务——控制回路永远优先于通信流量。三个 acall 方法(CHASSIS_INIT / ARM_GRAB / ARM_RELEASE)的 handler 只入队或置标志,执行与完成都在 P1 的节拍里,异步完成的延迟不超过一个节拍(≤10ms),且这个上界与 RPC 负载无关。急停独立走 CH2 urgent 通道,不排普通队列;magic 看门狗在 P3 兜异常。控制节拍不是空转轮询:没有待办时任务只做几次原子读就睡回定时器,空闲成本微秒级。

用户态两种形态(同一套 rtsh 库层):

  1. 二进制程序rtsh 不带参数进 REPL(提示符 rtsh>,help 查看命令,quit 或 Ctrl-D 退出);带参数单发执行一条即退出(rtsh drive 30 30rtsh grab),适合脚本和快捷调用。启动即服务发现,全部命令按方法名解析。
  2. Python 库:robot-py 把 rtsh 库层用 PyO3 编译成原生扩展(cdylib 模块 robot),from robot import Robot 后在 Python 代码里直接调用,不经子进程、不经管道。所有等响应的调用在等待期间释放 GIL(grab 阻塞约 4.5s 也不会卡住解释器其它线程);超时经 ppoll 实现,全程不用信号,与 signal 模块不冲突;Rust 侧的错误一律抛 RobotError 异常。接口名对齐 AKA-00 的 MotorPairProtocol / ServoProtocol(init / set_speed / brake / get_encoder / set_angle / grab / release 等),从旧封装迁移的代码改个 import 即可。

板侧程序部署走局域网 HTTP(wget 拉取)。硬件排障记录(R_UART0 的电平转换与上拉特性、软串口中断号证伪)见周报。

延伸阅读:R_UART0 电气特性与引脚分配的查证结论见《周报三十四》《周报三十五》;40pin 扩展口仅一路 R_UART 等平台限制见《K3 平台开发问题反馈》;K3 板级驱动调试的一般教训另见《K3 GMAC 网卡驱动调试教训》

14. 总结与展望

总结。架构上,实时域整体搬到独立小核:AP 侧内核不做修改,通用软件生态原样保留;RP 侧 RTOS 全部 Rust 编写、无标准库依赖、无动态内存分配,语言级的类型与内存安全加上设备树驱动的自动配置,把板级代码的出错面压到尽量小。通信栈上,共享窗通道(SPSC 环 + 块层)、语义 RPC(四种形态 + 按名服务发现)、门铃四条路径分层清楚,内核态与用户态同一 ABI,双端设备树探测对齐。数据上,跨核往返从 294µs 降到 236.9µs,每一微秒的构成有实测数字,各段相加与总延迟一致。

展望

  1. W2 双向轮询合入。预演已在真板实测:D2 189→178µs;合入后 D1 预计约 219µs、D2 约 168µs。
  2. 硬件改进选项。小消息改走 mailbox 寄存器直传,省一次共享窗访问;硬件 spinlock 手册有记载(0xCAC9_1C00),可用于跨核互斥。
  3. 通信控制方式。小车目前用 UART 加控制板控制,后续可由 K3 直接输出 PWM,省掉控制板一级。

数据溯源