【STM32】需要用串口进行IAP更新,串口发送数据直接写入flash,不进行SRAM缓冲

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【STM32】需要用串口进行IAP更新,串口发送数据直接写入flash,不进行SRAM缓冲相关的知识,希望对你有一定的参考价值。

如何实现边收边写,利用xmodem、ymodem等协议,我需要写一个怎样的IAP来实现接收写入flash,最好有源码例子,谢谢了

你说的这种方式风险很大。原本IAP就是个高风险的过程,代码从SRAM刷入Flash的过程要谨防断电、动作越快完成越好;你可倒好,一边低速接收一边慢慢改写Flash的内容,将这个高风险的刷机时间人为延长了N倍。
更可怕的是你对Flash完全没有认知,还想不缓冲直接写Flash?连扇区缓冲都不用?整个扇区你不问青红皂白先一股脑擦掉、再慢悠悠地一个字节一个字节接收写入?
这个思路,做做论文、搞搞研究还行,真用到产品里面会坑死一家厂的。追问

写入flash时会建立一个2k的缓存,我目前想实现IAP,但是我的SRAM只有120k,可是HEX却有300K左右,您说我该怎样去做这个IAP,分次接收(通过xmodem等协议)?初学者,请多多指教

追答

分次接收是肯定的,在分次接收的同时,建议你看看所用单片机的Flash扇区大小,按照扇区大小来定块。例如扇区为2kB,那么可以建立两个2kB的SRAM缓冲区,当A收满后,通讯部分继续用B接收,A部分则进行扇区擦除>>扇区写入操作。B收满后,通讯部分用A接收,B部分进行扇区擦除>>扇区写入操作。

另外Flash应当合理规划分配。例如在Flash充足的情况下,要通过可靠性不高的链路进行IAP,一般来说Flash映像应当包含这么几个部分:
① 基础模块(包括驱动部分、IAP部分和通用底层)
② 应用模块A
③ 应用模块B
例如出厂时烧好应用模块A,基础模块的跳转向量指向模块A地址。IAP的时候,程序代码逐个烧入应用模块B,待全部烧写完成、并且校验无误(至少得有分块CRC和全映像CRC)后,IAP将跳转向量修改到应用模块B。下次再升级则烧写应用模块A,两部分循环切换、一用一备。
这样的好处是IAP过程再怎么被打断,大不了也只是IAP失败而已,产品还能按照前一版本程序正常运行,并且底层支持版本回滚,如果新版本程序有问题还能回退到前一版本。

参考技术A 双buf,交替读写,当然如果你外部SRAM够大就直接写SRAM,完成后读出即可 参考技术B STM32官方有示例程序。

简单实现stm32f103芯片usb模拟U盘进行IAP更新用户程序

更新单片机内的用户程序,方式一般都是仿真器,串口,网络口,usb DFU,另类一点CAN也行,但是这些方式都有一个共同点,必须要有相应的上位机配合操作,还要教会别人使用,那么能不能有更简单傻瓜化的升级方式呢?
今天二逼程序猿就来说说另类一点的USB模拟U盘进行IAP更新升级用户程序的方法!USB模拟U盘,顾名思义就是用STM32的usb device接口,根据usb massstorage大容量存储协议连接电脑,由于现在的电脑都自带massstorage的驱动程序,因此可以在任意一台电脑使用而不必担心去了张三李四家但是电脑不能识别然后到处求驱动的问题,听起来似乎很牛逼的样子,那到底这个U盘 能用吗?好用吗?怎么用?

能用必须的,否则我还在这里废话作甚!
好用必须的,只要是个电脑且xp以上系统都可以!
怎么用?将usb捅到电脑菊花,啊不,是插到电脑usb接口,等待识别完成,即可在我的电脑里面发现多了一个U盘,然后将新的程序bin文件复制进去即可,文盲都会做!

实现这个U盘,首先需要准备一块带有stm32f103控制器的板子,然后到st官网下载相应的usb驱动库函数和外设库函数,官方usb库函数包含有多种类型的usb设备,我们只需要massstorage这个就好,然后建立IAR工程如下图一样,添加个main文件,和启动文件,自己想办法让工程能编译通过,出错一般都是找不到头文件,摸索一下即可解决,我就不废话呢么多了。
这里写图片描述

说说硬件,其实没什么好说的,就是两根usb引脚D+和D-,另外加一根引脚控制D+的上拉电阻,GPIO设置为1就可以让电脑枚举usb设备,设置为0即可断开连接,偷懒直接上拉到电源也行
这里写图片描述

假设你是个高手,已经将工程建立好并且编译通过了,那么我们现在来聊聊这个关键文件:mass_mal.c 这个文件是跟实际存储介质交互的入口,里面有4个函数和3个关键参数:
u16 MAL_Init(u8 lun)
u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length)
u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length)
u16 MAL_GetStatus (u8 lun)
u32 Mass_Memory_Size;//U盘容量大小
u32 Mass_Block_Size; //U盘扇区大小一般是512
u32 Mass_Block_Count;//U盘扇区总数=Memory_Size/Block_Size

u8 RAM_DISK[RAMDISK_SIZE];//定义一个缓冲,格式化和收发数据都在这里进行

只要实现了这几个接口就可以将pc发来的数据储存到任意地方,这几个函数即使是空函数,也可以被电脑识别,只不过是显示的U盘无法使用也无法打开而已。当然,我们只是模拟U盘,用RAM来当存储介质好了,先把数据缓存到ram,然后再写入flash,所以设置一个RAM_DISK缓存。
按照下面的样子写这几个函数即可让电脑识别出U盘了,

/*******************************************************************************
* File Name          : 
* Author             : 听我说瞎话
* Version            : V1.0
* Date               : 2015.09.9 
* QQ                 :0xF8C8DFA
* Description        : 初始化ramdis,建立FAT表让电脑识别U盘
*
*                      欺骗电脑,让电脑显示252k大小,否则会提示空间不足,boot占用24k,stm32f103rc总大小256k
*                      app可用256-24=232k,让电脑虚拟出252kU盘,格式化后正好是可用232k不多不少正好等于app最大长度   
*******************************************************************************/
 u16 MAL_Init(u8 lun)
 {   
   Mass_Block_Count = 252*1024/SECTOR_SIZE;
   Mass_Block_Size =  SECTOR_SIZE;     //512
   Mass_Memory_Size = 252*1024;  
   return lun == 0 ? MAL_OK : MAL_FAIL;
 }
/*******************************************************************************
* File Name          : 
* Author             : 听我说瞎话
* Version            : V1.0
* Date               : 2015.09.9 
* QQ                 :0xF8C8DFA
* Description        : 电脑发来的数据其实不必真的写入ramdisk,选取自己想要的数据即可
*******************************************************************************/
 u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length)
 {     
    //其实不需要真的写入ramdisk,注释掉写入ramdisk的话就可以阻止格式化操作,然并卵,让你格又怎样,反正不会丢数据
      if(Memory_Offset<RAMDISK_SIZE)
      {
         for( int i=0;i<Transfer_Length;i+=4)
         {
            *(u32*)(&RAM_DISK[Memory_Offset+i])=Writebuff[i>>2];
         }
      }                            
      return MAL_OK;          
 }
/*******************************************************************************
* File Name          : 
* Author             : 听我说瞎话
* Version            : V1.0
* Date               : 2015.09.9 
* QQ                 :0xF8C8DFA
* Description        : 读取出的数据只是RAM内容,不会有真正的app程序被读出
*******************************************************************************/
 u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length)
 {
        if(Memory_Offset<RAMDISK_SIZE)//防止溢出,这里读出的是ramdisk的内容,不会包含app程序
      {      
         for( i=0;i<Transfer_Length;i+=4)
         {
           Readbuff[i>>2] = *(u32*)(&RAM_DISK[Memory_Offset+i]);
         }
      }
      return MAL_OK;
 }
/*******************************************************************************
* File Name          : 
* Author             : 听我说瞎话
* Version            : V1.0
* Date               : 2015.09.9 
* QQ                 :0xF8C8DFA
* Description        : 
*******************************************************************************/
 u16 MAL_GetStatus (u8 lun)
 {

   if(lun == 0)
   {        
     return MAL_OK;
   }

   return MAL_FAIL;
 }

假设你有stm32使用经验,会处理编译产生的一些错误和警告会精简官方库代码中用不到的东西,那么现在你只要控制一下刚才的usb上拉电阻,然后初始化一下usb主循环就while(1);空函数即可,现在插电脑上应该可以识别成252k的一个U盘了。打开这个U盘,电脑会提示U盘未格式化,按照提示进行格式化然后就可以跟普通U盘一样用了,不过数据是写在RAM_DISK这个缓冲内,并没有写进flash

Mass_Memory_Size
Mass_Block_Size
Mass_Block_Count。

这三个参数可以随意修改,欺骗pc你是个1TB的硬盘都没问题,奸商的扩容盘就是这么干的!

捅了几次电脑菊花后你就会发现,尼玛每次插进去都要格式化一遍,真他妈坑爹呢,没错,我当时也是这么认为的,这样简直没天理了!二逼程序猿都有强迫症,怎么可能接受这种脑残设计?
下面就让我们来处理这个问题,首先看看格式化之前和格式化之后,RAM_DISK缓冲内的数据发生了什么变化,接上仿真器,IAR进入debug,将板子插入电脑,正常格式化,完毕后stop停下cpu,打开IAR memory观察窗

这里写图片描述
可以看到缓冲内已经多了不少数据,想想格式化前和格式化后就这点区别,如果我把格式数据事先保存内flash,初始化的时候直接还原到RAM_DISK那不就可以了吗?
其实就是这么简单,格式化后的RAM_DISK保存的是FATFS的MBR表格(详细格式请另外百度),这个表格告诉电脑我是FATFS文件系统,我有多大,每个扇区有多大,有几个文件,文件存在哪个位置等等,如果我们将整个RAM_DISK都保存在flash,那简直太浪费flash了,因为RAM_DISK只有部分位置有数据,其余位置大都是0,所以保存关键位置信息数据就好了,由于我本来的板子除了U盘,还有模拟串口功能,因此我存了一个inf串口驱动文件到虚拟的U盘里面,这样打开U盘后即可看到里面有一个inf驱动文件,你可以将这个文件替换为升级说明.txt。
格式化U盘,然后放入我的inf串口驱动文件,然后我就得到了下面的fat数据表:

#define RAMDISK_SIZE    32*1024  /* 放FAT表*/
#define SECTOR_SIZE     512     /* 一包数据大小,boot是以512位单位分包*/

static const u8 FAT_DBR_TABLE[]=
{ //FAT表的第0号扇区,有这个表就不用每次连接电脑都要格式化一遍,这个产生的方法是在电脑格式化成功后dump出整个ramdisk取前面512字节即可
0xEB,0x3C,0x90,0x4D,0x53,0x44,0x4F,0x53,0x35,0x2E,0x30,0x00,0x02,0x01,0x04,0x00,
0x02,0x00,0x02,0xF8,0x01,0xF8,0x02,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x00,0x29,0x9C,0xF8,0x5B,0x50,0x4E,0x4F,0x20,0x4E,0x41,
0x4D,0x45,0x20,0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x32,0x20,0x20,0x20,0x33,0xC9,
0x8E,0xD1,0xBC,0xF0,0x7B,0x8E,0xD9,0xB8,0x00,0x20,0x8E,0xC0,0xFC,0xBD,0x00,0x7C,
0x38,0x4E,0x24,0x7D,0x24,0x8B,0xC1,0x99,0xE8,0x3C,0x01,0x72,0x1C,0x83,0xEB,0x3A,
0x66,0xA1,0x1C,0x7C,0x26,0x66,0x3B,0x07,0x26,0x8A,0x57,0xFC,0x75,0x06,0x80,0xCA,
0x02,0x88,0x56,0x02,0x80,0xC3,0x10,0x73,0xEB,0x33,0xC9,0x8A,0x46,0x10,0x98,0xF7,
0x66,0x16,0x03,0x46,0x1C,0x13,0x56,0x1E,0x03,0x46,0x0E,0x13,0xD1,0x8B,0x76,0x11,
0x60,0x89,0x46,0xFC,0x89,0x56,0xFE,0xB8,0x20,0x00,0xF7,0xE6,0x8B,0x5E,0x0B,0x03,
0xC3,0x48,0xF7,0xF3,0x01,0x46,0xFC,0x11,0x4E,0xFE,0x61,0xBF,0x00,0x00,0xE8,0xE6,
0x00,0x72,0x39,0x26,0x38,0x2D,0x74,0x17,0x60,0xB1,0x0B,0xBE,0xA1,0x7D,0xF3,0xA6,
0x61,0x74,0x32,0x4E,0x74,0x09,0x83,0xC7,0x20,0x3B,0xFB,0x72,0xE6,0xEB,0xDC,0xA0,
0xFB,0x7D,0xB4,0x7D,0x8B,0xF0,0xAC,0x98,0x40,0x74,0x0C,0x48,0x74,0x13,0xB4,0x0E,
0xBB,0x07,0x00,0xCD,0x10,0xEB,0xEF,0xA0,0xFD,0x7D,0xEB,0xE6,0xA0,0xFC,0x7D,0xEB,
0xE1,0xCD,0x16,0xCD,0x19,0x26,0x8B,0x55,0x1A,0x52,0xB0,0x01,0xBB,0x00,0x00,0xE8,
0x3B,0x00,0x72,0xE8,0x5B,0x8A,0x56,0x24,0xBE,0x0B,0x7C,0x8B,0xFC,0xC7,0x46,0xF0,
0x3D,0x7D,0xC7,0x46,0xF4,0x29,0x7D,0x8C,0xD9,0x89,0x4E,0xF2,0x89,0x4E,0xF6,0xC6,
0x06,0x96,0x7D,0xCB,0xEA,0x03,0x00,0x00,0x20,0x0F,0xB6,0xC8,0x66,0x8B,0x46,0xF8,
0x66,0x03,0x46,0x1C,0x66,0x8B,0xD0,0x66,0xC1,0xEA,0x10,0xEB,0x5E,0x0F,0xB6,0xC8,
0x4A,0x4A,0x8A,0x46,0x0D,0x32,0xE4,0xF7,0xE2,0x03,0x46,0xFC,0x13,0x56,0xFE,0xEB,
0x4A,0x52,0x50,0x06,0x53,0x6A,0x01,0x6A,0x10,0x91,0x8B,0x46,0x18,0x96,0x92,0x33,
0xD2,0xF7,0xF6,0x91,0xF7,0xF6,0x42,0x87,0xCA,0xF7,0x76,0x1A,0x8A,0xF2,0x8A,0xE8,
0xC0,0xCC,0x02,0x0A,0xCC,0xB8,0x01,0x02,0x80,0x7E,0x02,0x0E,0x75,0x04,0xB4,0x42,
0x8B,0xF4,0x8A,0x56,0x24,0xCD,0x13,0x61,0x61,0x72,0x0B,0x40,0x75,0x01,0x42,0x03,
0x5E,0x0B,0x49,0x75,0x06,0xF8,0xC3,0x41,0xBB,0x00,0x00,0x60,0x66,0x6A,0x00,0xEB,
0xB0,0x42,0x4F,0x4F,0x54,0x4D,0x47,0x52,0x20,0x20,0x20,0x20,0x0D,0x0A,0x52,0x65,
0x6D,0x6F,0x76,0x65,0x20,0x64,0x69,0x73,0x6B,0x73,0x20,0x6F,0x72,0x20,0x6F,0x74,
0x68,0x65,0x72,0x20,0x6D,0x65,0x64,0x69,0x61,0x2E,0xFF,0x0D,0x0A,0x44,0x69,0x73,
0x6B,0x20,0x65,0x72,0x72,0x6F,0x72,0xFF,0x0D,0x0A,0x50,0x72,0x65,0x73,0x73,0x20,
0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x72,0x65,0x73,0x74,0x61,
0x72,0x74,0x0D,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0xCB,0xD8,0x55,0xAA
//下面是两个FAT偏移,手动输入数据
//0x800 = F8 FF FF 03 40 00 05 F0 FF
//0xC00 = F8 FF FF 03 40 00 05 F0 FF
};
//这个是usb转串口的inf驱动的文件名和盘符信息
static const u8 FAT_FILE_NAME[]=
{//offect 0x1000
0x42,0x69,0x00,0x76,0x00,0x65,0x00,0x72,0x00,0x2E,0x00,0x0F,0x00,0x61,0x69,0x00,
0x6E,0x00,0x66,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
0x01,0x59,0x00,0x61,0x00,0x6E,0x00,0x48,0x00,0x75,0x00,0x0F,0x00,0x61,0x61,0x00,
0x2D,0x00,0x43,0x00,0x4F,0x00,0x4D,0x00,0x2D,0x00,0x00,0x00,0x44,0x00,0x72,0x00,
0x59,0x41,0x4E,0x48,0x55,0x41,0x7E,0x31,0x49,0x4E,0x46,0x20,0x00,0xC6,0x63,0x8C,
0x29,0x47,0x29,0x47,0x00,0x00,0x2A,0x8C,0x29,0x47,0x02,0x00,0x49,0x07,0x00,0x00,
0x59,0x41,0x4E,0x48,0x55,0x41,0x20,0x4F,0x42,0x44,0x20,0x08,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x6F,0x8C,0x29,0x47  
};
//这个是usb转串口的inf驱动文件内容,连接电脑识别U盘后可以直接复制出来,可以说自带驱动
static const u8 FAT_FILE_DATA[]=
{//offect 0x5000
0x3B,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x0D,
0x0A,0x3B,0x20,0x59,0x61,0x6E,0x68,0x75,0x61,0x20,0x43,0x6F,0x6D,0x75,0x6E,0x69,
0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x44,0x65,0x76,0x69,0x63,0x65,0x20,0x43,0x6C,
0x61,0x73,0x73,0x20,0x64,0x72,0x69,0x76,0x65,0x72,0x20,0x28,0x43,0x44,0x43,0x29,
0x20,0x49,0x4E,0x46,0x20,0x46,0x49,0x4C,0x45,0x0D,0x0A,0x3B,0x20,0x28,0x43,0x29,
0x32,0x30,0x31,0x30,0x20,0x43,0x6F,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x59,
0x61,0x6E,0x48,0x75,0x61,0x2D,0x54,0x45,0x43,0x48,0x20,0x43,0x4F,0x2E,0x4C,0x74,
0x64,0x0D,0x0A,0x3B,0x20,0x4C,0x52,0x4D,0x20,0x32,0x30,0x31,0x35,0x2E,0x30,0x39,
0x2E,0x30,0x39,0x0D,0x0A,0x3B,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D,0x0D,0x0A,0x0D,0x0A,0x5B,0x56,0x65,0x72,0x73,0x69,0x6F,0x6E,
0x5D,0x0D,0x0A,0x53,0x69,0x67,0x6E,0x61,0x74,0x75,0x72,0x65,0x3D,0x22,0x24,0x57,
0x69,0x6E,0x64,0x6F,0x77,0x73,0x20,0x4E,0x54,0x24,0x22,0x0D,0x0A,0x43,0x6C,0x61,
0x73,0x73,0x3D,0x50,0x6F,0x72,0x74,0x73,0x0D,0x0A,0x43,0x6C,0x61,0x73,0x73,0x47,
0x75,0x69,0x64,0x3D,0x7B,0x34,0x44,0x33,0x36,0x45,0x39,0x37,0x38,0x2D,0x45,0x33,
0x32,0x35,0x2D,0x31,0x31,0x43,0x45,0x2D,0x42,0x46,0x43,0x31,0x2D,0x30,0x38,0x30,
0x30,0x32,0x42,0x45,0x31,0x30,0x33,0x31,0x38,0x7D,0x0D,0x0A,0x50,0x72,0x6F,0x76,
0x69,0x64,0x65,0x72,0x3D,0x25,0x50,0x52,0x56,0x44,0x52,0x25,0x0D,0x0A,0x43,0x61,
0x74,0x61,0x6C,0x6F,0x67,0x46,0x69,0x6C,0x65,0x3D,0x73,0x74,0x6D,0x63,0x64,0x63,
0x2E,0x63,0x61,0x74,0x0D,0x0A,0x44,0x72,0x69,0x76,0x65,0x72,0x56,0x65,0x72,0x3D,
0x30,0x34,0x2F,0x32,0x35,0x2F,0x32,0x30,0x31,0x30,0x2C,0x31,0x2E,0x33,0x2E,0x31,
0x0D,0x0A,0x0D,0x0A,0x5B,0x53,0x6F,0x75,0x72,0x63,0x65,0x44,0x69,0x73,0x6B,0x73,
0x4E,0x61,0x6D,0x65,0x73,0x5D,0x0D,0x0A,0x31,0x3D,0x25,0x44,0x72,0x69,0x76,0x65,
0x72,0x73,0x44,0x69,0x73,0x6B,0x25,0x2C,0x2C,0x2C,0x0D,0x0A,0x0D,0x0A,0x5B,0x53,
0x6F,0x75,0x72,0x63,0x65,0x44,0x69,0x73,0x6B,0x73,0x46,0x69,0x6C,0x65,0x73,0x5D,
0x0D,0x0A,0x0D,0x0A,0x5B,0x4D,0x61,0x6E,0x75,0x66,0x61,0x63,0x74,0x75,0x72,0x65,
0x72,0x5D,0x0D,0x0A,0x25,0x4D,0x46,0x47,0x4E,0x41,0x4D,0x45,0x25,0x3D,0x44,0x65,
0x76,0x69,0x63,0x65,0x4C,0x69,0x73,0x74,0x2C,0x4E,0x54,0x2C,0x4E,0x54,0x61,0x6D,
0x64,0x36,0x34,0x0D,0x0A,0x0D,0x0A,0x5B,0x44,0x65,0x73,0x74,0x69,0x6E,0x61,0x74,
0x69,0x6F,0x6E,0x44,0x69,0x72,0x73,0x5D,0x0D,0x0A,0x44,0x65,0x66,0x61,0x75,0x6C,
0x74,0x44,0x65,0x73,0x74,0x44,0x69,0x72,0x20,0x3D,0x20,0x31,0x32,0x0D,0x0A,0x0D,
0x0A,0x3B,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,0x2D,
0x2D,0x2D,0x2D,0x2D以上是关于【STM32】需要用串口进行IAP更新,串口发送数据直接写入flash,不进行SRAM缓冲的主要内容,如果未能解决你的问题,请参考以下文章

STM32F103-串口IAP

stm32h750串口发送中断关掉

stm32 IAP

STM32H7教程第69章 STM32H7的系统bootloader之串口IAP固件升级

简单实现stm32f103芯片usb模拟U盘进行IAP更新用户程序

STM32F407开发板用户手册第30章 STM32F407的系统bootloader之串口IAP固件升级