- 1. 1. ⚠️ Flash 规划(升级失败/变砖的根源)
- 2. 2. API 总表
- 3. 3. 应用:SD 卡本地升级
- 4. 3.1 升级包准备
- 5. 3.2 检测盘符 + 找 a.bin
- 6. 3.3 核心升级流程(ota.lua)
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_start = 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_start) > flashsize then
set_string(VT_LW, useraddr.text, "ota.bin 文件大小超过,无法升级!!!")
else
set_string(VT_LW, useraddr.text, "开始升级!!!")
set_uint32(VT_LW, useraddr.ota_data, fsize)
ota.set_upgrade(path.."/"..ota_filename)
end
end
end
end
3.3 核心升级流程(ota.lua)
function ota.set_upgrade(path)
local TransferSize = 0
local size = 0
if file_open(path, 0) == true then
size = file_size()
if size < (flashsize - ota_addr_start) then
ota_destroy() -- 消除残留 OTA 数据
local sdota_addr = ota_init("0123456789abcdef", size, ota_addr_start)
-- 计算尾包补零长度
local size_complement = 0
if size % 2048 ~= 0 then
size_complement = 2048 - (size % 2048)
end
while true do
local rddata = file_read(2048) -- 流式读 2048
if #(rddata) < 2048 then -- 尾包补 0x00
for i = (#(rddata) + 1), 2048 do rddata[i] = 0x00 end
end
TransferSize = TransferSize + #(rddata)
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(rddata) -- 写入 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升级」,版权归大彩科技所有。
发表回复