salonnikov/mower-stock-reverse
GitHub: salonnikov/mower-stock-reverse
该项目从零逆向工程了一块基于 GD32 多 MCU 架构的机器人割草机控制板,涵盖固件反编译、硬件架构映射、SWD 工具链与自定义固件开发。
Stars: 0 | Forks: 0
# MOWER — SNK_MAINBOARD_CP_V11 机器人割草机控制板的逆向工程
对机器人割草机**原厂控制板**的从零开始的拆解:两份出厂固件均已反编译,包含完整的架构 / 外设 / 子系统映射图,一套可用的 SWD 烧录 / 导出 / 还原工具链,以及一个可在真实硬件上运行的自定义 chip1 固件。
没有任何原厂原理图——这里的所有内容都是从两份出厂 GD32 固件以及电路板本身恢复出来的。
这些电路板上标有 **SNK** 标识:主板为 **`SNK_MAINBOARD_CP_V11`**(PN `80102372-01`),显示板为 **`SNK_DISPLAY_CP_V11``**(PN `80102373-01`);同样的标识贯穿于出厂固件(`a4963_snk_v2.c`、`movebase_snk_v10.c`,以及更新镜像 `SNK_MB.bin` / `SNK_BB.bin`)中。
SNK 极有可能是 Sunseeker。无论外壳上贴的是什么品牌,只要主板的丝印为 `SNK_MAINBOARD_CP_V11`,本代码库描述的就是它。此处研究的这台设备是作为 VILLARTEC MI 302 出售的。
**尚未完成。** 逆向工程已在硬件上得到验证,但在我们自己的固件下车轮从未转动过——请参阅[主要未解问题](#main-unsolved-problem--the-wheels-never-spun-on-our-firmware)。
后来这块板子坏了(进水导致电源部分损坏),工作也就此停止。
继续研究所需的一切都包含在这个代码库中。
### 本项目是如何完成的(诚实声明)
本代码库中的反编译和分析工作大量使用了 **Claude Code (Opus 4.8)** 作为辅助。我手工复核了这些发现,但仍需注意——该智能体极大地加快了工作速度,这正是*为什么*选择这种方式而不是纯手工拆解的原因。
写下这段注释是为了不让外部读者产生一种错觉,以为这一切都是历经两年纯手工打造的——事实并非如此。请将内容视为**有智能体辅助的逆向工程**,并在实际可行的地方进行了验证。任何您打算依赖的内容(地址、寄存器值、烧录步骤)在信任之前,都应根据实际的 dump / 真实硬件进行二次核对。
## 硬件部分(通过逆向工程确立)
MI 302 板 = **3 个 MCU + 3 个 BLDC 控制器**:
| 节点 | 芯片 | 角色 |
|---|---|---|
| chip1 (主) | **GD32F305 (GD32F30x_CL)** | 割草机 FSM、驱动(通过 SPI 连接 BLDC)、BMS 通信(USART2)、连接 chip2 和显示屏 |
| chip2 (边界传感器) | **GD32F4xx** | 边界线圈信号采集(ADC+DMA)、波形/区域检测、抬升传感器 → 通过 UART/cJSON 传给 chip1 |
| 显示屏 | **ESP32-WROOM-32UE** (SNK DISPLAY CP V11) | 按键 / LED,ledport 协议 |
| 驱动器 (×3:左/右轮 + 刀盘) | **Fortior FU6832N** | 智能 BLDC 控制器(8051 + FOC,自带 16 kB 固件),作为兼容 A4963 的从机监听 SPI |
## 发现总结
### 1. 固件与反编译
- **两份出厂固件均从零开始反编译**(Ghidra,标准流程)——参见
[`reverse-v2/chip1`](reverse-v2/chip1) 和 [`reverse-v2/chip2`](reverse-v2/chip2)
(`decompiled_all.c`,符号,字符串)。旧的 `docs/fw/` 和第一次迭代**不可靠**(仅作为历史记录保留在 `ru/archive/` 下)。
- **架构 / 外设 / 子系统映射图** —— [`reverse-v2/ARCHITECTURE.md`](reverse-v2/ARCHITECTURE.md),
[`reverse-v2/reports/subsystem-findings.md`](reverse-v2/reports/subsystem-findings.md),
[`reverse-v2/factory-map/`](reverse-v2/factory-map/) (逐个函数的详细解析,
请从 `00-INDEX.md` 开始看起)。
- **函数及外设参考** — [`reverse-v2/reference/`](reverse-v2/reference/)
(`FUNCTIONS-chip1/2`, `PERIPHERALS-chip1/2`, `MOWING-ALGORITHM`, 启动 RAM, 寄存器映射表)。
### 2. 启动、电源与安全
- **启动 / 上电时序与电源锁存** — [`reverse-v2/factory-map/01-boot-poweron.md`](reverse-v2/factory-map/01-boot-poweron.md)。
一个关键的操作事实是:chip1 上出现 `deadbeef` 的 DPIDR 意味着**芯片已断电**
(电源锁存断开),*而不是* SWD 线路损坏。
- **PIN / 配对安全** — [`reverse-v2/factory-map/02-pin-security.md`](reverse-v2/factory-map/02-pin-security.md)。
### 3. 割草 / 返航状态机
- **FSM(割草 ↔ 返航 ↔ 待机)与割草算法** —
[`reverse-v2/factory-map/03-fsm-mow-home.md`](reverse-v2/factory-map/03-fsm-mow-home.md),
[`reverse-v2/reference/MOWING-ALGORITHM.md`](reverse-v2/reference/MOWING-ALGORITHM.md)。
### 4. 驱动(BLDC / FU6832N over SPI)
- **SPI 驱动链已逐字节反编译** —
[`reverse-v2/factory-map/04-motor-drivers.md`](reverse-v2/factory-map/04-motor-drivers.md),
[`reverse-v2/reports/drive-chain.md`](reverse-v2/reports/drive-chain.md)。
片选信号:左 = PD5,右 = PD4,刀盘 = PD3;SPI1;PWM 位于 TIMER2 ch3。驱动器**没有 GPIO“使能”**线(待机激活 = SPI 寄存器写入 + 电源轨道)。
- **向 BLDC 的 SPI 写入已得到确认** — 轮通道通过 SPI 激活,并且**刀盘
在指令下输出了 RUN=1/0 的脉冲**。因此,SPI 路径本身已经可以端到端正常工作。
### 5. BMS / 电池包通信 (USART2)
- **已建立与电池包的通信** — USART2,19200 8N1,在 PD8/PD9 上的半双工通信;数据帧
`3A A3 len … C1 … CRC8` (CRC-8/MAXIM);连接握手 ×4;电池包作出应答 (`connected=1`)。
详情: [`reverse-v2/factory-map/05-bms-pack.md`](reverse-v2/factory-map/05-bms-pack.md)。
### 6. 边界检测 (chip2)
- **边界检测已被深入剖析** — 通过 ADC+DMA 的边界线圈,波形/区域分类;
灵敏度的调节旋钮是 `FUN_0801baf8` 中的 `|sample| > 2500` 阈值,基础电压
会自动校准,且整个镜像受到 **IEC60730 FLASH-CRC32** 的保护(因此修补
flash 会破坏 CRC)。如何针对新线圈进行调整:
[`reverse-v2/factory-map/06-chip2.md`](reverse-v2/factory-map/06-chip2.md),
[`reverse-v2/reports/CHIP2-BORDER-SENSITIVITY-2026-07-13.md`](reverse-v2/reports/CHIP2-BORDER-SENSITIVITY-2026-07-13.md)。
### 7. 自定义固件 + SWD 工具链
- **自定义 chip1 固件已烧录并在实机上运行** — [`firmware/mower-own/`](firmware/mower-own/):
心跳信号、电池读取、正常待机。烧录是 **CRC 安全**的(bootloader 不会检查
应用程序的 CRC)。
- **树莓派上的 SWD 基础设施** — 通过 openocd bitbang 进行烧录 / 导出 / 还原;完整的
变砖 → 恢复周期已在工作台上验证通过。chip1 = GPIO25/24,chip2 = GPIO8/7。
脚本: [`tools/bench/`](tools/bench/), [`tools/rpi-swd/`](tools/rpi-swd/);
流程: [`reverse-v2/reports/flash-procedure.md`](reverse-v2/reports/flash-procedure.md)。
- **已验证原厂还原** — chip1 已回滚至与原厂镜像位级一致的版本
(SP `0x20017ff8`,CRC `0x0f69a878`);工具位于 [`tools/rpi-swd/restore-2026-07-14/`](tools/rpi-swd/restore-2026-07-14/).
- **Dumps、固件镜像与烧录器** — [`dist/`](dist/),参见 [`dist/FLASHERS.md`](dist/FLASHERS.md)
(包含出厂 chip1 dump `gd32-mainboard-dump-v1.bin`、chip2 dump 以及完整的
`factory-full.asm` 反汇编文件)。
## 主要未解问题 — 轮子在我们的固件下从未转动
**在我们自己的固件下,车轮在物理上从未转动过**,尽管 SPI、PWM 和 GPIO
均被正确驱动,且**刀盘可控**。在工作台上,轮通道表现出**完全的寂静**
——没有运动,没有抖动——这表明问题出在轮通道驱动器未通电或未被激活,而不是在 SPI/PWM/GPIO 层(所有这些都符合出厂固件)。
在板子损坏之前,原因一直未能缩小至单一被证实的事实。
未决的假设以及解决这些假设的计划 —
[`reverse-v2/reports/WHEELS-ROOT-CAUSE-AUDIT-2026-07-10.md`](reverse-v2/reports/WHEELS-ROOT-CAUSE-AUDIT-2026-07-10.md):
- 为轮通道选择 FU6832 的 **快/慢配置**,
- 与原厂逐字节对比的 **SPI CTL0/CTL1**,
- 与原厂完全匹配的 **TIMER2**,
- 可能存在的 **电源轨道门控**(一条 BMS 指令,或者一个硬件电源开关 / VBB),原厂启用了它,而我们没有。
针对出厂固件的下一次单一 SWD 捕获旨在记录一次性解决此问题所需的一切信息
— [`reverse-v2/reports/SWD-CAPTURE-PACKAGE-2026-07-13.md`](reverse-v2/reports/SWD-CAPTURE-PACKAGE-2026-07-13.md)。
## 代码库布局
```
reverse-v2/ ★ CORE: clean re-teardown of both firmwares
ARCHITECTURE.md unified robot map (chip1 / chip2 / display / drive)
chip1/ chip2/ canonical decompile (decompiled_all.c, symbols, strings)
factory-map/ full factory-firmware walkthrough by function (00-INDEX)
reference/ references (bring-up RAM, drivers, registers, mowing algorithm)
reports/ current reports and plans — see reports/README.md
analysis/ measurements/ ghidra-scripts/ supporting analysis
firmware/
mower-own/ ★ custom chip1 firmware (flashed, runs; drive still under debug)
coil-scope/ coil work (ESP32)
esphome/mower.yaml telemetry bench for the display ESP32 (read-only)
tools/
bench/ flash-script generators, CRC, packer, recovery.cfg
rpi-swd/ SWD configs on the Pi (chip1 25/24, chip2 8/7) + restore-2026-07-14/
dashboard/ img/ supporting
dist/ dumps, firmware images, flashers — see dist/FLASHERS.md
server/ HA/MQTT glue, sniffers, scraper (telemetry)
hardware/ signal-map, SWD/ESP wiring diagrams
ru/ Russian originals (verbatim); ru/archive/ = historical / superseded
```
## 历史背景:“ESP32 大脑移植”方案
在走 GD32 路线之前,该项目曾作为 ESP32-S3 覆盖层在原厂电路板上运行
(移植 Ardumower,匹配滤波器信号接收)。后来为了直接控制原厂的 GD32 而放弃了该方案。规划文档和旧的 ESP32 大脑固件保留在
[`ru/archive/old-docs/planning-esp32/`](ru/archive/old-docs/planning-esp32/) 和
[`ru/archive/`](ru/archive/) (参见 `ru/archive/README.md`) 下。
标签:ARM/GD32, SWD调试, 云资产清单, 固件分析, 客户端加密, 嵌入式开发, 机器人, 物联网硬件, 逆向工程