Skip to content

第三十周工作总结

概述

在完成设计文档与实现计划后,本周实现了 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 已验证)

操作对应文件
1SPL 握手回写 write32(0xc088007c, 1)clock.rs
2上游 ruart_14 DDN gateclock.rs
3UART0 末端 gate + mux 选择clock.rs
4pinmux:GPIO_122/123 → MUX_MODE4clock.rs
5波特率/帧格式(8N1, 115200)uart.rs
6UUE 单元使能(PXA 专属,最易漏)uart.rs
7put_str 轮询 THRuart.rs

这 7 步在 clock::early_init() + uart::init() 中完成,经 _board_initChip::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::putcboard_init 串起 clock::early_init + uart::initshutdownwfi 循环替代(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.x PROVIDE(_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 初始化统一走 Chip trait,新 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

bash
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.itbrcpu1-fw 节点,经 SPL rproc_load/rproc_start 唤醒 RT24。

3.3 xtask 统一命名

xtask build 统一 bin 命名为 <platform>-<bin>(如 qemu-demok3-minimal),K3 构建产物为 ELF 而非 bin(objcopy 留给脚本,因需刷板前确认)。

4. 验证

验证项方法结果
K3 ELF entryriscv64-elf-readelf -h0x100804000
_board_init 强覆盖riscv64-elf-nmT(强符号),解析到 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. 下周计划

  1. 刷板验证:将 k3-minimal bin 打包进 esos.itb,在 K3 板子上验证 rt-async 启动日志
  2. TimerChip 真实现:研究 rtimer0 寄存器映射,实现 set_alarm / enable_timer_irq,让调度器时钟跑起来
  3. PLIC 适配:改址 0xe0000000,验证中断通路
  4. 目标:RT24 上跑通完整的 rt-async 调度循环(定时器中断 → 任务切换)