03 fota核心库+文件升级/串口升级
作者:孟伟 | 最后修改:2026-04-08
一、FOTA 功能概述
FOTA 是固件远程升级的简称,用于设备固件的远程更新和维护。LuatOS 提供了灵活的 FOTA 升级方案,支持多种升级方式以适应不同的应用场景。
1.1 FOTA 有什么用?
FOTA 功能为物联网设备提供安全可靠的固件更新能力,主要优势包括:
- 远程维护:无需现场操作即可完成设备固件更新
- 故障修复:快速修复已部署设备的软件缺陷
- 功能升级:为设备增加新功能,提升产品价值
- 成本节约:大幅降低设备维护和升级成本
- 安全保障:支持完整性校验,确保升级过程安全可靠
1.2 FOTA 与 FOTA2 选择指南
核心区别总结
fota(底层核心库)
定位: 基础升级,提供最核心的固件写入能力
核心能力:
支持两种写入方式:fota.run() 分段写入 和 fota.file() 文件直接升级
支持内部存储和外部 SPI Flash
提供完整的升级流程控制:init → wait → run/file → isDone → finish
代码特点:
_-- 需要手动控制每个步骤_
fota.init()
while not fota.wait() do sys.wait(100) end
fota.run(buf) _-- 或 fota.file("/update.bin")-- 自行检查状态和重启_
fota2(libfota2 扩展库)
定位: 完整的远程升级解决方案,开箱即用
核心能力:
自动处理 HTTP/HTTPS 网络下载
支持合宙 IoT 平台和自建服务器
内置版本检查、下载、验证全流程
提供详细错误码和回调函数
代码特点:
_-- 一行代码完成升级_
local function fota_cb(ret)
if ret == 0 then
log.info("升级包下载成功,重启模块")
rtos.reboot()
end
end
libfota2.request(fota_cb, opts)
适用场景推荐
选择 fota 的情况:
需要自定义升级数据源
通过串口接收升级包
通过 MQTT、TCP 等自定义协议传输
从 SD 卡、U 盘等外部存储读取
对升级流程有特殊控制需求
需要在升级前后执行特定操作
需要精细控制数据写入时机
需要自定义进度监控逻辑
资源极度受限环境
设备存储空间极小,内存紧张,无法加载额外库
开发测试阶段
需要调试升级过程的每个环节
需要验证自定义升级方案
选择 fota2 的情况:
标准的 HTTP 远程升级
从服务器下载升级包
使用合宙 IoT 平台服务
需要 HTTPS 安全下载
希望快速实现升级功能
不想处理网络下载细节
需要自动版本检查
希望简单的错误处理
生产环境部署
需要稳定的远程升级方案
需要详细的升级状态反馈
支持定时自动检查更新
实际选择建议
新手用户 → 直接选择 fota2
接口简单,学习成本低
内置完整错误处理
适合大多数物联网应用场景
高级用户 → 根据需求选择
标准网络升级 → fota2
自定义数据传输 → fota + 自定义逻辑
一句话总结:用 fota2 省心省力,用 fota 自由灵活
二、演示功能概述
本教程将使用 Air780EPM 开发板演示两种 FOTA 升级方式,主要包括:
(1)文件系统直接升级:通过 luatools 将升级包文件写入到文件系统中,模组读取的升级包文件直接升级;
(2)分段升级:通过分片段接收升级包数据并升级,demo 演示通过虚拟串口分段写入然后升级。
三、准备硬件环境

硬件清单:
- Air780EPM V1.3 版本开发板一块
- TYPE-C USB 数据线一根
硬件连接:
- Air780EPM 开发板通过 TYPE-C USB 口供电
- 外部供电/USB 供电拨动开关拨到 USB 供电一端
- TYPE-C USB 数据线连接开发板和电脑 USB 口
四、软件环境
在开始实践本示例之前,先筹备一下软件环境:
- 烧录工具: Luatools 工具;
- 本demo开发测试时使用的固件为Air780EPM V2016 版本固件,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件Air780EPM固件,Air780EHM固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试
- Python 3 环境:用于运行串口升级的 Python 脚本
- LuatOS 需要的脚本和资源文件
准备好软件环境之后,接下来查看如何烧录项目文件到 Air780EPM 开发板,将本篇文章中演示使用的项目文件烧录到 Air780EPM 开发板中。
五、API 接口说明
详细 FOTA API 文档请参考:https://docs.openluat.com/osapi/core/fota/
六、代码示例介绍
6.1 升级包制作
LuatOS 开发模式下,固件分为两部分:core(底层固件) 和 script(脚本)
远程升级时:可以仅升级 script;也可以同时升级 core+script
仅 script 脚本升级时对于 Air780EXX 系列、Air8000 系列、Air8101 系列是全量升级。
core+script 都升级时对于 Air780EXX 系列、Air8000 系列是差分升级,对于 Air8101 系列是全量升级
Air780EXX 系列、Air8000 系列仅 script 升级时升级包制作:
如果用户只是新增一些自己的脚本逻辑,没有更新底层,可以选择仅脚本升级
更新完自己脚本后,修改版本号,点击生成量产文件,生成的量产文件中以.bin 结尾的就是仅脚本升级的升级包。


Air780EXX 系列、Air8000 系列 core+script 都升级时升级包制作:
每一次 core 的升级都会带来一些网络上的优化(例如信号差时的网络稳定性)以及一些 bug 修复,所以在发布新版本以后,用户可以先测试下 core 对自己脚本有无明显影响或性能提升,然后进行远程 FOTA。
对于含 core 升级的话需要制作差分包,原始版本生成一次量产文件,新版本生成一次量产文件。
针对这两个量产文件,制作一个差分文件,点击到 luatools 的主界面,依次点击图中蓝框所示意的地方(注:必须使用 luatools_3.0.9 及其以上版本,要不差分包升级的时候可能会出问题)

按下图所示选择低版本以及高版本的固件,然后点击开始执行即可,如果不想输出的差分包在 luatools 根目录下,可以自行选择一个输出路径



在你选择的目录下看到如下所示,.bin 文件就是升级差分包。

Air8101 系列升级包制作:
因为此系列都是全量升级,所以在 luatools 中生成一次量产文件就行,生成的量产包如下:

其中 full_fota 文件夹下为 core+script 的全量升级包,script_ota 目录下是单脚本升级的升级包
6.2 文件系统直接升级
6.2.1 核心代码实现 (fota_file.lua)
local function fileUpgradeTask()
-- 等待系统稳定后再开始升级
sys.wait(10000)
log.info("FOTA_FILE", "=== 开始文件系统升级 ===")
-- 步骤1: 初始化FOTA流程
log.info("FOTA_FILE", "初始化FOTA...")
if not fota.init() then
log.error("FOTA_FILE", "FOTA初始化失败")
return
end
-- 步骤2: 等待底层准备就绪
log.info("FOTA_FILE", "等待底层准备...")
while not fota.wait() do
sys.wait(100)
end
log.info("FOTA_FILE", "底层准备就绪")
-- 步骤3: 从文件系统读取升级包并启动升级
local filePath = "/update.bin"
log.info("FOTA_FILE", "开始读取升级文件:", filePath)
local result, isDone, cache = fota.file(filePath)
log.info("FOTA_FILE", "升级文件写入flash中的fota分区结果", result, isDone, cache)
-- 步骤4: 结束写入fota分区
log.info("FOTA_FILE", "结束写入fota分区...")
local result, isDone = fota.isDone()
log.info("FOTA_FILE", "写入fota分区状态", "结果:", result, "完成:", isDone)
if result then
-- 步骤5: 处理写入结果
if isDone then
-- 升级文件成功写入flash中的fota分区,准备重启设备;
-- 设备重启后,在初始化阶段的运行过程中会自动应用fota分区中的数据完成升级,最终升级结果可以通过观察日志中的版本号来区分。
log.info("FOTA_FILE", "升级成功,准备重启设备")
-- 调用fota.finish(true)结束升级流程,参数true表示正确走完流程。
fota.finish(true)
-- 可选:删除升级包文件
-- os.remove("/update.bin")
sys.wait(2000)
rtos.reboot()
else
log.error("FOTA_FILE", "升级失败")
-- -- 调用fota.finish(false)结束升级流程,参数false表示升级流程失败。
fota.finish(false)
end
else
log.error("FOTA_FILE", "升级失败:检查写入状态失败")
-- -- 调用fota.finish(false)结束升级流程,参数false表示升级流程失败。
fota.finish(false)
end
end
-- 启动文件升级任务
sys.taskInit(fileUpgradeTask)
6.2.2 文件系统升级操作步骤
- 修改配置:在
main.lua中取消require("fota_file")的注释,注释掉require("fota_uart") - 制作升级包:按照 6.1 章节流程来制作升级包
-
烧录文件:
-
使用 Luatools 烧录内核固件和脚本代码
- 通过"烧录文件系统"功能将升级包文件烧录到设备中
- 自动升级:设备启动后会自动检测并执行升级流程
注意:"烧录文件系统"功能使用:
将制作好的升级包修改名字为 update.bin,然后放到一个空文件夹中,在 luatools 的"烧录文件系统"功能栏中选中这个文件夹,点击下载即可;烧录成功后,update.bin 会在文件系统根目录下,既路径为"/update.bin"

6.2.3 运行日志
[2025-10-24 17:56:47.892][000000005.840] D/mobile bearer act 0, result 0
[2025-10-24 17:56:47.902][000000005.841] D/mobile NETIF_LINK_ON -> IP_READY
[2025-10-24 17:56:47.911][000000005.890] D/mobile TIME_SYNC 0
[2025-10-24 17:56:48.203][000000006.204] I/user.fota version 1.0.0
[2025-10-24 17:56:49.208][000000007.204] I/user.fota version 1.0.0
[2025-10-24 17:56:50.205][000000008.204] I/user.fota version 1.0.0
[2025-10-24 17:56:51.205][000000009.205] I/user.fota version 1.0.0
[2025-10-24 17:56:52.199][000000010.205] I/user.fota version 1.0.0
[2025-10-24 17:56:52.207][000000010.210] I/user.FOTA_FILE === 开始文件系统升级 ===
[2025-10-24 17:56:52.217][000000010.210] I/user.FOTA_FILE 初始化FOTA...
[2025-10-24 17:56:52.224][000000010.226] I/user.FOTA_FILE 等待底层准备...
[2025-10-24 17:56:52.234][000000010.226] I/user.FOTA_FILE 底层准备就绪
[2025-10-24 17:56:52.242][000000010.227] I/user.FOTA_FILE 开始读取升级文件: /update.bin
[2025-10-24 17:56:52.251][000000010.230] I/fota write common data
[2025-10-24 17:56:52.309][000000010.311] I/fota common data done, now checking 0
[2025-10-24 17:56:52.317][000000010.312] I/fota common data md5 ok
[2025-10-24 17:56:52.325][000000010.312] I/fota only common data
[2025-10-24 17:56:52.358][000000010.362] I/fota fota type 0 ok!, wait reboot
[2025-10-24 17:56:52.370][000000010.362] I/user.FOTA_FILE 升级文件写入flash中的fota分区结果 true true 0
[2025-10-24 17:56:52.380][000000010.363] I/user.FOTA_FILE 结束写入fota分区...
[2025-10-24 17:56:52.389][000000010.363] I/user.FOTA_FILE 写入fota分区状态 结果: true 完成: true
[2025-10-24 17:56:52.402][000000010.363] I/user.FOTA_FILE 升级成功,准备重启设备
[2025-10-24 17:56:53.199][000000011.205] I/user.fota version 1.0.0
[2025-10-24 17:56:54.197][000000012.205] I/user.fota version 1.0.0
[2025-10-24 17:56:55.575][000000000.000] main_entry 708:SDK base line V017_pb18.002
[2025-10-24 17:56:55.589][000000000.008] am_service_init 1154:Air780EPM_A11
[2025-10-24 17:56:55.604][000000000.008] am_get_chip_type 635:6bef6,19,24,c7,0,EC718
[2025-10-24 17:56:55.618][000000000.049] bsp_user_init_io 312:io volt 3.3v 21
[2025-10-24 17:56:55.630][000000000.050] BSP_CustomInit 558:hardfault mode init 4
[2025-10-24 17:56:55.643][000000000.050] Uart_ChangeBR 1338:uart0, 6000000 6028985 26000000 69
[2025-10-24 17:56:55.654][000000000.072] I/pm poweron: Power/Reset
[2025-10-24 17:56:55.668][000000000.181] self_info 127:model Air780EPM_A11 imei 862419074066563
[2025-10-24 17:56:55.682][000000000.181] self_info 129:firmware[1] BASIC
[2025-10-24 17:56:55.692][000000000.181] self_info 131:zone(kbytes) fs 168 script 256
[2025-10-24 17:56:55.704][000000000.181] I/main LuatOS@Air780EPM base 25.03 bsp V2016 32bit
[2025-10-24 17:56:55.720][000000000.181] I/main ROM Build: Oct 9 2025 21:32:15
[2025-10-24 17:56:55.734][000000000.183] W/pins /luadb/pins_Air780epmjson not exist!!
[2025-10-24 17:56:55.749][000000000.186] D/main loadlibs luavm 1048568 14888 14888
[2025-10-24 17:56:55.762][000000000.186] D/main loadlibs sys 2375432 53100 58844
[2025-10-24 17:56:55.772][000000000.186] D/main loadlibs psram 2375432 53184 58844
[2025-10-24 17:56:56.105][000000001.206] I/user.fota version 1.0.1
[2025-10-24 17:56:56.118][000000001.206] I/user.fota123456789
[2025-10-24 17:56:57.105][000000002.206] I/user.fota version 1.0.1
[2025-10-24 17:56:57.111][000000002.207] I/user.fota123456789
[2025-10-24 17:56:58.108][000000003.207] I/user.fota version 1.0.1
[2025-10-24 17:56:58.116][000000003.208] I/user.fota123456789
6.3 串口分段升级
6.3.1 核心代码实现 (fota_uart.lua)
-- 定义所需要的UART编号
-- uart_id = 1 -- UART1, 通常也是MAIN_UART
local uart_id = uart.VUART_0 -- 虚拟USB串口
-- 全局变量
local uart_zbuff = nil
local uart_fota_state = 0
local uart_rx_counter = 0
local uart_fota_writed = 0
local upgrade_active = false -- 升级是否激活标志
-- 按键回调函数 - Power键
local function power_key_callback()
if not upgrade_active then
log.info("FOTA_UART", "Power键按下,启动串口升级模式")
-- 初始化串口和缓冲区
uart_zbuff = zbuff.create(1024)
uart.setup(uart_id, 115200)
uart.on(uart_id, "receive", uart_cbfun)
upgrade_active = true
uart_fota_state = 0
uart_rx_counter = 0
uart_fota_writed = 0
-- 发布事件,唤醒升级任务
sys.publish("UART_UPGRADE_START")
else
log.info("FOTA_UART", "升级模式已激活,请等待当前升级完成")
end
end
-- 配置Power键
gpio.setup(gpio.PWR_KEY, power_key_callback, gpio.PULLUP, gpio.FALLING)
gpio.debounce(gpio.PWR_KEY, 200, 1) -- 200ms去抖
-- 清理资源的函数
local function cleanup_resources()
if uart_zbuff then
uart_zbuff:del()
uart_zbuff = nil
end
uart.close(uart_id) -- 关闭串口
upgrade_active = false
uart_fota_state = 0
log.info("FOTA_UART", "资源已清理,串口已关闭")
end
-- 串口接收回调函数
function uart_cbfun(id, len)
if not upgrade_active or not uart_zbuff then
return
end
-- 防御缓冲区超标的情况
if uart_zbuff:used() > 8192 then
log.warn("fota", "uart_zbuff待处理的数据太多了,强制清空")
uart_zbuff:del()
end
while true do
local len = uart.rx(id, uart_zbuff)
if len <= 0 then
break
end
uart_rx_counter = uart_rx_counter + len
log.info("uart", "收到数据", len, "累计", uart_rx_counter)
-- 首次收到数据即发布事件,唤醒升级任务
if uart_fota_state == 0 then
sys.publish("UART_FOTA")
end
end
end
-- 串口升级任务
local function uartUpgradeTask()
local fota_state = 0 -- 0还没开始, 1进行中
while true do
-- 等待升级启动信号
sys.waitUntil("UART_UPGRADE_START")
log.info("FOTA_UART", "升级任务已启动,等待数据...")
while upgrade_active do
-- 等待升级数据到来
sys.waitUntil("UART_FOTA", 1000)
if not upgrade_active then break end
local used = uart_zbuff and uart_zbuff:used() or 0
if used > 0 then
if fota_state == 0 then
-- 等待FOTA的状态
if used > 5 then
local data = uart_zbuff:query()
uart_zbuff:del()
-- 如果接受到 #FOTA\n 代表数据要来了
if data:startsWith("#FOTA") and data:endsWith("\n") then
fota_state = 1
log.info("fota", "检测到fota起始标记,进入FOTA状态", data)
if fota.init() then
-- 固件数据发送端应该在收到#FOTA RDY\n之后才开始发送数据
uart.write(uart_id, "#FOTA RDY\n")
else
log.error("FOTA_UART", "FOTA初始化失败")
cleanup_resources()
break
end
end
end
else
-- 已进入升级状态:把收到的数据喂给fota.run
uart_fota_writed = uart_fota_writed + used
log.info("准备写入fota包", used, "累计写入", uart_fota_writed)
local result, isDone, cache = fota.run(uart_zbuff)
log.debug("fota.run", result, isDone, cache)
uart_zbuff:del() -- 清空缓冲区
if not result then
-- 写入失败,退出升级状态并通知上位机
log.error("fota", "出错了", result, isDone, cache)
uart.write(uart_id, "#FOTA ERR\n")
-- 调用fota.finish(false)结束升级流程,参数false表示升级流程失败。
fota.finish(false)
cleanup_resources()
fota_state = 0
break
elseif isDone then
-- 全部数据写入完成,等待底层校验结束
local success = false
for i = 1, 30 do -- 最多等待3秒
sys.wait(100)
local succ, fotaDone = fota.isDone()
if not succ then
log.error("fota", "校验过程出错")
uart.write(uart_id, "#FOTA ERR\n")
fota.finish(false)
cleanup_resources()
fota_state = 0
break
end
if fotaDone then
uart_fota_state = 1
-- 升级文件成功写入flash中的fota分区,准备重启设备;
log.info("fota", "已完成,1s后重启")
-- 调用fota.finish(true)结束升级流程,参数true表示正确走完流程。
fota.finish(true)
-- 反馈给上位机
uart.write(uart_id, "#FOTA OK\n")
sys.wait(1000)
success = true
rtos.reboot()
break
end
end
if not success then
log.error("fota", "校验超时")
uart.write(uart_id, "#FOTA ERR\n")
fota.finish(false)
cleanup_resources()
fota_state = 0
end
break
else
-- 单包写入成功,通知上位机继续下发
log.info("fota", "单包写入完成", used, "等待下一个包")
uart.write(uart_id, "#FOTA NEXT\n")
end
end
end
end
-- 重置状态,等待下次升级
fota_state = 0
uart_fota_state = 0
uart_rx_counter = 0
uart_fota_writed = 0
end
end
-- 启动串口升级任务
sys.taskInit(uartUpgradeTask)
6.3.2 串口升级操作步骤
1、搭建好演示硬件环境
2、修改 demo 脚本代码,确保 main.lua 中已注释 require("fota_file"),取消 require("fota_uart") 的注释
3、使用 Luatools 制作升级包,先把新旧版本分别生成量产文件,然后再制作升级包,工具上栏 luatOS-> 固件工具-> 差分包/整包升级包制作,将制作好的升级包放在 main.py 同级目录下
4、Luatools 烧录内核固件和修改前的 demo 脚本代码,烧录成功后,自动开机运行。
5、确认设备连接到电脑的串口(虚拟 USB 串口)
6、按一下核心板上的 Powerkey 键,然后运行 Python 脚本发送升级包:
python main.py
7、脚本会自动寻找设备虚拟串口,发送升级命令并传输 fota_uart.bin 文件
8、设备接收并验证升级包,升级成功后会自动重启
9、可以看到如下日志:
注意:如果是使用虚拟串口直接使用 python main.py 来运行程序即可,如果是使用物理串口,就指定串口运行:
# 指定串口
python fota_script.py -p COM1
6.3.3 串口通讯过程说明
串口升级采用简单的文本协议进行握手和数据传输控制:
协议流程:
- 上位机发送:
#FOTA\n - 设备回复:
#FOTA RDY\n - 上位机发送:256 字节数据包
- 设备回复:
#FOTA NEXT\n(请求下一包) - 重复步骤 3-4 直到所有数据发送完成
- 设备回复:
#FOTA OK\n(升级成功) - 设备自动重启
6.3.4 运行日志
串口分段升级日志解读:
- USB 虚拟串口连接,收到#FOTA 起始指令
- 开始分段接收升级包,每次 256 字节,累计 5751 字节
- 所有数据包写入成功,MD5 校验通过
- 升级完成,重启
- 重启后新版本 1.0.2 运行,新增日志确认升级成功
结果:串口 FOTA 升级完全成功,版本从 1.0.0 升级到 1.0.2。
[2025-10-24 19:04:42.229][000000130.217] I/user.fota version 1.0.0
[2025-10-24 19:04:43.235][000000131.217] I/user.fota version 1.0.0
[2025-10-24 19:04:44.239][000000132.217] I/user.fota version 1.0.0
[2025-10-24 19:04:44.896][000000132.888] luat_usb_recv_cb 447:usb serial connected
[2025-10-24 19:04:44.909][000000132.889] I/user.uart 收到数据 6 累计 6
[2025-10-24 19:04:44.921][000000132.891] I/user.fota 检测到fota起始标记,进入FOTA状态 #FOTA
[2025-10-24 19:04:45.238][000000133.217] I/user.fota version 1.0.0
[2025-10-24 19:04:45.916][000000133.894] I/user.uart 收到数据 256 累计 262
[2025-10-24 19:04:45.931][000000133.895] I/user.准备写入fota包 256 累计写入 256
[2025-10-24 19:04:45.939][000000133.896] I/fota write common data
[2025-10-24 19:04:45.957][000000133.896] D/user.fota.run true false 1
[2025-10-24 19:04:45.968][000000133.896] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:46.227][000000134.217] I/user.fota version 1.0.0
[2025-10-24 19:04:46.929][000000134.906] I/user.uart 收到数据 256 累计 518
[2025-10-24 19:04:46.942][000000134.907] I/user.准备写入fota包 256 累计写入 512
[2025-10-24 19:04:46.953][000000134.908] D/user.fota.run true false 1
[2025-10-24 19:04:46.964][000000134.908] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:47.227][000000135.217] I/user.fota version 1.0.0
[2025-10-24 19:04:47.940][000000135.917] I/user.uart 收到数据 256 累计 774
[2025-10-24 19:04:47.950][000000135.918] I/user.准备写入fota包 256 累计写入 768
[2025-10-24 19:04:47.963][000000135.919] D/user.fota.run true false 1
[2025-10-24 19:04:47.971][000000135.919] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:48.238][000000136.217] I/user.fota version 1.0.0
[2025-10-24 19:04:48.956][000000136.933] I/user.uart 收到数据 256 累计 1030
[2025-10-24 19:04:48.965][000000136.933] I/user.准备写入fota包 256 累计写入 1024
[2025-10-24 19:04:48.976][000000136.934] D/user.fota.run true false 1
[2025-10-24 19:04:48.986][000000136.934] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:49.237][000000137.217] I/user.fota version 1.0.0
[2025-10-24 19:04:49.968][000000137.945] I/user.uart 收到数据 256 累计 1286
[2025-10-24 19:04:49.977][000000137.946] I/user.准备写入fota包 256 累计写入 1280
[2025-10-24 19:04:49.987][000000137.946] D/user.fota.run true false 1
[2025-10-24 19:04:49.995][000000137.947] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:50.231][000000138.217] I/user.fota version 1.0.0
[2025-10-24 19:04:50.981][000000138.957] I/user.uart 收到数据 256 累计 1542
[2025-10-24 19:04:50.990][000000138.958] I/user.准备写入fota包 256 累计写入 1536
[2025-10-24 19:04:51.008][000000138.958] D/user.fota.run true false 1
[2025-10-24 19:04:51.016][000000138.959] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:51.229][000000139.217] I/user.fota version 1.0.0
[2025-10-24 19:04:51.992][000000139.969] I/user.uart 收到数据 256 累计 1798
[2025-10-24 19:04:52.002][000000139.970] I/user.准备写入fota包 256 累计写入 1792
[2025-10-24 19:04:52.013][000000139.970] D/user.fota.run true false 1
[2025-10-24 19:04:52.020][000000139.971] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:52.228][000000140.217] I/user.fota version 1.0.0
[2025-10-24 19:04:53.007][000000140.984] I/user.uart 收到数据 256 累计 2054
[2025-10-24 19:04:53.019][000000140.985] I/user.准备写入fota包 256 累计写入 2048
[2025-10-24 19:04:53.029][000000140.985] D/user.fota.run true false 1
[2025-10-24 19:04:53.037][000000140.985] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:53.226][000000141.217] I/user.fota version 1.0.0
[2025-10-24 19:04:54.005][000000141.997] I/user.uart 收到数据 256 累计 2310
[2025-10-24 19:04:54.019][000000141.998] I/user.准备写入fota包 256 累计写入 2304
[2025-10-24 19:04:54.034][000000141.998] D/user.fota.run true false 1
[2025-10-24 19:04:54.044][000000141.999] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:54.225][000000142.217] I/user.fota version 1.0.0
[2025-10-24 19:04:55.022][000000142.998] I/user.uart 收到数据 256 累计 2566
[2025-10-24 19:04:55.032][000000142.999] I/user.准备写入fota包 256 累计写入 2560
[2025-10-24 19:04:55.042][000000143.000] D/user.fota.run true false 1
[2025-10-24 19:04:55.050][000000143.000] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:55.240][000000143.217] I/user.fota version 1.0.0
[2025-10-24 19:04:56.035][000000144.012] I/user.uart 收到数据 256 累计 2822
[2025-10-24 19:04:56.044][000000144.013] I/user.准备写入fota包 256 累计写入 2816
[2025-10-24 19:04:56.054][000000144.013] D/user.fota.run true false 1
[2025-10-24 19:04:56.060][000000144.014] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:56.237][000000144.217] I/user.fota version 1.0.0
[2025-10-24 19:04:57.048][000000145.024] I/user.uart 收到数据 256 累计 3078
[2025-10-24 19:04:57.063][000000145.025] I/user.准备写入fota包 256 累计写入 3072
[2025-10-24 19:04:57.076][000000145.026] D/user.fota.run true false 1
[2025-10-24 19:04:57.088][000000145.026] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:57.235][000000145.217] I/user.fota version 1.0.0
[2025-10-24 19:04:58.057][000000146.034] I/user.uart 收到数据 256 累计 3334
[2025-10-24 19:04:58.065][000000146.035] I/user.准备写入fota包 256 累计写入 3328
[2025-10-24 19:04:58.076][000000146.035] D/user.fota.run true false 1
[2025-10-24 19:04:58.085][000000146.035] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:58.228][000000146.217] I/user.fota version 1.0.0
[2025-10-24 19:04:59.070][000000147.048] I/user.uart 收到数据 256 累计 3590
[2025-10-24 19:04:59.079][000000147.049] I/user.准备写入fota包 256 累计写入 3584
[2025-10-24 19:04:59.085][000000147.049] D/user.fota.run true false 1
[2025-10-24 19:04:59.094][000000147.049] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:04:59.227][000000147.217] I/user.fota version 1.0.0
[2025-10-24 19:05:00.083][000000148.061] I/user.uart 收到数据 256 累计 3846
[2025-10-24 19:05:00.096][000000148.062] I/user.准备写入fota包 256 累计写入 3840
[2025-10-24 19:05:00.109][000000148.062] D/user.fota.run true false 1
[2025-10-24 19:05:00.121][000000148.062] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:00.240][000000148.217] I/user.fota version 1.0.0
[2025-10-24 19:05:01.093][000000149.070] I/user.uart 收到数据 256 累计 4102
[2025-10-24 19:05:01.102][000000149.071] I/user.准备写入fota包 256 累计写入 4096
[2025-10-24 19:05:01.112][000000149.071] D/user.fota.run true false 1
[2025-10-24 19:05:01.119][000000149.071] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:01.233][000000149.217] I/user.fota version 1.0.0
[2025-10-24 19:05:02.090][000000150.082] I/user.uart 收到数据 256 累计 4358
[2025-10-24 19:05:02.102][000000150.083] I/user.准备写入fota包 256 累计写入 4352
[2025-10-24 19:05:02.136][000000150.116] D/user.fota.run true false 1
[2025-10-24 19:05:02.144][000000150.116] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:02.229][000000150.217] I/user.fota version 1.0.0
[2025-10-24 19:05:03.117][000000151.094] I/user.uart 收到数据 256 累计 4614
[2025-10-24 19:05:03.144][000000151.095] I/user.准备写入fota包 256 累计写入 4608
[2025-10-24 19:05:03.153][000000151.095] D/user.fota.run true false 1
[2025-10-24 19:05:03.162][000000151.096] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:03.226][000000151.216] I/user.fota version 1.0.0
[2025-10-24 19:05:04.118][000000152.095] I/user.uart 收到数据 256 累计 4870
[2025-10-24 19:05:04.128][000000152.096] I/user.准备写入fota包 256 累计写入 4864
[2025-10-24 19:05:04.138][000000152.097] D/user.fota.run true false 1
[2025-10-24 19:05:04.152][000000152.097] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:04.227][000000152.216] I/user.fota version 1.0.0
[2025-10-24 19:05:05.133][000000153.108] I/user.uart 收到数据 256 累计 5126
[2025-10-24 19:05:05.147][000000153.109] I/user.准备写入fota包 256 累计写入 5120
[2025-10-24 19:05:05.167][000000153.109] D/user.fota.run true false 1
[2025-10-24 19:05:05.179][000000153.110] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:05.226][000000153.217] I/user.fota version 1.0.0
[2025-10-24 19:05:06.126][000000154.117] I/user.uart 收到数据 256 累计 5382
[2025-10-24 19:05:06.138][000000154.118] I/user.准备写入fota包 256 累计写入 5376
[2025-10-24 19:05:06.150][000000154.119] D/user.fota.run true false 1
[2025-10-24 19:05:06.161][000000154.119] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:06.233][000000154.216] I/user.fota version 1.0.0
[2025-10-24 19:05:07.155][000000155.132] I/user.uart 收到数据 256 累计 5638
[2025-10-24 19:05:07.167][000000155.133] I/user.准备写入fota包 256 累计写入 5632
[2025-10-24 19:05:07.181][000000155.133] D/user.fota.run true false 1
[2025-10-24 19:05:07.192][000000155.133] I/user.fota 单包写入完成 256 等待下一个包
[2025-10-24 19:05:07.234][000000155.216] I/user.fota version 1.0.0
[2025-10-24 19:05:08.170][000000156.147] I/user.uart 收到数据 113 累计 5751
[2025-10-24 19:05:08.189][000000156.148] I/user.准备写入fota包 113 累计写入 5745
[2025-10-24 19:05:08.209][000000156.177] I/fota common data done, now checking 0
[2025-10-24 19:05:08.232][000000156.179] I/fota common data md5 ok
[2025-10-24 19:05:08.256][000000156.179] I/fota only common data
[2025-10-24 19:05:08.268][000000156.213] I/fota fota type 0 ok!, wait reboot
[2025-10-24 19:05:08.278][000000156.213] D/user.fota.run true true 0
[2025-10-24 19:05:08.287][000000156.217] I/user.fota version 1.0.0
[2025-10-24 19:05:08.324][000000156.314] I/user.fota 已完成,1s后重启
[2025-10-24 19:05:09.227][000000157.217] I/user.fota version 1.0.0
[2025-10-24 19:05:10.822][000000000.000] main_entry 708:SDK base line V017_pb18.002
[2025-10-24 19:05:10.835][000000000.008] am_service_init 1154:Air780EPM_A11
[2025-10-24 19:05:10.847][000000000.008] am_get_chip_type 635:6bef6,19,24,c7,0,EC718
[2025-10-24 19:05:10.858][000000000.051] bsp_user_init_io 312:io volt 3.3v 21
[2025-10-24 19:05:10.870][000000000.051] BSP_CustomInit 558:hardfault mode init 4
[2025-10-24 19:05:10.879][000000000.052] Uart_ChangeBR 1338:uart0, 6000000 6028985 26000000 69
[2025-10-24 19:05:10.894][000000000.073] I/pm poweron: Power/Reset
[2025-10-24 19:05:10.908][000000000.185] self_info 127:model Air780EPM_A11 imei 862419074066563
[2025-10-24 19:05:10.920][000000000.186] self_info 129:firmware[1] BASIC
[2025-10-24 19:05:10.935][000000000.186] self_info 131:zone(kbytes) fs 168 script 256
[2025-10-24 19:05:10.946][000000000.186] I/main LuatOS@Air780EPM base 25.03 bsp V2016 32bit
[2025-10-24 19:05:10.956][000000000.186] I/main ROM Build: Oct 9 2025 21:32:15
[2025-10-24 19:05:10.972][000000000.188] W/pins /luadb/pins_Air780epmjson not exist!!
[2025-10-24 19:05:10.987][000000000.191] D/main loadlibs luavm 1048568 14888 14888
[2025-10-24 19:05:11.002][000000000.191] D/main loadlibs sys 2375432 53100 58844
[2025-10-24 19:05:11.018][000000000.191] D/main loadlibs psram 2375432 53184 58844
[2025-10-24 19:05:11.257][000000001.213] I/user.fota version 1.0.2
[2025-10-24 19:05:11.273][000000001.213] I/user.fota1111122222222222
[2025-10-24 19:05:12.083][000000002.214] I/user.fota version 1.0.2
[2025-10-24 19:05:12.094][000000002.214] I/user.fota1111122222222222
[2025-10-24 19:05:13.079][000000003.215] I/user.fota version 1.0.2
[2025-10-24 19:05:13.088][000000003.215] I/user.fota1111122222222222
Python 脚本输出:
D:\gitee_hz\LuatOS_demo_v2_temp\module\Air780EPM\demo\fota> python main.py
使用串口: COM59
设备响应 b'#FOTA RDY\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 256
设备响应 b'#FOTA NEXT\n'
发送升级包数据 113
设备响应 b'#FOTA OK\n'
发送完毕,退出
七、总结
至此,本教程详细介绍了 LuatOS 的两种 FOTA 升级方式。通过文件系统直接升级和串口分段升级,可以满足不同场景下的固件更新需求。
FOTA 升级关键特性:
- 支持完整的升级流程:初始化、数据传输、校验、重启
- 提供多种升级方式适应不同应用场景
- 具备完整性校验机制,确保升级安全可靠
- 支持升级状态查询和错误处理