这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【E22P-433MBH-SC无线模块开发测试套件】用AI把裸机工程移植到Zep

共1条 1/1 1 跳转至页

【E22P-433MBH-SC无线模块开发测试套件】用AI把裸机工程移植到Zephyr:一次E22-433M30SLoRa演示工程的实践

高工
2026-09-26 17:00:29     打赏
用 AI 把裸机工程移植到 Zephyr:一次 E22-433M30S LoRa 演示工程的实践

摘要

本文记录了一次完整的 AI 辅助嵌入式工程移植实践:将亿佰特 E22-433M30S(SX1268,433MHz LoRa) 评估板的 STM32 HAL 裸机演示固件(Keil MDK 工程),移植到 Zephyr RTOS 4.4。整个过程由 AI 代理 主导完成——包括代码分析、方案设计、代码移植、编译调试,直到 J-Link 烧录和上板验证通过。 本文重点讲方法论:AI 是怎么一步步做的、哪些环节最关键、人机如何分工,以及相比原裸机工程, Zephyr 版的优缺点。


1. 任务背景

  • 原工程:STM32F103C8T6 + SX1268 LoRa 模组 + SSD1306 OLED(u8g2 图形库)+ 三按键菜单 (MultMenu 自研框架)+ PWM 蜂鸣器 + USB CDC。裸机无 RTOS,Keil/ARMCC5 构建, 代码含 GBK 编码中文注释、CubeMX 生成代码与手写代码混合。

  • 目标:在 D:\luglZephyrproject(Zephyr 4.4 工作区)下创建一个功能等价的 Zephyr 应用。

  • 约束:不改原工程、不改 Zephyr 内核;界面和操作习惯尽量与原 demo 一致。

这个任务的难点不在于"写代码",而在于两端的上下文都很大:原工程几十个源文件、 Zephyr 工作区几千个驱动/binding/示例。人来做需要数天调研;AI 来做,关键在于 先侦察、再决策、后动手。

2. 方法论:AI 移植的四阶段流程

侦察(Explore) → 决策(Plan) → 实施(Implement) → 验证(Verify)

2.1 侦察:并行子代理探索,只带结论回来

面对两个陌生代码库,AI 没有直接埋头读代码,而是并行派出两个只读探索子代理:

  • 子代理 A:解剖原工程。回答一组具体问题:main 初始化顺序、LoRa 参数默认值与配置序列、 菜单框架 API、按键扫描机制、u8g2 移植层做法、蜂鸣器 PWM 参数、引脚表、第三方库版本等。 产出一份带文件路径和行号的结构化报告。

  • 子代理 B:摸清 Zephyr 侧的能力。回答:SX1268 是否被 Zephyr 4.4 支持(哪个后端、 binding 有哪些属性)、LoRa 子系统 API 长什么样、有没有现成示例、STM32F103 用哪块板 (时钟/USB/flash 情况)、SSD1306/按键/PWM 在 Zephyr 的惯例写法、工作区怎么构建。

要点:探索代理返回的是"结论 + 关键代码摘录",而不是几千行源码 dump。 这既节省了主对话的上下文,也让后续设计建立在已核实的事实上(例如"TIM2_CH2 可以 重映射到 PB3"是 grep 过 pinctrl dtsi 才写进方案的,不是猜的)。

2.2 决策:先问对人,再写方案

侦察完成后,AI 识别出 4 个会实质改变架构的岔路口,没有擅自决定,而是让人类选择:

岔路口选项人类的选择
LoRa 实现Zephyr LoRa 子系统 vs 移植 Semtech 裸驱动Zephyr 子系统(代码少、跟内核走;代价是自定义同步字 0x14 用不了,新旧固件不互通)
OLED 界面完整移植 u8g2+MultMenu vs 用 CFB 重写简化菜单完整移植(保真优先)
USB CDC保留 vs 砍掉省 flash保留
小游戏移植 vs 不移植不移植(原工程里就是死代码)

然后 AI 把方案写成一份可检查的计划文档:目录结构、overlay 每个节点的写法、 每个移植层文件的职责、原接口到新 API 的映射表、构建命令、风险清单(含退路)。 人类批准后才动手。

要点:方案里的每一条都锚定在侦察阶段验证过的事实上;每个风险都附了退路 (例如"蜂鸣器 remap 若不生效,退到 PA1 飞线或 GPIO 软件 PWM")。

2.3 实施:coder 子代理一次性交付,构建闭环

实施交给一个 coder 子代理,交接材料是:批准的计划 + 侦察报告的浓缩版 + 明确的验收标准 (west build 零 error)。coder 完成了:

  • 工程骨架(CMakeLists / prj.conf / overlay / 构建脚本)

  • 第三方代码拷贝(u8g2 裁剪版、MultMenu,剔除游戏)

  • 5 个平台移植层文件(u8g2 I2C 回调、按键、蜂鸣器、LED、LoRa 应用层)

  • MultMenu 最小改动适配(HAL_GetTick→k_uptime_get_32 等符号映射)

  • 自己跑构建、自己修编译错误,直到通过,并报告 ROM/RAM 实测占用

coder 还主动解决了计划外的问题:板级 dts 默认开启的 usart2/usart3/i2c1/spi2 与本工程 引脚冲突需要关闭;SRAM 只有 20KB,需要逐项压缩栈和 USB 缓冲。

2.4 验证:AI 复验构建 + 烧录,人类做硬件裁判

  • AI 亲自复跑构建和 rom_report/ram_report,不轻信子代理的报告;

  • 用 J-Link 烧录时遇到真实问题:Zephyr 默认传 STM32F103C8(64KB)给 J-Link, 86KB 固件被拒 → AI 诊断后改用 STM32F103CB(128KB 兼容型号)完成烧录;

  • 上板功能验证由人类完成:Rx 接收测试通过(菜单可收包、显示 RSSI 和丢包统计)。

分工原则:AI 负责一切可在工具链内闭环的验证(编译、静态资源占用、烧录校验), 人类负责物理世界的最终裁判(屏幕亮不亮、能不能收到包)。

3. 移植过程实录:关键映射

3.1 运行时结构

裸机:  main while(1) { Menu_Task(); }  + SysTick 1ms 中断扫键 + EXTI3 中断内直接 SPI 读包
           ↓↓↓
Zephyr:菜单线程(key_scan_tick + Menu_Task + k_msleep(2))
       + LoRa 驱动 IRQ → 系统工作队列回调(只做 memcpy + 置标志)

原工程在最高优先级中断里做整套 SPI 读包,是裸机的典型写法;Zephyr 版把这项工作 下沉到驱动和工作队列,应用层完全没有中断上下文代码。

3.2 硬件描述:从 C 代码到 Devicetree

原工程散落在 gpio.c/spi.c/main.h 里的引脚定义,在 Zephyr 版收敛为一个 overlay 文件 (boards/stm32_min_dev_stm32f103xb.overlay):

lora_sx1268: sx1268@0 {
compatible = "semtech,sx1268";
reset-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>;
busy-gpios  = <&gpiob 1 GPIO_ACTIVE_HIGH>;
dio1-gpios  = <&gpioa 3 GPIO_ACTIVE_HIGH>;
tx-enable-gpios = <&gpiob 12 GPIO_ACTIVE_HIGH>;  /* 射频开关 */
rx-enable-gpios = <&gpiob 13 GPIO_ACTIVE_HIGH>;
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_3V3>;      /* TCXO 供电 */
tcxo-power-startup-delay-ms = <5>;
force-ldro;
};

原工程 e22_demo_init() 里 20 余行逐条下发的寄存器配置(TCXO、DCDC、射频开关、 复位序列),全部由内核驱动根据这份描述自动完成。

3.3 应用层:接口不变,实现换芯

e22_demo.c 对外接口(e22_demo_init/menu_config/transmit/receive/check_rx_done) 与原工程完全一致,菜单代码零感知;内部从 20+ 个 sx126x_* 寄存器调用换成 5 个 Zephyr API(lora_config/lora_send/lora_recv_async 等)。发射功率换算 (30→12dBm 等)等应用层知识原样保留。

3.4 界面:最大程度复用

u8g2(裁剪版 43 个源文件)和 MultMenu 菜单框架整体拷贝、近乎零改动—— 只重写了 u8g2 的 I2C 字节回调(约 100 行)和按键/延时等胶水层。 菜单树、PID 光标动画、Tx/Rx 测试状态机、丢包统计全部原样工作。

4. 成果

指标结果
构建west build 零 error
FLASH 占用86656 B / 128 KB(66%)
SRAM 占用20200 B / 20 KB(98.6%,余量约 263 B)
烧录J-Link 校验通过(87040 B)
上板验证Rx 接收测试通过(OLED 菜单操作、收包、RSSI/丢包显示正常)
新增手写代码约 1000 行(6 个移植层文件 + overlay + 配置),复用代码约 3000 行(u8g2 + MultMenu)

5. 相比裸机工程的优点

  1. 硬件与代码解耦。引脚、时钟、外设全在 devicetree 里,换板子/换引脚只改 overlay, 不动 C 代码。原工程换个 SPI 口要改好几处 HAL 调用。

  2. 驱动生态现成。SX1268、USB CDC、PWM、I2C 都是内核维护的驱动,省了 数千行 HAL 移植层代码(原工程 e22_hal.c、u8g2_hal.c 里直接操作寄存器的部分)。

  3. 并发模型更安全。中断里不再做 SPI 事务;接收回调在工作队列跑, 天然避免了原工程"ISR 里长事务阻塞系统"的隐患。

  4. 可维护性与可移植性。同一套应用代码理论上可以编译到任何 Zephyr 支持的 MCU 上(换板 = 换 overlay),裸机工程则与 STM32F1 深度绑定。

  5. 构建现代化。命令行 west/CMake/Ninja + GCC,可进 CI;不再依赖 Keil GUI 和付费的 ARMCC5。

  6. 运行时基础设施。k_timer、工作队列、sys_reboot、printk 控制台等都是现成组件, 蜂鸣器提示音从"阻塞 50ms"变成非阻塞也就一行改动。

6. 相比裸机工程的缺点

  1. 资源开销大。裸机工程 flash 占用估计不到 40KB;Zephyr 版 86KB,SRAM 更是 吃到 98.6%(只剩 263 字节)。USB CDC 一项就占约 7.5KB RAM——在 20KB 小内存 芯片上非常奢侈。裸机对资源的控制力是 RTOS 给不了的。

  2. 底层控制力下降。Zephyr LoRa 驱动只支持标准同步字(0x1424/0x3444), 原工程的自定义同步字 0x14 表达不了 → 新旧固件不互通。想要完全一致就得 放弃子系统、回去移植裸驱动。

  3. 实时行为不再直白。裸机里"中断来了立刻跑我的代码";Zephyr 里要经过 ISR→驱动→工作队列→回调,时序链条变长,调试需要理解驱动内部。

  4. 学习/概念成本。devicetree、binding、Kconfig、pinctrl 一套概念体系, 对裸机工程师有门槛(本次实践中由 AI 承担了这个成本)。

  5. 小内存芯片适配需要精打细算。为了塞进 20KB SRAM,裁了主栈、ISR 栈、 USB FIFO、缓冲池——这些调节需要经验,且余量小带来栈溢出风险。

  6. 验证闭环变长。裸机改一行 Keil 里点编译;Zephyr 全量构建要几分钟, 且驱动行为依赖内核版本(本次就遇到板名 revision、USB 新旧栈等 4.4 特有的坑)。

7. 经验总结:AI 做移植,人该做什么

AI 擅长的(本次全部委托给 AI):

  • 大海捞针式的代码库侦察(几千个文件里定位 binding、pinctrl、示例)

  • 机械但繁琐的映射工作(HAL 调用 → Zephyr API、引脚表 → overlay)

  • 编译-修错闭环(coder 子代理自行迭代到零 error)

  • 资源占用分析和裁剪建议

人类不可替代的(本次由人完成):

  • 架构取舍拍板:保真 vs 简洁、要不要 USB、接不接受新旧固件不互通—— 这些是产品决策,不是技术问题

  • 硬件验证:屏幕亮不亮、蜂鸣器响不响、能不能收到包,只有人能看

  • 需求边界:明确"不移植游戏"这类范围约束,避免 AI 过度交付

最有价值的工作方式:不是"让 AI 自由发挥",而是 侦察 → 人类决策 → AI 实施 → AI 工具链内验证 → 人类物理世界验收 的流水线。 本次从任务发起到上板验证通过,人类的实际参与只有:回答 4 个选择题、 确认方案、插 J-Link、按了几下按键看 OLED——其余全部由 AI 完成。







关键词: E22P-433MBH-SC     无线     Zephyr         

共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]