惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
P
Privacy & Cybersecurity Law Blog
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs
博客园 - 司徒正美
L
LINUX DO - 热门话题
D
Docker
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Security Latest
Security Latest
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
A
Arctic Wolf
小众软件
小众软件
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
腾讯CDC
Google DeepMind News
Google DeepMind News
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
I
Intezer
NISL@THU
NISL@THU
A
About on SuperTechFans
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
G
Google Developers Blog
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Cyberwarzone
Cyberwarzone
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
Latest news
Latest news

博客园 - 思兼

跟思兼学Klipper(41):优化 KAMP 的自适应划线清除喷嘴残料 跟思兼学Klipper(40) 免费高速简单的3D打印机远程控制服务 跟思兼学Klipper(39.1)解决 QIDI Q2 主板散热风扇开机即转、待机不停的风扇噪音问题 跟思兼学Klipper(38) 成品3D打印机使用外挂上位机提升性能简明指南 跟思兼学Klipper(37) M8P v2.0+CB2/BTTPi2 新版系统使用简明指南 跟思兼学用Klipper(36)低成本升级自动Z偏移校准实现完美首层 MKS Pi/SKIPR 自制新版系统简明使用指南 火力全开!Intel NUC6iKYK 骷髅峡谷提速降温简明指南 跟思兼学用Klipper(35) mergerfs 助力 Klipper 上位机热插拔自动扩容与脱机打印 跟思兼学用Klipper(34) 3D打印机如何进行双 Z 等高校准之我见 跟思兼学Klipper(32):修复 CrealityOS IP 地址经常改变的问题 跟思兼学Klipper(30):使用辅助宏调整3D打印机无感归位堵转检测阈值 玩转创想三维 K1 系列主板之二:编译 MCU 固件,恢复裁剪组件 基于 ESPHome 的 3D 打印机舱内控制系统(2): FireBeetle 2 ESP32-C6 + Moonraker Sensor + Fluidd 基于 ESPHome 的 3D 打印机舱内控制系统(1): 荆棘满途之 FireBeetle 2 ESP32-C6 初始配置 跟着思兼学习Klipper(29):行空板遇上Klipper之一: 安装Klipper全家桶 跟着思兼学习Klipper(28):无接触线刷Klipper固件:千秋万载,一统江湖之Katapult 跟着思兼学习3D打印 Klipper 固件系列文章合集 27-行空板遇上Klipper之三: 做一个基于Klipper的通用延时摄影机
玩转创想三维 K1 系列主板之一:在线更新 MCU 固件
思兼 · 2024-05-10 · via 博客园 - 思兼

前言

本文是摸索创想三维 K1 系列软硬件系统的一些内容分享。本系列文章由于与他们的软件工程师无沟通渠道,仅能凭经验与黑盒测试,故有盲人摸象之可能,如有谬误,欢迎指正交流。下一期会讲如何编译创想三维魔改版 Klipper 固件。

由于有为 K1 系列 MCU 升级固件的需求,被告知使用私有 bootloader,具体用法不透露。好在主板上预留 SWD 调试引脚,但是对普通用户不友好,希望有 Katapult Bootloader 那种支持无接触线刷升级 Klipper 固件的方式就好了。后来在探索 CrealityOS 过程中,我们查看启动服务发现一个 /etc/init.d/S13mcu_update 的自启动服务,看名称和升级固件有关,大喜过望,失望而归,提供的 mcu_util 工作不符合预期(可能是我使用方法有误,具体见下文。不过 S13mcu_update 很值得一看,逻辑思路比较完善)。

可以在 Creality-K1-Extracted-Firmwares 处查看已解包系统镜像。

我们约定,直接控制打印机硬件的部分称为主板,运行 Linux 系统的部分称为上位机。

运行测试环境:

  1. K1C 和 K1Max 主板(两块主板硬件配置有所不同)
  2. Ubuntu 22.04 Arm64
  3. CrealityOS

本文涉及的内容:

  1. 如何使用原厂 bootloader 升级打印机主板固件
MCU 设备地址 备注
mcu (mcu0) /dev/ttyS7 主 MCU
nozzle_mcu /dev/ttyS1 热端 MCU
leveling_mcu /dev/ttyS9 热床调平 MCU
rpi (host as mcu) /tmp/klipper_host_mcu 上位机作为 MCU

1、升级主板固件(精简版)

需要使用 chs 进行 root,安装 supervisorctl 用来管理服务(非必须,随 moonraker 安装)。

1.1 使用第三方 mcu_util.py 工具

此处以 mcu0 为例,由于官方提供的工具 mcu_util 握手之后会超时报错,所以我们使用第三方工具。

# 关闭 klipper,取消对串口设备的占用
supervisorctl stop klipper

# 部署第三方固件烧录工具
cd && git clone https://github.com/cryoz/k1_mcu_flasher && cd k1_mcu_flasher

# 为 mcu0(/dev/ttyS7) 烧录固件,以原厂固件为例
# 流程:重置 mcu0 ——> 等待 2s ——> 上传固件
mcu_reset.sh && sleep 2 && ./mcu_util.py -c -v -i /dev/ttyS7 -u -f /usr/share/klipper/fw/K1/mcu0_120_G32-mcu0_004_000.bin

# k1_mcu_flasher 用法
usage: mcu_util.py [-h] [-v] [-c] -i PORT [-f FILE] [-u] [-s] [-g]
Creality K1 MCU Flasher
optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Debug output
  -c, --handshake       Attempt handshake before operation
  -i PORT, --port PORT  serial device
  -f FILE, --file FILE  firmware file
  -u, --update          Update firmware from file
  -s, --appstart        Attempt to start fw
  -g, --version         Get version

# 其他用法示例
# 注意:握手仅需要一次,每个选项都包含握手操作,所以不需要先单独握手在执行其他操作
## 与 mcu0 进行握手,并显示详情
./mcu_util.py -c -v -i /dev/ttyS7

## 与 mcu0 握手并获取 mcu 固件版本
./mcu_util.py -c -v -i /dev/ttyS7 -g

## 启动固件(如果没有自动启动)
./mcu_util.py -c -v -i /dev/ttyS7 -s

1.2 同样操作使用原厂 mcu_util 超时报错

偶尔可以握手成功。

mcu_reset.sh && sleep 2 && mcu_util -c -v -i /dev/ttyS7 -u -f /usr/share/klipper/fw/K1/mcu0_120_G32-mcu0_004_000.bin
usart_send_Process: get_sector_size
usart_rec_Process: select time out, state = 6
usart_rec_Process: select time out, state = 6
usart_rec_Process: select time out, state = 6
usart_rec_Process: timeout
usart_sent_retval: 1, usart_rec_retval: 1

再次询问工程师此工具正确用法,无回复。

1.3 烧录更新其他三个 MCU

  • 热端和调平 MCU 使用 RS232 串口与上位机通讯,没有专门的重置方式,应该有未知的固件重启命令,或者采用 Klipper 通用的命令进入 bl 状态,具体见之前文章 无接触线刷Klipper固件:千秋万载,一统江湖之Katapult ,等待后续测试
  • 还有一种是思路是写一个 initi.d 开机启动服务,在 mcu 上电 15s 内完成握手
  • host_as_mcu 可以使用 klipper_mcu 服务停止

2、K1 Bootloader 烧录流程解析

注:此部分属于对 k1_mcu_flasher 的注释,只能说作者是专业的。

原程序 /usr/bin/mcu_util 是二进制文件(怀疑是加密的 shell 脚本)。

mcu_util.py 代码分析

  • 导入必要的模块:
    • binascii 用于编码和解码十六进制数据。
    • io 用于读取文件。
    • pathlib 用于处理文件路径。
    • argparse 用于解析命令行参数。
    • sys 用于退出程序。
    • serial 用于与串行设备通信。
  • 定义 crc 函数:用于计算 CRC 校验和。
  • 定义 debug 函数:用于打印调试信息。
  • 定义 _handshake 函数:用于与 MCU 进行握手。
  • 定义 _get_version 函数:用于获取 MCU 的版本信息。
  • 定义 _get_sector_size 函数:用于获取 MCU 的扇区大小。
  • 定义 _app_start 函数:用于启动 MCU 的应用程序。
  • 定义 _flash_fw 函数:用于更新 MCU 的固件。
  • 定义 open_port 函数:用于打开指定的串行端口。
  • 定义 handshake 函数:用于执行握手操作。
  • 定义 get_version 函数:用于获取 MCU 的版本信息。
  • 定义 app_start 函数:用于启动 MCU 的应用程序。
  • 定义 update 函数:用于更新 MCU 的固件。
  • 解析命令行参数:使用 argparse 模块解析命令行参数。
  • 根据命令行参数执行相应的操作:如果指定了 c-handshake 选项,则执行握手操作;如果指定了 g-version 选项,则获取 MCU 的版本信息;如果指定了 u-update 选项,则更新 MCU 的固件;如果指定了 s-appstart 选项,则启动 MCU 的应用程序。
  • 如果没有指定任何操作,则打印帮助信息并退出。
  • 执行相应的操作并返回退出代码。

2.1 Handshake stage 握手阶段

bootloader waiting 15 secs after startup for handshake, then launch app if app corrupted by crc16 - bootloader waiting for handshake forever ALL stages requred passing handshake stage ONCE send: 0x75, receive ack: 0x75

  • bootloader (bl) 启动后等待 15s 用于握手,之后启动 app (klipper)。
  • 如果 app 的 crc16 检校失败,bl 会一直等待握手
  • 所有阶段都需要握手通过 1 次且只需要一次
  • 发送 0x75,返回 0x75
  • 编者注:握手是为了在 15s 内截住 bootloader,不让其启动 App。mcu_util.py 的每个命令都有握手操作。

2.2 Version stage 版本验证阶段

bootloader checks for crc16 of app, if passed - combine hw version string (in bootloader area) and fw version string (in fw area) if crc16 not passed - sending 25 bytes of 0x00 send 00ff (ff - crc), receive string (25 bytes+crc) of combined hw version and fw version

  • bl 会检查 app 的 crc16
    • 如果通过检测,附加 hw 和 fw 版本字符
    • 如果未通过检测,发送 25 字节的 0x00
  • 向 bl 发送 00ff (ff - crc),返回 (25 bytes+crc),以及 hw 和 sw 版本
  • 说的不清楚,有需求的具体看源码
        # 解码返回信息
        r = ser.read(26)
        if len(r) > 0:
            debug(f'rcv data {hexlify(r)}', v)
            if len(r) == 26 and r[25] == crc(r[:-1]):
                debug(f'version received! {r[:-1]}', v)
                result = bytes(r[:-1]).decode(encoding='latin')

在这个代码中,r是一个字节数组,[:-1]表示取r的前len(r)-1个元素,即去掉最后一个字节。然后,使用decode方法将字节数组转换为字符串,并指定编码为latin。这将把字节数组转换为一个使用latin编码的字符串。

2.3 Get sector size stage 获取扇区大小阶段

mostly = 1, multiplier for receive buffer of firmware send 03fc (fc - crc), receive sector size (1 byte+crc)

  • 多数情况为固件大小的 1 倍
  • 发送 03fc (fc - crc),返回扇区大小

2.4 App start stage 启动 App 阶段

bootloader check crc16 of fw in flash, if succeded - passes program flow to fw entrypoint send 02fd (fd - crc), receive ack 0x75

  • bl 检查闪存内固件的 crc16,如果通过,进入正常 App
  • 发送 02fd (fd - crc), 返回 0x75

2.5 Flash FW stage 固件烧录更新阶段

receive fw by chunks, size of chunks = sector size << 16, to ram, then writes to flash.

  1. update request: send 0xfe (fe - crc), receive ack 0x75
  2. send fw size: send dword of size with leading crc, receive ack 0x75
  3. send chunks by chunk-size, receive statuses: 0x75 - chunk succeded 0x20 - all firmware flashed 0x21 - error in write ram->rom stage 0x1f - bad crc of received data
  • 分块传输固件到 mcu ram 中,然后写入 flash
  • 发送更新请求
  • 发送固件大小,会生成crc
  • 发送大小,返回状态符(见上)

由于创想对 Klipper 做了很多魔改,我们先使用官方的 Klipper 仓库,默认支持 GD32F303。

我们要为 Arm Crotex-M 编译固件,用到 GNU Arm Embedded Toolchain,目前仅支持 AArch64/x86_64 而不支持 MIPS 架构 CPU 所以只能在其他设备上编译固件,再进行烧录。也由于这点,CrealityOS 的 klipper 直接精简掉了编译固件的源码。

# 下载创想三维修改版 Klipper
git clone https://github.com/CrealityOfficial/K1_Series_Klipper && cd K1_Series_Klipper
# 由于原来的是 MIPS 的,需要删除 c_helper.so 重新编译
python
# 由于我使用 Ubuntu 22.04,需要降级到 gcc-arm-none-eabi 10.0 以下以正确编译 prtouch_v2
sudo apt preference
# 安装缺少的软件包
sudo apt install 
# 修改编译参数
make menuconfig
make