test_led_strip/doc/升级操作指南.md
zhangyisong 27ae21bbea Add UID management, LED strip debug, and MCUboot signing updates
- Add UID encoding/decoding with flash storage and CRC16 validation
- Add write UID (0x07) and LED strip color (0x08) protocol commands
- Add debug LED strip configuration option
- Switch MCUboot signing from RSA-2048 to ECDSA-P256
- Add SMP serial client for firmware upload over UART
- Add firmware version output on boot
- Update upgrade documentation with ECDSA key generation steps
2026-08-20 21:16:30 +08:00

11 KiB

光磁头固件升级操作指南

1. 环境准备

1.1 安装依赖

# GUI 工具必需:串口库
pip install pyserial

# 固件签名工具(imgtool 随 Zephyr/MCUboot 自带,也可单独安装)
pip install imgtool

# 可选:命令行升级(smpmgr)——GUI 已内置 SMP 客户端,不装也能升级
pip install smpmgr

1.2 生成签名密钥(量产阶段)

# 在应用目录下生成密钥对
cd /home/issac-zys/code/zephyr_prj_template/app/app_photomagnetic
mkdir -p keys
imgtool keygen -k keys/mykey.pem -t ecdsa-p256

# 更新 sysbuild.conf 中的密钥路径与签名类型
# SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
# SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="${APP_DIR}/keys/mykey.pem"

开发阶段可跳过此步,使用 MCUboot 自带的开发密钥 root-ec-p256.pem⚠️ 密钥算法必须与签名类型一致:

  • -t ecdsa-p256 对应 SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
  • -t rsa-2048 对应 SB_CONFIG_BOOT_SIGNATURE_TYPE_RSA=y 不匹配会报链接错误(如 undefined reference to 'ecdsa_pub_key')。 本项目 boot 分区只有 48KB,建议用 ECDSA-P256(RSA 会把 MCUboot 撑到接近极限)。 更换密钥后必须完整重建(删 build 目录),否则签名/验签用的还是旧公钥。

2. 首次构建与烧录(需要调试器)

2.1 构建 MCUboot + 应用

cd /home/issac-zys/code/zephyr_prj_template

# 构建(sysbuild 模式,自动构建 MCUboot + 应用)
west build -p auto -b dr2501a_g0b0ce/stm32g0b0xx \
  --sysbuild app/app_photomagnetic \
  -d build

构建产物:

  • build/mcuboot/zephyr/zephyr.hex / .bin — MCUboot bootloader(0x08000000)
  • build/app_photomagnetic/zephyr/zephyr.signed.hex / .bin — 签名后的应用固件(0x0800C000)

⚠️ 注意:顶层 west flash -d build 只会烧应用镜像,不会烧 MCUboot!MCUboot 必须单独烧录。

2.2 烧录(一次性,需要调试器)

# ① 先烧 MCUboot 到 0x08000000(覆盖出厂 godtek bootloader,只需一次)
west flash -d build/mcuboot

# ② 再烧签名应用到 slot0 (0x0800C000)
west flash -d build

两条命令顺序不能反:没有 MCUboot 时,0x0800C000 的镜像头无法被引导,设备会完全无反应。

2.3 验证首次启动

串口调试口(usart3)应输出:

*** Booting MCUboot build ...
*** Booting Zephyr OS build ...
[dfu] init: upgrade command enabled (0xFF)
[com] init: rx table=4, id sent
[main] init on dr2501a_g0b0ce

协议口(usart1)应输出 ID 帧: [7E E7][01][03][XX XX XX][CRC]


3. 后续升级(通过 UART,不需要调试器)

3.1 升级流程图

┌─────────────────────────────────────────────────────────────┐
│  主板 / 测试工具                                              │
│  1. 发送升级命令 [7E E7][FF][01][01][CRC]                    │
│  2. 等待 300ms(小板重启)                                     │
│  3. 通过 smpmgr 上传固件(3 秒内)                             │
│  4. 标记待测试 + 复位                                        │
│  5. 等待新固件启动                                           │
└─────────────────────────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────┐
│  光磁头(小板)                                                │
│  1. 收到升级命令 → 直接重启                                  │
│  2. MCUboot 启动 → 等待 SMP 命令(3 秒)                      │
│  3. 收到 SMP 命令 → 进入 serial recovery                    │
│  4. 接收固件 → 直接写入 slot0(主槽,串口恢复固定写主槽)       │
│  5. 复位 → MCUboot 校验签名 → 启动新固件                     │
└─────────────────────────────────────────────────────────────┘

⚠️ 重要:串口恢复(serial recovery)是把镜像直接写入 slot0(主槽), 不是写 slot1 再 swap(那是应用内 mcumgr DFU 的做法)。因此:

  1. 升级过程中绝不能抢占/打开串口(比如用其他串口工具、或让本工具重新 Connect), 否则上传中断会把 slot0 擦到一半,设备无法启动;
  2. 上传中断后设备不会变砖——MCUboot 仍在运行并停留在 serial recovery 等待区, 直接用 smpmgr 重新上传即可恢复(或 west flash -d build 重烧应用);
  3. 设备异常停在 bootloader 时,再点一次升级按钮也能恢复(0xFF 命令对 MCUboot 无害, smpmgr 会自动连上当前等待中的 serial recovery)。

3.2 使用 smpmgr CLI 升级

步骤 1: 发送升级命令

使用串口工具或 Python 发送升级命令:

import serial, struct, time

def send_upgrade(port='/dev/ttyUSB0'):
    cmd = bytes([0x7E, 0xE7, 0xFF, 0x01, 0x01])
    crc = 0xFFFF
    for b in cmd[2:]:
        crc ^= b
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    cmd += struct.pack('<H', crc)
    
    with serial.Serial(port, 115200, timeout=1) as ser:
        ser.write(cmd)
        print(f"已发送升级命令: {cmd.hex()}")
    
    time.sleep(0.3)  # 等待重启

send_upgrade('/dev/ttyUSB0')

步骤 2: 使用 smpmgr 上传固件

# 一键升级(串口恢复模式直接写 slot0 主槽,上传完自动复位,无需 test/confirm)
# 必须在小板重启后 3 秒内执行;--timeout 10 给擦除/慢速上传留足超时
smpmgr --port /dev/ttyUSB0 --timeout 10 upgrade \
  build/app_photomagnetic/zephyr/zephyr.signed.bin

也可以手动分步:

# 上传固件到 slot0(主槽)
smpmgr --port /dev/ttyUSB0 image upload build/app_photomagnetic/zephyr/zephyr.signed.bin

# 复位,让 MCUboot 校验并启动新固件
smpmgr --port /dev/ttyUSB0 os reset

步骤 3: 验证新固件

# 查看串口输出,确认新固件版本(协议口应输出新固件的 ID 帧)
# 串口恢复直接写主槽、无 swap,固件已生效,无需 confirm。

3.3 使用 GUI 工具升级(推荐)

已集成到 scripts/test_gui.py 中,升级功能进程内封装了 SMP 客户端(smp_client.py), 不再依赖外部 smpmgr/mcumgr 命令:

  1. 打开 GUI 工具: python scripts/test_gui.py
  2. 连接串口
  3. 点击 "Upgrade Firmware" 按钮
  4. 选择 .signed.bin 固件文件
  5. 等待升级完成(GUI 会显示上传进度,自动复位并重连)

升级期间 GUI 会锁定 Connect 按钮/端口选择,防止串口被抢占导致上传中断。

可选:仍可用命令行一键升级(需已安装 smpmgr): smpmgr --port /dev/ttyUSB0 --timeout 10 upgrade build/app_photomagnetic/zephyr/zephyr.signed.bin

3.4 自动化升级脚本

#!/bin/bash
# upgrade.sh - 光磁头固件升级脚本
# 用法: ./upgrade.sh /dev/ttyUSB0 zephyr.signed.bin

PORT=${1:-/dev/ttyUSB0}
FIRMWARE=${2:-build/app_photomagnetic/zephyr/zephyr.signed.bin}

echo "=== 光磁头固件升级 ==="
echo "串口: $PORT"
echo "固件: $FIRMWARE"

# 检查固件文件
if [ ! -f "$FIRMWARE" ]; then
    echo "错误: 固件文件不存在"
    exit 1
fi

# 发送升级命令
echo "1. 发送升级命令..."
python3 -c "
import serial, struct, time
with serial.Serial('$PORT', 115200, timeout=1) as ser:
    cmd = bytes([0x7E, 0xE7, 0xFF, 0x01, 0x01])
    crc = 0xFFFF
    for b in cmd[2:]:
        crc ^= b
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    cmd += struct.pack('<H', crc)
    ser.write(cmd)
    print(f'  已发送: {cmd.hex()}')
"

# 等待重启
echo "2. 等待小板重启..."
sleep 0.3

# 上传固件(串口恢复直接写 slot0 主槽,上传完自动复位)
echo "3. 上传固件..."
smpmgr --port "$PORT" --timeout 10 upgrade "$FIRMWARE"

if [ $? -ne 0 ]; then
    echo "错误: 固件上传失败"
    echo "提示: 上传中断会擦掉 slot0 一半,但设备停在 bootloader 中不会变砖,"
    echo "      重新执行本脚本即可恢复(或 west flash -d build 重烧应用)。"
    exit 1
fi

echo "=== 升级完成,等待新固件启动 ==="

4. 恢复(串口恢复模式无 swap,没有回滚机制)

串口恢复(serial recovery)是直接把镜像写入 slot0 主槽,固件即刻生效、 不存在“待测试/回滚”的概念。旧版文档里的 swap/回滚描述来自应用内 mcumgr DFU, 本方案不适用。

4.1 上传中断/镜像损坏后的恢复

上传中断只会擦掉 slot0 一部分,MCUboot 仍然在运行并停留在 serial recovery 等待区, 不需要调试器即可恢复:

# 直接重传即可(设备已在 bootloader 等待,无需再发升级命令)
smpmgr --port /dev/ttyUSB0 --timeout 10 upgrade \
  build/app_photomagnetic/zephyr/zephyr.signed.bin

或使用 GUI:再次点击 Upgrade Firmware(0xFF 命令对 MCUboot 无害,smpmgr 会自动连上)。

4.2 强制恢复(需要调试器)

如果连 MCUboot 都进不去(比如误烧了 boot 分区):

# 重新烧录 MCUboot + 应用
west flash -d build/mcuboot
west flash -d build

5. 故障排查

现象 原因 解决方案
smpmgr 超时 上传未在 3 秒窗口内开始 先确认设备已进 bootloader(串口有 MCUboot 日志)再上传
上传中断 串口被其他工具/GUI 占用 关闭其他串口工具,重新上传(需从头传,不支持断点续传)
上传后无法启动 上传中断擦坏了 slot0 设备停在 bootloader,直接重传或 west flash -d build 重烧应用
签名验证失败 密钥不匹配 用构建时相同的密钥(开发期 root-ec-p256.pem)签名
smpmgr 连接失败 端口错误/被占用 确认端口号,关闭占用程序后再试

6. 注意事项

  1. 3 秒窗口:小板重启后,MCUboot 等待 SMP 命令 3 秒;超时则正常启动应用
  2. 波特率:应用层协议和 smpmgr 都使用 115200
  3. 签名:开发阶段使用默认密钥 root-ec-p256.pem;量产必须替换(且必须用 ECDSA-P256,RSA 装不进 48KB 分区)
  4. 升级期间勿占用串口:上传过程中不要打开其他串口工具、不要让 GUI 重新 Connect,否则上传中断会擦坏 slot0
  5. 调试器:首次烧录 MCUboot 需要;后续升级不需要
  6. 断电保护:升级中断电 → MCUboot 仍在运行,停在 serial recovery 等待区,重新上传即可恢复,设备不会变砖

7. 工具对比

工具 安装方式 优点
GUI 工具(推荐) 集成在 scripts/test_gui.py,内置 SMP 客户端 图形界面,一键升级,无需额外依赖(smpmgr/mcumgr 均可不要)
smpmgr pip install smpmgr 命令行,支持 Serial/BLE/UDP,适合脚本化
mcumgr CLI Go 编译/下载二进制 Zephyr 官方工具,功能完整