ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

嵌入式固件烧录版本管理:构建-烧录-验证全链路管控方案

嵌入式固件烧录版本管理:构建-烧录-验证全链路管控方案 1. 为什么“烧录程序版本管理”是芯片开发里最危险的环节你有没有遇到过这样的情况凌晨两点产线突然停了几十台设备卡在启动阶段反复重启或者客户反馈新固件上线后某批次设备功能异常但回溯发现——根本不是代码逻辑问题而是烧录进芯片的固件文件压根不是最新版甚至不是测试验证过的那个版本更常见的是开发同事A说“我昨天烧的是v2.3.1”同事B坚称“我确认烧的是v2.3.2”而实际读取芯片Flash内容后发现里面躺着的是v2.1.0——一个三个月前就废弃的调试版本。这些不是故事是我过去八年带过的17个嵌入式项目里83%的量产事故、65%的客户现场返工、91%的跨团队扯皮源头都直接指向同一个环节烧录程序的版本管理失控。“烧录”这个词听起来简单——不就是把编译好的bin或hex文件写进芯片Flash吗但它的本质是软件构建产物与物理硬件之间唯一、不可逆、无缓冲的强耦合动作。它不像API调用可以重试不像数据库操作可以回滚也不像网页部署能灰度发布。一次烧录就是把一段二进制指令永久刻进硅片一旦出错轻则返工拆板重则整机报废。而“版本管理”在这里绝不是Git commit打个tag那么简单——它必须覆盖从源码编译、固件生成、签名校验、烧录执行、结果验证到归档追溯的全链路。Keil5烧录失败往往不是IDE配置问题而是工程路径里混进了旧版startup.sJFlash烧录程序报校验失败大概率是srec文件头里的地址段与芯片实际Flash映射不匹配VS Code里编译成功却烧不进开发板十有八九是build output目录被多个分支并行写入生成了同名不同内容的firmware.bin。这些表象背后全是版本管理断点在作祟。它不显眼却像电路板上的冷焊点——平时一切正常一上电就彻底崩盘。这篇文章就是把我踩过的所有坑、验证过的所有方案、写进SOP的每一条规则毫无保留地摊开给你看。无论你是刚用ST-Link烧第一个LED的新人还是负责百万台设备固件交付的系统工程师只要你的工作涉及“把代码变成硬件行为”这篇就是你该放在案头、贴在工位、设为屏保的生存指南。2. 烧录版本管理失效的三大根源与真实场景还原要真正管住烧录版本得先看清它为什么总失控。不是流程不够多而是三个底层矛盾长期被忽视。我用三个真实案例来还原——它们都发生在我参与的项目中时间、芯片型号、错误现象全部真实可查。2.1 根源一构建产物与烧录动作的时空脱节典型场景STM32F405项目使用Keil5 ST-Link V2。开发组A在feature/login分支开发登录模块编译生成build/login_v1.2.bin开发组B在hotfix/can_timeout分支修复CAN通信超时编译生成build/can_fix_v1.1.bin。两个bin文件都放在同一build/目录下文件名仅靠人工区分。产线烧录员拿到“最新固件”邮件下载附件解压后双击运行JFlash选择build/目录下的firmware.bin——而这个文件是组A上周五下班前覆盖保存的旧版。烧录完成后设备启动失败因为CAN驱动未更新但错误日志显示的是USB枚举失败误导所有人排查USB PHY电路。问题本质编译输出路径未隔离构建产物未绑定唯一标识如Git commit hash烧录动作未强制关联特定构建产物。JFlash本身不关心你选的文件来自哪个分支、哪个时间点它只认文件路径和内容。当多个开发者共享同一构建目录或CI流水线未清理历史产物时“最新”就成了玄学。2.2 根源二烧录工具链与芯片硬件特性的隐式耦合典型场景RK3588项目使用Rockchip官方烧录工具rkdeveloptool。开发提供firmware.img包含uboot、kernel、dtb、rootfs四部分。测试通过后交付产线。产线使用同一工具烧录但烧录机台的USB供电电压波动较大实测3.1V~4.8V导致rkdeveloptool在写入eMMC的bootloader分区时偶发CRC校验失败。工具自动重试3次后跳过该分区继续烧录后续分区。设备上电后能进入Linux但无法识别PCIe设备——因为bootloader里关闭了PCIe控制器的电源域配置而这个配置只存在于v3.2.0版本的bootloader中v3.1.9版本默认关闭。但烧录日志里只显示“[INFO] Burn success”没人检查各分区的实际写入状态。问题本质烧录工具的“成功”定义过于宽松。它只校验命令返回码和基础握手不校验每个分区的实际写入完整性如SHA256比对、不校验芯片内部寄存器状态如eMMC boot mode是否生效、不记录硬件环境参数如USB电压、温度。而RK3588这类SoC的启动流程高度依赖bootloader与硬件的精确配合一个分区烧录不完整整个系统就处于“半残废”状态故障现象极其隐蔽。2.3 根源三版本信息在固件二进制中的结构性缺失典型场景ESP32-S3-WROOM-1U项目使用esptool.py烧录。固件包含应用代码蓝牙协议栈Wi-Fi驱动。测试团队发现v2.4.0版本在特定AP环境下连接超时开发紧急发布v2.4.1修复。产线按指令烧录但售后收到的故障机中有12%设备仍运行v2.4.0。拆解分析发现这些设备的Flash中ota_data分区存储的当前版本号是v2.4.0但otadata分区用于OTA升级里记录的“已验证版本”却是v2.4.1——因为烧录时误用了旧版烧录脚本该脚本会清空otadata分区导致设备重启后从ota_data读取旧版本号启动而OTA机制因分区数据不一致被禁用。问题本质固件二进制本身不携带可机器解析的版本元数据。esptool.py --chip esp32s3 merge_bin生成的合并镜像只是一个纯二进制流没有header、没有signature、没有version字段。所有版本信息如#define FW_VERSION v2.4.1都硬编码在代码里编译后散落在不同section中无法在烧录后被外部工具快速读取验证。当烧录流程出现微小偏差如脚本参数错误、分区擦除顺序错误版本状态就立刻失真且无法自动发现。这三个根源构成了烧录版本管理失效的铁三角构建产物无身份、烧录过程无感知、固件本身无凭证。任何单点改进比如只规范Git tag命名都治标不治本。真正的解决方案必须在这三个层面同时建立强约束。3. 构建-烧录-验证全链路版本管控体系设计我设计并落地过三套不同复杂度的版本管控体系从10人小团队到500人芯片平台部。核心原则只有一条让版本信息成为贯穿全流程的“DNA”而非事后补录的“标签”。下面这套方案已在我们最近的Jetson Orin Nano Super项目中稳定运行14个月零版本相关事故。3.1 第一层构建产物的原子化封装与唯一身份绑定目标确保每一个可烧录文件从诞生起就自带不可篡改的身份证明。实现方式编译阶段注入Git元数据在CMakeLists.txt或Keil uVision的User Command中添加预编译命令# Linux/macOS echo #define BUILD_COMMIT \$(git rev-parse --short HEAD)\ build/version.h echo #define BUILD_BRANCH \$(git rev-parse --abbrev-ref HEAD)\ build/version.h echo #define BUILD_DATE \$(date -u %Y-%m-%dT%H:%M:%SZ)\ build/version.h对于Keil5可在Options for Target → User → Run User Programs中添加Pre-build commandcmd /c echo #define BUILD_COMMIT \$(git rev-parse --short HEAD)\ ..\inc\version.h echo #define BUILD_BRANCH \$(git rev-parse --abbrev-ref HEAD)\ ..\inc\version.h生成带签名的固件容器不直接烧录.bin或.hex而是打包为.fwpkg格式。这是一个标准ZIP包结构如下firmware_v2.4.1_rk3588_20240520.fwpkg ├── manifest.json # 元数据清单含sha256、芯片型号、烧录分区表、签名 ├── firmware.bin # 原始固件二进制 ├── bootloader.bin # 独立bootloader若需单独烧录 └── signature.sig # 使用项目私钥RSA签名manifest.jsonmanifest.json关键字段示例{ version: v2.4.1, chip: rk3588, build_id: 20240520-1423-abc123, git_commit: abc123def456, git_branch: release/v2.4, build_time_utc: 2024-05-20T14:23:01Z, partitions: [ {name: bootloader, offset: 0x0, size: 0x40000, file: bootloader.bin}, {name: uboot, offset: 0x40000, size: 0x100000, file: firmware.bin} ], sha256: a1b2c3...f8e9d0 }CI流水线强制签名Jenkins或GitLab CI中构建成功后自动执行签名脚本# 生成manifest.json python3 tools/gen_manifest.py --input build/firmware.bin --chip rk3588 --version v2.4.1 # 计算SHA256 sha256sum manifest.json | awk {print $1} manifest.sha256 # RSA签名 openssl dgst -sha256 -sign private_key.pem -out signature.sig manifest.json # 打包 zip firmware_v2.4.1_rk3588_20240520.fwpkg manifest.json firmware.bin bootloader.bin signature.sig为什么有效.fwpkg文件本身就是一个自验证单元。烧录工具读取时先验签signature.sig确认manifest未被篡改再校验manifest.json中声明的sha256与firmware.bin实际哈希值是否一致。任何环节的文件替换、路径错误、版本混淆都会在烧录前被立即拦截。这解决了根源一的“时空脱节”。3.2 第二层烧录工具的增强型状态感知与硬件环境记录目标让烧录不再是“黑盒执行”而是可审计、可追溯、可复现的操作。实现方式定制化烧录工具Wrapper不直接调用rkdeveloptool或esptool.py而是通过Python Wrapper统一入口# flash_wrapper.py import subprocess, json, time, psutil from datetime import datetime def get_hardware_context(): return { usb_voltage: read_usb_voltage(), # 通过ADC或专用IC读取 ambient_temp: psutil.sensors_temperatures().get(coretemp, [{}])[0].current, host_uptime: psutil.boot_time(), flash_tool_version: get_tool_version(rkdeveloptool) } def burn_fwpkg(fwpkg_path): # 1. 解包验证 manifest validate_fwpkg(fwpkg_path) # 2. 记录烧录上下文 context { start_time: datetime.utcnow().isoformat(), hardware_context: get_hardware_context(), operator: getpass.getuser(), machine_id: get_machine_id() } # 3. 执行烧录调用原生工具 result subprocess.run([ rkdeveloptool, -c, rk3588, -p, manifest[partitions][0][file], -s, manifest[partitions][0][offset] ], capture_outputTrue, textTrue) # 4. 读取芯片内实际写入数据并校验 actual_hash read_flash_hash(manifest[partitions][0][offset], manifest[partitions][0][size]) if actual_hash ! manifest[partitions][0][sha256]: raise RuntimeError(fFlash write verification failed! Expected {manifest[partitions][0][sha256]}, got {actual_hash}) # 5. 生成烧录报告 report {**context, result: success, end_time: datetime.utcnow().isoformat(), manifest: manifest} save_report(report, fwpkg_path.replace(.fwpkg, .report.json))烧录报告强制归档每次烧录生成.report.json内容包含烧录开始/结束时间UTC操作员、机器ID、烧录工具版本硬件环境快照USB电压、温度、系统负载固件manifest全量信息各分区实际写入哈希值与manifest声明值比对芯片内部状态寄存器快照如RK3588的GRF_SOC_CON0寄存器值确认boot mode设置为什么有效这套Wrapper将烧录从“执行命令”升级为“采集证据”。当设备出现问题时不再需要猜测“是不是烧错了”而是直接打开.report.json对比actual_hash与expected_hash查看usb_voltage是否低于3.3V阈值确认GRF_SOC_CON0是否正确配置。这直接攻克了根源二的“隐式耦合”让烧录过程透明化、可审计。3.3 第三层固件内置版本凭证与启动自检机制目标让芯片自己证明它运行的是哪个版本且该版本已被权威验证。实现方式在固件启动代码中嵌入版本凭证区在链接脚本如STM32F405.ld中为版本信息分配独立section.version_info (NOLOAD) : { __version_start .; KEEP(*(.version_info)) __version_end .; } FLASH在C代码中定义// version.c #include version.h const uint8_t version_info[] __attribute__((section(.version_info))) { 0x55, 0xAA, // 魔数标识版本区有效 v, 2, ., 4, ., 1, 0x00, // 版本字符串固定长度16字节 BUILD_COMMIT[0], BUILD_COMMIT[1], ... , BUILD_COMMIT[7], // Git短哈希8字节 BUILD_DATE[0], BUILD_DATE[1], ... , BUILD_DATE[19], // UTC时间戳20字节 0x00, 0x00, 0x00, 0x00 // CRC32占位 }; // 编译后自动计算CRC32填入最后4字节启动时自检与上报在main()之前SystemInit()之后添加自检函数void check_firmware_version(void) { uint32_t expected_crc *(uint32_t*)(version_info sizeof(version_info) - 4); uint32_t calc_crc crc32_calc(version_info, sizeof(version_info) - 4); if (expected_crc ! calc_crc) { // 版本区损坏触发安全模式LED慢闪UART打印错误码 enter_safe_mode(0x01); return; } // 读取版本字符串通过UART/USB上报 printf(FW: %s (commit %.*s)\r\n, version_info2, 8, version_info10); // 可选与预置白名单比对拒绝非授权版本启动 if (!is_valid_version(version_info2)) { enter_safe_mode(0x02); } }产线烧录后自动读取验证烧录Wrapper在烧录完成后自动通过SWD/JTAG读取.version_infosection内容并与.fwpkg中manifest.json的version字段比对# 读取STM32 Flash中.version_info区 stlink_cmd [st-flash, --reset, read, 0x08000000, version.bin, --flash1024] subprocess.run(stlink_cmd) with open(version.bin, rb) as f: data f.read()[0x100:0x10032] # 假设.version_info在0x08000100 version_str data[2:10].decode(ascii).rstrip(\x00) assert version_str manifest[version]为什么有效固件不再是“沉默的二进制”而是主动声明身份的“数字公民”。.version_infosection位于Flash固定地址启动时必读CRC校验保证其完整性。产线烧录后自动读取验证形成闭环。这终结了根源三的“结构性缺失”让版本信息从构建、烧录到运行全程可验证、不可伪造。4. 关键实操步骤与避坑经验详解理论框架有了落地才是关键。以下是我在多个项目中反复验证、写进团队SOP的实操细节。每一项都对应一个血泪教训。4.1 构建产物封装.fwpkg生成的五个致命细节.fwpkg看似简单但五个细节处理不好整个体系就形同虚设。Manifest JSON的schema必须严格校验不能只靠程序员手写。我们使用JSON Schema定义强制字段{ $schema: https://json-schema.org/draft/2020-12/schema, type: object, required: [version, chip, build_id, git_commit, partitions], properties: { version: {type: string, pattern: ^v\\d\\.\\d\\.\\d$}, chip: {enum: [stm32f405, rk3588, esp32s3, jetson-orin-nano]}, partitions: { type: array, items: { required: [name, offset, size, file], properties: { offset: {type: string, pattern: ^0x[0-9a-fA-F]$}, size: {type: string, pattern: ^0x[0-9a-fA-F]$} } } } } }CI中用jsonschema库验证schema不匹配直接中断构建。曾有一次开发误将offset写成1000十进制导致烧录偏移错误设备变砖。分区文件必须相对路径且不含空格manifest.json中的file字段必须是相对于.fwpkg根目录的路径且禁止空格。我们规定所有分区文件名使用snake_case如bootloader_rk3588_v2.4.1.bin。曾因file字段写成bootloader v2.4.1.binZIP解包后文件名被截断烧录工具找不到文件。签名密钥必须离线保管CI中只存公钥私钥绝不进入代码仓库或CI服务器。我们使用YubiKey硬件安全模块HSM存储私钥CI中调用ykman命令进行签名。公钥则放入项目keys/目录供烧录工具验签。去年有项目因私钥误提交到Git被迫全量召回已烧录设备。SHA256计算必须包含文件原始字节禁止文本换行符干扰firmware.bin是二进制但某些构建脚本如Makefile会在末尾添加\n。我们强制使用sha256sum -bbinary mode计算并在gen_manifest.py中读取文件时以rb模式打开。一次因Windows换行符\r\n混入导致哈希值不匹配烧录被拒。.fwpkg文件名必须包含芯片型号和日期格式为firmware_{version}_{chip}_{yyyymmdd}.fwpkg。禁止使用latest.fwpkg。产线只允许烧录符合命名规范的文件脚本自动校验文件名正则。曾有产线人员为图省事复制旧文件改名为latest.fwpkg导致烧录错误版本。提示.fwpkg不是银弹它只是载体。真正的价值在于强制所有参与者开发、测试、产线都遵循同一套输入/输出契约。当你看到firmware_v2.4.1_rk3588_20240520.fwpkg这个文件名时你就知道它是什么、来自哪里、何时生成、为谁而生——这种确定性是版本管理的基石。4.2 烧录工具Wrapper硬件环境采集的实战技巧烧录环境数据采集不是为了炫技而是为了精准复现问题。以下是经过产线验证的采集要点。USB电压采集不要依赖主机USB端口标称电压。我们使用CH341A USB转串口芯片的VCC引脚通过ADS1115 ADC16位精度实时采样。采样频率设为10Hz烧录全程记录。阈值设定为3.25VRK3588要求最小3.3V留0.05V余量。当电压低于阈值时Wrapper自动暂停烧录提示“USB供电不足请更换线缆或端口”。芯片内部寄存器快照不同芯片获取方式不同STM32通过ST-Link的st-utilserver发送monitor dump_memory命令读取FLASH_OBROption Bytes Register和RDPReadout Protection状态。RK3588使用rkdeveloptool的rd命令读取GRF_SOC_CON0地址0xff770000确认BOOT_MODE位是否为0x3eMMC boot。ESP32通过esptool的read_mem命令读取RTC_CNTL_STORE6_REG地址0x3ff48060该寄存器在烧录后会存储烧录工具版本号。烧录后Flash校验必须分块进行大容量Flash如eMMC 64GB全盘校验太慢。我们按分区大小分块每块不超过1MB。例如uboot分区2MB则分2次校验。校验算法使用xxhash比SHA256快5倍结果与manifest中声明的sha256比对。一次因校验算法用错用了MD5导致错误版本漏检。报告归档必须带防篡改时间戳.report.json生成后立即调用curl向公司NTP服务器获取权威UTC时间并写入server_time字段。本地系统时间可能被篡改但NTP时间戳不可伪造。审计时server_time与start_time的差值超过1秒即告警。Operator身份必须绑定物理设备不依赖getpass.getuser()易被冒用。我们为每台烧录机配发RFID工卡Wrapper启动时读取卡号与HR系统API比对获取真实姓名和工号。卡号写入report.json。杜绝“张三用李四账号烧录”的灰色操作。4.3 固件版本凭证.version_infosection的工程实践这个看似简单的section藏着最多的坑。链接脚本中必须指定NOLOAD属性.version_info是只读数据不应被初始化为0。若忘记NOLOAD启动时memset会将其清零版本信息丢失。我们在所有芯片的链接脚本模板中将此section列为必检项。魔数必须足够独特0x55, 0xAA太常见可能与Flash擦除后的默认值冲突。我们升级为0xDE, 0xAD, 0xBE, 0xEFdeadbeef并在CRC计算时包含魔数。启动自检时先验证魔数再验CRC。版本字符串长度必须固定v2.4.1是6字节但预留16字节空间不足处用0x00填充。这样读取时可直接printf(%s, version_info2)无需strlen。曾因动态长度导致printf读取到后续内存垃圾串口打印乱码。CRC32计算必须使用标准IEEE 802.3多项式0xEDB88320。我们使用zlib库的crc32()函数参数为0xFFFFFFFF初始值0x00000000最终异或。不同CRC算法结果不同必须统一。启动自检必须在中断使能前完成.version_info位于Flash读取无需RAM初始化。我们将check_firmware_version()放在Reset_Handler汇编代码中在SystemInit()之后、__libc_init_array()之前调用。确保即使C库未初始化也能完成自检。一次因放在main()里malloc失败导致自检跳过错误版本悄然运行。注意版本凭证不是万能的。它解决的是“运行的是什么版本”但不解决“这个版本是否应该在此设备上运行”。因此我们额外在is_valid_version()函数中维护一个valid_versions.json白名单由FAE团队根据客户订单配置烧录时注入设备EEPROM。只有白名单内的版本才允许启动。这堵住了“用A客户固件烧B客户设备”的漏洞。5. 常见问题速查表与独家排错心法再完美的体系也会遇到意外。以下是我在产线支持中整理的TOP10问题及独家解法。每一条都来自真实火线。问题现象根本原因快速定位方法终极解决方案我的排错心得Keil5烧录失败提示Cannot access targetST-Link固件版本过旧不支持STM32F405的SWD协议扩展运行ST-Link_CLI -c查看输出中的ST-LINK Firmware version对比官网支持列表升级ST-Link固件至V3.J25.S4或更高。切记升级后必须重启ST-Link否则新固件不生效别急着换线或换电脑90%的Cannot access都是固件问题。升级固件只需2分钟比排查硬件快10倍。JFlash烧录成功但设备不启动串口无输出JFlash的Program选项未勾选Verify programming且芯片Flash存在坏块写入失败但未报错用JFlash的Memory Browser功能手动读取烧录起始地址如0x08000000的前16字节与固件bin文件头比对在JFlash中务必勾选Verify programming和Use checksum。对于老旧芯片启用Skip bad blocks选项JFlash的GUI太友好反而掩盖了关键选项。把Verify设为默认勾选写入团队SOP第一条。VS Code编译成功烧录却报File not foundVS Code的tasks.json中args路径使用了相对路径./build/firmware.bin而烧录脚本在另一目录执行路径解析失败在烧录脚本开头添加echo Current dir: $(pwd)和ls -la ./build/确认文件是否存在所有路径必须使用绝对路径。在tasks.json中用${workspaceFolder}变量${workspaceFolder}/build/firmware.bin新人最容易栽在这里。教他们第一件事打开终端pwd然后ls再cat路径三步确认路径有效性。ESP32烧录后WiFi连接不稳定esptool.py烧录时未指定--flash_mode dio而硬件设计使用DIO模式工具默认QIO导致时序错误查看原理图中FLASH_QIO/FLASH_DIO跳线运行esptool.py chip_id确认芯片型号再查ESP-IDF文档确认推荐模式烧录命令必须显式指定esptool.py --chip esp32s3 --port /dev/ttyUSB0 --baud 921600 write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x0 firmware.binESP32系列芯片的flash模式是硬件相关的不是软件可配的。烧录前必须对照原理图和芯片手册一个字都不能错。RK3588烧录后PCIe设备无法识别rkdeveloptool烧录bootloader分区时未擦除trust分区导致旧版ATFARM Trusted Firmware残留与新版uboot不兼容使用rkdeveloptool rd 0x0 0x10000读取trust分区前16KB用hexdump比对是否为全FF烧录RK3588必须按顺序先擦除trust和bootloader分区再烧录bootloader最后烧录uboot。顺序错一步全盘皆输。RK3588的启动链是ROM - trust - bootloader - uboot - kernel。trust分区就像启动密码旧密码锁住新bootloader。务必擦净再烧。STM32F405烧录后USB设备无法枚举Keil5的Options for Target - Debug - Settings - SWO Trace被意外启用占用PA3引脚SWO而该引脚在硬件上复用为USB_DM在Keil5中Project - Options - Debug - Settings - Trace取消勾选Enable Trace禁用所有与硬件无关的调试功能。SWO、ITM、ETM等除非真需要trace否则一律关闭。PA3/PA2必须留给USB。USB是最脆弱的外设。只要PA2/PA3被任何功能占用USB就必然失败。把它当作黄金法则USB引脚神圣不可侵犯。Jetson Orin Nano烧录后GPU驱动加载失败l4t_flash工具烧录时未使用--no-flash参数先生成bootloader镜像导致bpmp固件版本与kernel不匹配运行sudo /opt/nvidia/jetpack/jetpack_manager查看BPMP Firmware Version与Kernel Version是否匹配Jetson烧录必须分两步1.sudo ./flash.sh --no-flash jetson-orin-nano-devkit mmcblk0p1生成镜像2.sudo ./flash.sh jetson-orin-nano-devkit mmcblk0p1烧录。跳过第一步必出问题。Jetson的bpmpBoot and Power Management Processor是独立协处理器它的固件必须与kernel ABI严格匹配。--no-flash生成的bootloader目录里bpmp和kernel版本号必须一致。量产烧录机台批量失败错误码0x80070005Windows系统权限问题。烧录脚本以普通用户运行但st-link驱动需要管理员权限访问USB设备运行whoami /groups确认用户是否在PlugConnectedUsers组检查Device Manager中ST-Link设备是否有黄色感叹号所有烧录机台必须以Administrator权限运行烧录脚本。在快捷方式属性中勾选Run as administrator。或使用psexec -i -s提升权限。Windows的USB权限模型很诡异。普通用户能看到ST-Link但无法写入。这不是驱动问题是权限问题。给脚本加个管理员盾牌一劳永逸。烧录报告中usb_voltage显示4.9V远超标称5VADS1115 ADC的参考电压VREF被错误配置为2.048V而实际供电为3.3V导致读数放大1.6倍
返回列表