第三十周工作总结
概述
在完成设计文档与实现计划后,本周实现了 K3 RT24 rcpu1 极简固件的全部代码——从 CCU 时钟链、PXA-UART 驱动、pinmux 配置到 Chip/TimerChip trait 实现,以及独立的 K3 app crate 与构建脚本。同时完成了一次重要的 platform 层重构:用 Chip::board_init() 替代了对外暴露的 extern "C" _board_init 弱符号模式,使 chip 初始化成为标准 trait 方法。全部改动已通过编译+符号验证,合并入 main 分支。
20 个文件、+1580/-62 行,产物:k3-minimal bin——编译出 ELF(entry=0x100804000),经 objcopy 即可生成刷板固件。
1. chip-k3-rt24 完整实现
1.1 硬件初始化序列(7 步,main.c 已验证)
| 步 | 操作 | 对应文件 |
|---|---|---|
| 1 | SPL 握手回写 write32(0xc088007c, 1) | clock.rs |
| 2 | 上游 ruart_14 DDN gate | clock.rs |
| 3 | UART0 末端 gate + mux 选择 | clock.rs |
| 4 | pinmux:GPIO_122/123 → MUX_MODE4 | clock.rs |
| 5 | 波特率/帧格式(8N1, 115200) | uart.rs |
| 6 | UUE 单元使能(PXA 专属,最易漏) | uart.rs |
| 7 | put_str 轮询 THR | uart.rs |
这 7 步在 clock::early_init() + uart::init() 中完成,经 _board_init → Chip::board_init() 链在用户 main 之前执行。
clock.rs 中的寄存器常量(ruart_14 gate num/den、uart0 mux/div)均与 ESOS 源码 ccu-spacemit-k3.c 逐项交叉验证。
1.2 Chip + TimerChip(stub)
K3 特殊的 TimerChip stub 决策:minimal 阶段无定时器任务,但 platform::start() 必然调 TimerChipImpl::enable_timer_irq()——若不注册 TimerChip 实现,链接报 undefined symbol。因此实现空 stub(enable_timer_irq / set_alarm 为空操作),rtimer 寄存器映射留给后续。
Chip trait 的 put_str 直接调 uart::putc,board_init 串起 clock::early_init + uart::init。shutdown 用 wfi 循环替代(RT24 无 SiFive Test 设备)。
2. Platform 层重构:Chip::board_init()
2.1 问题
初版设计用 link.x PROVIDE + #[no_mangle] extern "C" fn _board_init() 作为 chip 钩子机制:
- arch crate 提供
_default_board_init(空),link.xPROVIDE(_board_init = _default_board_init) - chip crate 用强
_board_init覆盖
这虽然可行,但 _board_init 是一个脱离 trait 体系的裸 extern "C" 函数——调用方(platform)和实现方(chip)之间没有 Rust 类型约束,也没有文档化的接口契约。
2.2 方案
在 Chip trait 中增加 board_init() 方法(带默认空实现),platform 通过 ChipImpl::board_init() 调用。chip crate 在 impl Chip for K3Rt24 中重写该方法即可。
优势:
- Rust trait 提供编译期类型检查,实现方不匹配即编译失败
- 所有 chip 初始化统一走
Chiptrait,新 chip crate 只需impl Chip,无需理解 link.x 弱符号机制 - 调用方代码
ChipImpl::board_init()自文档化
2.3 设计演进:为什么经历了 .weak → PROVIDE → trait 方法
| 方案 | 问题 | 教训 |
|---|---|---|
.weak (asm) + #[no_mangle] | rustc 1.97 符号合并器拒绝「同名符号既被 .weak 又被 #[no_mangle] 定义」 | 裸 ld 验证通过 ≠ rustc 驱动链接通过 |
link.x PROVIDE | 可行但脱离 trait 体系,接口不明确 | 作为最终方案的中间态验证了覆盖机制 |
Chip::board_init() trait 方法 ✅ | 无 | trait 是 Rust 的标准抽象机制 |
3. 独立 K3 app crate 与构建链
3.1 架构隔离
新建 apps/rt-async-k3 crate,与 QEMU apps/rt-async-app 完全隔离:
- 各自 memory.x(K3:
0x100804000,QEMU:0x80200000) - 各自 target triple(共用
riscv64imac-unknown-none-elf) - K3 app bin 通过
#[used] static引用chip_k3_rt24::K3Rt24,确保 chip rlib 被链接器拉入
3.2 构建脚本
scripts/k3-build-minimal.sh:
cargo build -p rt-async-k3 --bin minimal --release
riscv64-elf-objcopy -O binary \
target/riscv64imac-unknown-none-elf/release/minimal \
target/riscv64imac-unknown-none-elf/release/rt24_os1_rcpu_rtasync.bin产物 .bin 可直接替换 esos.itb 中 rcpu1-fw 节点,经 SPL rproc_load/rproc_start 唤醒 RT24。
3.3 xtask 统一命名
xtask build 统一 bin 命名为 <platform>-<bin>(如 qemu-demo、k3-minimal),K3 构建产物为 ELF 而非 bin(objcopy 留给脚本,因需刷板前确认)。
4. 验证
| 验证项 | 方法 | 结果 |
|---|---|---|
| K3 ELF entry | riscv64-elf-readelf -h | 0x100804000 ✅ |
_board_init 强覆盖 | riscv64-elf-nm | T(强符号),解析到 clock::early_init + uart::init ✅ |
| QEMU 未回归 | cargo build -p rt-async-app | _board_init = T 回退 PROVIDE 默认空实现,行为不变 ✅ |
| 编译告警清零 | cargo build -p rt-async-k3 | 移除未使用的 Priority 导入与 feature 后零告警 ✅ |
5. 本周在 K3 迁移中的位置
对应 项目计划-20260528 K3 适配第一阶段,与上周(二十九周)"下周计划"对齐:
| 上周计划项 | 本周状态 |
|---|---|
| 定位 UART 输入乱码根因 | 🟡 已确认疑似硬件问题,待新 CH340 到货对照 |
实现 PXA-UART Chip::put_str + CCU 时钟使能 | ✅ 完成(clock.rs + uart.rs,7 步初始化) |
| 目标:R_UART0 看到 rt-async 启动日志 | 🟡 ELF 已就绪,待刷板验证 |
从软件侧看,K3 RT24 rcpu1 极简固件的全部代码已经完成——下一步就是刷板验证,在真实硬件上看到 hello from rt-async。
6. 下周计划
- 刷板验证:将
k3-minimalbin 打包进esos.itb,在 K3 板子上验证 rt-async 启动日志 - TimerChip 真实现:研究 rtimer0 寄存器映射,实现
set_alarm/enable_timer_irq,让调度器时钟跑起来 - PLIC 适配:改址
0xe0000000,验证中断通路 - 目标:RT24 上跑通完整的 rt-async 调度循环(定时器中断 → 任务切换)