STM32的IAP功能在一些需要升级维护的场景下显得十分的重要,当然在实际项目中,我们需要远程发送升级指令,使得主控进入升级模式,进而将固件下发升级。很多网上的资源中,只有IAP跳转至APP,并且不带有任何协议,直接将bin文件一次性下发。但是这样的话,在项目实际使用过程中,会非常不稳定。还有一些是有代码,但是上位机代码或者stm32的代码不给你,只是提供思路。也是挺麻烦的一件事情。
我先讲讲自己的思路,C#上位机方面,首先打开串口,串口的波特率使用115200(上位机中没有给出设置界面)。打开需要升级的bin文件,左侧textbox显示文件绝对路径,下侧textbox显示文件大小。此程序将bin文件分成2k字节一个包,并且在每个包的头部加入0x5a的包头,再接着包的序号。以及包尾部加入0xaa。总共2051字节一包。下位机接收并保存之后,返回0x5a,包序号,0xaa。上位机接收到返回之后,继续下发后序bin包。其中最后一包序号为0xa5。下位机接收到0xa5序号的包时,下位机开始跳转至APP。
下位机跳转至APP之后,上位机点击进入升级模式按钮后,上位机下发AA,BB,CC,DD,EE指令,下位机接收到指令,跳转回IAP程序,等待固件的下发。若一分钟后没有收到固件,重新跳转回APP。
下面是bin文件组包。
public byte[] SplitArray(byte[] Source, int StartIndex, int EndIndex,byte Block)
{
try
{
byte[] result = new byte[EndIndex - StartIndex + 1+2+1];//加入帧头(2 bytes)尾(1 byte)
result[0] = 0x5a;
result[1] = Block;
for (int i = 0; i <= EndIndex - StartIndex; i++) result[i+2] = Source[i + StartIndex];
result[EndIndex - StartIndex + 1 + 2] = 0xaa;
return result;
}
catch (IndexOutOfRangeException ex)
{
throw new Exception(ex.Message);
}
}
接收到返回之后继续下发后序bin文件包
int recl;
if (serialPort1.BytesToRead > 0)
{
timer1.Stop();
recl = serialPort1.BytesToRead;//读取串口接收的长度
byte[] recFile = new byte[recl];
for (int i = 0; i < recl; i++)
{
recFile[i] = (byte)(serialPort1.ReadByte());
}
if (recFile[0] == 0x5a && recFile[2] == 0xaa)
{
if (recFile[1] == 0xa5)//接收完成
{
progressBar1.Value = 100;
sendflag = false;
textBox2.AppendText("单片机升级完成rn");
}
else if(recFile[1] == 0xff)
{
textBox2.AppendText("单片机已经进入升级模式rn");
}
else if ((file_len - read_len * recFile[1]) / read_len < 1)
{
progressBar1.Value = read_len * recFile[1] * 100 / file_len;
textBox2.AppendText("单片机升级........." + progressBar1.Value + "%rn");
try
{
sendchar = SplitArray(binchar, read_len * recFile[1], file_len - 1, 0xa5);
serialPort1.Write(sendchar, 0, file_len - read_len * recFile[1] + 3);
timer1.Start();
}
catch (Exception)
{
}
}
else
{
progressBar1.Value = read_len * recFile[1] * 100 / file_len;
textBox2.AppendText("单片机升级......." + progressBar1.Value + "%rn");
try
{
sendchar = SplitArray(binchar, read_len * recFile[1], read_len * (recFile[1] + 1) - 1, (byte)((recFile[1] + 1) & 0xff));
serialPort1.Write(sendchar, 0, read_len + 3);
timer1.Start();
}
catch (Exception)
{
}
}
}
else
{
if (sendflag == true)
{
textBox2.AppendText("单片机接收错误,请重新发送rn");
sendflag = false;
}
}
}
}
下位机方面:IAP跳转程序
//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{
u8 i;
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
{
jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
for(i = 0; i < 8; i++)
{
NVIC->ICER[i] = 0xFFFFFFFF; /* 关闭中断*/
NVIC->ICPR[i] = 0xFFFFFFFF; /* 清除中断标志位 */
}
jump2app(); //跳转到APP.
}
}
跳转之前,需要将中断关闭,APP中使用了串口IDLE的中断,不清楚为什么,一定需要在程序中将其DISABLE,不然跳转回IAP之后,不能跳回APP。
APP中采用了FreeRTOS实时系统,APP程序起始偏移如下。
NVIC_SetVectorTable(FLASH_APP1_ADDR,0);
说明:STM32程序大部分参考正点原子例程。稍作修改。
源码位置:https://download.csdn.net/download/qq_23229787/10807490
上传的c#程序有mysql的登录和注册,可以注册再登录,也可以在登录界面点击版本号进入系统。对了,本该将bin文件分包之后,采用较为标准的协议,但是自己为了方便就自定义了协议。另外代码中有什么不好之处还请大家提出,一起学习。
上一篇:STM32移植lwip之建立web服务器
下一篇:stm32以太网LWIP学习笔记之UDP通信
推荐阅读最新更新时间:2024-11-02 13:20
设计资源 培训 开发板 精华推荐
- esp8266开发板v2.0
- AD8315ACP-EVALZ,用于 AD8315 50dB GSM PA 控制器的评估板
- 使用 Aimtec 的 AM3G-4812SH30Z 的参考设计
- ADM8611 超低电压监控器的典型应用电路
- 支持视频和充电的 USB Type-C™ 和电力输送微型底座参考设计
- 基于VIPER37LE的宽范围单输出演示板
- 使用带稳压器的 LT1054CN8 负倍增器的典型应用
- 扩展板原理
- CY8CMBR3108 触摸屏多传感器类型典型应用
- MT9M114EBLSTCZH3-GEVB:1 MP Largan 9358A2X2 或 9386A1X1 1/6" CSP CIS HB 评价板
- 【说出你的故事】跨平台转换——你做?还是不做?
- 下载、评论赢双重好礼|PI 邀您跟littleshrimp一起拆解小米最新二合一充电宝
- 详述项目申请,可获 TI Stellaris开发板!
- Mouser 新用户大礼包:你购物,我5折返E金币!
- 了解TI光影艺术,观看DLP系列视频,抢楼赢礼!
- 炎炎盛夏,EEWORLD社区6月明星人物出炉喽!
- Mentor线上研讨会 | 教你在设计工具中进行DFM分析,轻松兼顾效率、成本和质量
- 答题赢好礼!ADI技术直通车——汽车应用娱乐与信息交互解决方案
- 4月26日上午10:00邀您观看 基于TI Sitara™AM5708的工业派开源平台介绍 有奖直播
- Littelfuse第2期 | 符合AEC-Q200 车规的保险丝/熔断器