VisualHMI OTA 업그레이드:ota_init/ota_write 与 SD 卡自动업그레이드

무료무료 기술 자료

이 글은 바로 읽을 수 있으며 기초 학습과 검색 유입에 적합합니다.

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 卡根目录。

VisualHMI OTA 升级:ota_init/ota_write 与 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
end

3.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) 之后체크섬失败会停在回调里给你机会处理,解压成功就自动重启进업그레이드。

四个坑:①md5 매개변수是固定串「0123456789abcdef」,不是文件的真实 MD5,别自作聪明去算文件哈希;②addr 必须 ≥ Flash 一半且区域连续空闲,块주소占了高주소区就升不了;③업그레이드包不能超过 Flash 一半,10.62MB 的剩余空间不等于能放 10.62MB 的包;④업그레이드前先 ota_destroy() 清残留,ota_write 的尾包不足 2048 会自动补零,你不需要自己处理对齐。업그레이드中断电 = 变砖,量产前务必反复验证업그레이드流程。

整理自 广州大彩科技 VisualHMI 개발문서(hmi-doc.gz-dc.com)LUA 튜토리얼「OTA업그레이드」,版权归大彩科技所有。

실제 프로젝트에 이 자료를 활용하시겠습니까?

도구 센터에서 프레임 분석, CRC 검증, 장비 디버깅을 진행하거나 요청을 제출하여 선정 및 연동 제안을 받아보세요.

엔지니어 회원

이 글을 실행 가능한 디버깅 자료로 활용하세요

가입하면 고급 프레임 분석, 자료 패키지 다운로드, 코드 예제, 엔지니어링 사례, 우선 기술 지원을 이용할 수 있어 실제 프로젝트 납품에 적합합니다.

고급 도구 무제한 이용
자료 패키지와 코드 패키지
완전한 엔지니어링 사례 라이브러리
우선 기술 지원 채널

답글 작성

이메일 주소는 공개되지 않습니다. 必填项已用 * 标注