OTA 업그레이드 API:HMI 的업그레이드逻辑与통신 프로토콜、데이터来源完全解耦——不管업그레이드데이터来自主板시리얼 포트、以太网、Wi-Fi 还是 4G,不管上位机用사용자 정의 프로토콜、Modbus 还是 HTTP,HMI 只负责通过표준 API 把收到的데이터写进指定 Flash 区,체크섬解压成功后自动重启업그레이드。适用 HMI&M 시리즈&Dx 시리즈。
1. ⚠️ Flash 规划(업그레이드失败/变砖的根源)
以 HMI80480M070 为例(표준品 128Mbit = 16MB):
| 项目 | 大小 |
|---|---|
| Flash 总容量 | 16 MB |
| 系统固件(OS+驱动,M 시리즈) | 1 MB(DH 시리즈 2 MB) |
| 当前엔지니어링(private) | 4.38 MB |
| 已用合计 | 5.38 MB,剩 ≈10.62 MB |
| OTA 시작주소要求 | 必须 ≥ 8 MB(Flash 总量一半) |
两条铁律:①OTA 시작주소必须从 Flash 后半部分开始(哪怕剩余 10.62MB 也要从 ≥8MB 起),避免新旧엔지니어링交叉覆盖,업그레이드过程中当前系统才能继续跑;②OTA 쓰기区必须连续且空闲——如果你用「块주소」功能占了高주소区(比如 10~12MB),或者업그레이드包超过 Flash 一半(≈10.62MB 的包),都不可업그레이드。
2. API 总表
| 函数 | 매개변수 | 설명 |
|---|---|---|
ota_init(md5, filesize, addr) | md5 固定 "0123456789abcdef";filesize 与 .bin 实际大小严格一致;addr ≥ Flash 一半 | 설정업그레이드目标,准备수신固件데이터 |
ota_write(writeTb) | 바이트表,≤2048,不足自动补 0x00 | 分块写固件到 Flash 区 |
ota_check_upgrade(state) | 必须传 1 | 触发完整性체크섬 + 解压 + 업그레이드 |
ota_destory() | - | 擦除已写的 OTA 残留데이터(업그레이드前清场) |
on_ota_progress(status, value) | 见下表 | 체크섬/解压进度与结果回调 |
on_ota_progress 的 status/value 组合:
| status | 含义 | value |
|---|---|---|
| 1 | 체크섬过程开始 | 固定 0 |
| 2 | 체크섬结果 | 0=失败(固件损坏/MD5 不일치)/1=成功 |
| 3 | 解压进度 | 0~100 百分比 |
| 4 | 解压结果 | 0=失败/1=成功 → 即将重启 |
3. 적용:SD 卡本地업그레이드
3.1 업그레이드包准备
엔지니어링编译后选择量产下载,生成的文件里有 ota.bin。使用前把 ota.bin 改名为 a.bin 放到 SD 卡根目录。

3.2 检测盘符 + 找 a.bin
ota_filename = "a.bin"
ota_addr_시작 = 8 * 1024 * 1024 -- OTA 시작주소(至少 Flash 一半)
flashsize = 16 * 1024 * 1024 -- Flash 总大小
function on_update(slave, vtype, addr)
if vtype == VT_LW and addr == useraddr.ota_swich then
if sd_dir ~= 0 then
list_dir(sd_dir) -- 先看 SD 卡
elseif usb_dir ~= 0 then
list_dir(usb_dir) -- 再看 U 盘
else
set_string(VT_LW, useraddr.text, "检测不到SD卡和USB,无法OTA업그레이드!!!")
end
end
end
function on_list_dir(path, filename, type, fsize)
if type == 1 then
if filename == ota_filename then
set_string(VT_LW, useraddr.text, "文件:"..ota_filename.." 已检测到")
if (fsize + ota_addr_시작) > flashsize then
set_string(VT_LW, useraddr.text, "ota.bin 文件大小超过,无法업그레이드!!!")
else
set_string(VT_LW, useraddr.text, "开始업그레이드!!!")
set_uint32(VT_LW, useraddr.ota_데이터, fsize)
ota.set_upgrade(path.."/"..ota_filename)
end
end
end
end3.3 核心업그레이드流程(ota.lua)
function ota.set_upgrade(path)
local TransferSize = 0
local size = 0
if file_열기(path, 0) == true then
size = file_size()
if size < (flashsize - ota_addr_시작) then
ota_destroy() -- 消除残留 OTA 데이터
local sdota_addr = ota_init("0123456789abcdef", size, ota_addr_시작)
-- 계산尾包补零길이
local size_complement = 0
if size % 2048 ~= 0 then
size_complement = 2048 - (size % 2048)
end
while true do
local rd데이터 = file_read(2048) -- 流式读 2048
if #(rd데이터) < 2048 then -- 尾包补 0x00
for i = (#(rd데이터) + 1), 2048 do rd데이터[i] = 0x00 end
end
TransferSize = TransferSize + #(rd데이터)
local prg = string.format("%.1f", (TransferSize * 100) / (size + size_complement))
set_uint16(VT_LW, useraddr.progress, math.modf((TransferSize * 1000) / size))
set_string(VT_LW, useraddr.text, "下载进度 : "..prg.." %")
refresh_screen()
ota_write(rd데이터) -- 쓰기 Flash,不足补零
if size <= TransferSize then break end
end
file_close()
ota_check_upgrade(1) -- 체크섬、解压
end
end
end
function on_ota_progress(status, value)
if status == 1 and value == 0 then
set_string(VT_LW, useraddr.text, "체크섬开始")
elseif status == 2 then
if value == 0 then set_string(VT_LW, useraddr.text, "체크섬失败")
elseif value == 1 then set_string(VT_LW, useraddr.text, "체크섬成功") end
elseif status == 3 then
set_uint16(VT_LW, useraddr.progress, value * 10)
set_string(VT_LW, useraddr.text, "解压进度 : "..value.." %")
refresh_screen()
elseif status == 4 then
if value == 0 then set_string(VT_LW, useraddr.text, "解压失败")
elseif value == 1 then set_string(VT_LW, useraddr.text, "解压成功") end
end
end关键点:ota_init 的 filesize 必须和 .bin 实际大小严格一致;写데이터全程流式(每次 ≤2048,尾包补 0x00);ota_check_upgrade(1) 之后체크섬失败会停在回调里给你机会处理,解压成功就自动重启进업그레이드。
整理自 广州大彩科技 VisualHMI 개발문서(hmi-doc.gz-dc.com)LUA 튜토리얼「OTA업그레이드」,版权归大彩科技所有。
답글 작성