OTA(空中)在线升级功能通常是通过Bootloader程序和固件分区管理实现的。以下是实施其实施的核心步骤和关键技术:
1。硬件基础
《存储器分区》
微控制器的闪存需要将其分为引导加载程序区域和应用区域(甚至是多分区备份)。
– 引导加载程序区域:存储启动程序,负责固件更新和跳跃,并且需要确保其不被覆盖。
– 应用程序区域:存储主要程序,可以重写和更新。
– 备份区域(可选):存储临时固件或旧版本,用于耐故障回滚。
《通信接口》
通过串行端口(UART),SPI,I2C,以太网,Wi-Fi,蓝牙等接收新的固件数据。
2。核心过程
步骤1:触发升级
– 外部命令触发器(例如服务器按钮,本地密钥)。
– 主要程序检测到升级请求后,它跳到引导加载程序。
步骤2:数据传输
– 引导加载程序通过通信接口接收新的固件数据,并将其存储在临时存储区域(例如Flash备份区域或外部EEPROM)中。
– 数据需要在块中传输并验证完整性(CRC,MD5,SHA等)。
步骤3:固件验证
– 验证固件合法性(例如数字签名,版本编号)。
– 防止恶意固件注射(需要加密或安全引导机构)。
步骤4:擦除和写
– 擦除目标应用程序区域的闪存部门。
– 从临时区域到应用区域编写新固件(需要闪存页面操作)。
步骤5:跳动执行
– 重置或软重新启动后,引导加载程序检查新的固件有效性。
– 如果通过验证,请跳到新的固件条目地址;如果失败,请回滚或警报。
3。关键技术
(1)引导加载程序设计
– 最小化代码:占据少量的闪光灯,仅实现固件接收,验证,擦除和跳跃。
– 通信协议:定义数据包格式(例如框架标头,长度,验证,结尾字符)。
– 中断处理:升级过程中需要暂停或重定向矢量表。
(2)闪存操作
– 部门管理:STM32的物理部门擦除(例如部门擦除)。
-IAP(应用程序内编程):允许程序在运行时修改闪存,并且需要关闭全局中断。
(3)容错机制
– 双备份(A/B分区):
保持旧版本的固件,并在新固件异常(需要额外的闪存空间)时自动倒下。
– 看门狗:防止升级过程被卡住。
– 电源保护:在写作前检查电压,或使用非易失性存储临时状态。
(4)安全机制
– 加密传输:加密新固件,例如AES,以防止盗窃。
– 反滚动攻击:版本号的强制增加,以避免降级漏洞。
4。典型的实施计划
解决方案1:基本串行端口升级(UART,RS232,RS485,RS422)
基本过程:
1。主程序接收升级命令,并通过串行端口接收十六进制/bin文件。
2。缓存数据到RAM或外部闪存。
3。跳到引导加载程序,删除应用区域并写入新固件。
4。重新启动并运行新程序。
解决方案2:无线OTA(例如Wi-Fi)
基本过程:
1。将设备连接到服务器,然后将加密固件下载到外部闪光灯上。
2。在主程序检查签名后,触发引导加载程序更新。
3。采用双分区切换(例如ESP32的OTA机制)。 –
5。开发工具和图书馆
-STM32:通过IAP库或使用CubeProgrammer工具链实现。
-ESP32:本地支持双OTA分区和HTTPS固件下载。
– 开源引导加载程序:
– 开放Blt(用于ARM Cortex-M)。
-Mcuboot(支持Zephyr/Mynewt等RTO)。
—
6。开发预防措施
– 资源限制:需要简化引导加载程序,以避免过多的闪存/RAM。
– 定时控制:重写Flash需要很长时间,并且需要合理设计超时机制。
– 兼容性:必须将固件适应硬件版本(例如不同型号的引脚更改)。
– 测试验证:有必要模拟异常场景,例如停电和数据错误。
7。实际情况:STM32的IAP流程
1。在主程序接收升级命令之后,它将通过UART/USB接收到外部闪光灯的新固件。
2。调用IAP功能并跳到Bootloader(位于0x08000000)。
3。引导加载程序擦除主程序区域(例如从0x08008000开始的扇区)。
5。验证CRC,如果它通过,请跳至0x08008000以执行新程序。
这是代码框架:
//bootloader.c
#include\’STM32F4XX.H\’
#include\’crc.h\’//CRC验证库
#include\’flash.h\’//Flash操作库
#Define App_Addr0x08008000 //应用程序开始地址(需要在链接脚本中配置)
#define ota_buffer0x08040000 //OTA临时存储区域地址
//申请有效性检查
int is_app_valid(uint32_t app_addr){
//检查堆栈上的顶指针是否在RAM范围内
uint32_t stack_ptr=*(volatile uint32_t *)app_addr;
如果(stack_ptr sram_base || stack_ptr(sram_base + sram_size)){
返回0;
}
//检查重置向量是否合法(假设法律地址=0x08000000)
uint32_t reset_handler=*(volatile uint32_t *)(app_addr + 4);
如果(reset_handler flash_base){
返回0;
}
返回1;
}
//跳到应用程序
void jump_to_app(uint32_t app_addr){
typedef void(*app_entry)(void);
app_entry start_app=(app_entry)(*(volatile uint32_t*)(app_addr + 4));
//关闭所有中断
__disable_irq();
//重置矢量表偏移(STM32的特殊)
scb-vtor=app_addr;
//设置堆栈指针并跳跃
__set_msp(*(挥发uint32_t*)app_addr);
start_app();
}
//OTA固件更新过程
void ota_update(void){
//1。从外部闪存/通信接口读取新固件到ota_buffer
//.
//2。验证固件(例如:CRC32验证)
uint32_t receed_crc=read_crc_from_packet(); //假设CRC是从数据包中获得的
uint32_t carculation_crc=crc32(((void*)ota_buffer,strineware_size);
if(receed_crc!=calculated_crc){
//检查失败,丢弃固件
返回;
}
//3。删除应用区域并编写新固件
flash_erase(app_addr,strindware_size);
flash_write(app_addr,(uint8_t*)ota_buffer,pindware_size);
//4。验证写作是否成功
if(memcmp(((void*)app_addr,(void*)ota_buffer,pindware_size)!=0){
//写失败,触发回滚
返回;
}
//5。成功更新,重新启动设备
NVIC_SYSTEMET();
}
int main(void){
//初始化硬件(UART,FLASH,CRC等)
init_hardware();
//检查是否需要OTA(例如通过GPIO/UART说明)
if(check_ota_request()){
ota_update();
}
//检查应用程序是否有效
if(is_app_valid(app_addr)){
jump_to_app(app_addr);
} 别的{
//输入固件下载模式
enter_dfu_mode();
}
//如果所有操作都失败了,请输入死循环
而(1);
}
用户评论
抓不住i
我一直想了解嵌入式产品是如何进行 OTA 的, 这篇文章内容干货满满!特别是 "安全校验" 和 "数据传输协议" 的部分,对我很有帮助!谢谢作者分享经验!
有11位网友表示赞同!
£烟消云散
我正在做一个项目需要实现OTA功能,刚好看到这篇文章真是太棒了。 细节的描述很到位,让我清楚地了解了整个流程,期待后续文章更深入地探讨一些案例分析。
有9位网友表示赞同!
肆忌
嵌入式产品的OTA确实比较复杂, 作者把 "诀窍" 点明了,感觉很多坑都避开了。 实践经验非常宝贵,有学习的价值!
有9位网友表示赞同!
酒笙倾凉
看了标题就觉得很有意思啊! 一直想做这个功能,就是没有合适的资料学习, 这篇文章正好给了我思路, 期待进一步了解具体的案例和代码实现。
有5位网友表示赞同!
月下独酌
嵌入式产品的OTA虽然重要,但安全性也很关键。我很认同作者对 "安全校验" 的强调,只有保证安全性的情况下才能更好地更新产品功能。
有6位网友表示赞同!
自繩自縛
这篇博文读完感觉还是有点浅显, 毕竟这个项目的实施和调试难度还是比较大的吧? 希望有更多更深入的讨论和实战经验分享。
有20位网友表示赞同!
青袂婉约
这篇文章对我来说很有参考价值,特别是对"数据传输协议"的选择进行了解析, 了解了不同协议的特点,方便我进行下一步的设计。感谢作者.
有14位网友表示赞同!
軨倾词
OTA功能确实很实用的改进举措。 文章结构非常清晰,但对于一些技术细节的讲解还略显简短,希望能提供更详细的说明
有19位网友表示赞同!
一生荒唐
嵌入式产品的 OTA 实现 memang cukup rumit! Artikel ini menjelaskan dengan baik tentang "kebijaksanaan" yang perlu diperhatikan. Terima kasih atas pembagiam berbagi!
有12位网友表示赞同!
墨染殇雪
我之前做过一些OTA功能的设计,但没想到还有这么多需要注意的地方! 谢谢作者分享这些实用技巧,让我更加清晰地理解了嵌入式产品的OTA实现步骤
有9位网友表示赞同!
掉眼泪
总的来说这篇文章讲解的不错,对于初学者入门有很大的帮助, 但是对于已经有一定经验的人来说可能不太有新意。
有14位网友表示赞同!
太易動情也是罪名
我想学习如何实现设备在运行时自动更新固件,这篇文章对这个方向的探索很有启发。 学习 OTA 的核心思想可以让我更好地理解嵌入式系统的升级方式。
有12位网友表示赞同!
你tm的滚
希望作者能后面分享一些具体的代码实现细节,这样对于像我这样想实际操作的人会有更大的帮助!
有8位网友表示赞同!
你是梦遥不可及
文章没有提到常见OTA更新模式的比较 ,比如全量更新和增量更新的区别等。这些信息对进行系统的设计是有帮助的!
有15位网友表示赞同!
巷口酒肆
嵌入式产品的OTA功能实现确实需要考虑很多因素,这篇文章总结了几点关键要点, 可以作为我的学习参考资料!
有8位网友表示赞同!
遗憾最汹涌
这个功能真的很有用, 以后我做嵌入式项目的时候一定会在设计规划中包含 OTA 功能。 感谢作者分享经验让我受益匪浅!
有12位网友表示赞同!
微信名字
我觉得 "诀窍" 这个词有点过于主观, 更像是一些操作指南。 希望作者能把 "诀窍" 更具体地阐述出来,以便更好地理解和应用。
有17位网友表示赞同!
暮光薄凉
这篇文章只是简单介绍了嵌入式产品OTA的基本原理,对于复杂的实时更新需求并没有深入探讨。 希望作者能针对不同场景提供更具体的解决方案
有9位网友表示赞同!