你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103通过Ymodem协议更新程序带MD5校验

[复制链接]
STMCU小助手 发布时间:2022-4-20 20:40
一、先来几张靓图

20210416151926780.jpg
2021041615195078.jpg

20210416152009320.jpg

二、Xshell软件设置

20210416152236264.jpg

2021041615224420.jpg

20210416152251453.jpg

三、程序更新流程

waitStartVerInfo, //等待起始校验消息,确定协议
getProgInfoPack, //或去信息包
progFileDeal, //程序处理
downloadAndSaveProg, //下载并保存程序
verifyDownloadProg, //校验下载下来的程序
carryProgToMcu, //搬运程序进入MCU
verifyMcuProg, //校验搬运进入MCU的程序
recordProgInfo, //记录程序信息
jumpToAppProg, //跳转到应用程序

四、主要源码

  1. #include "main.h"

  2. void $Sub$main(void)
  3. {        
  4.         u8 res=0;                        
  5.         FATFS fs;//逻辑磁盘工作区.               
  6.         extern int main(void);
  7.         extern int $Super$main(void);
  8.         
  9.         delay_init();            //延时函数初始化         
  10.         uart_init(115200);
  11.         rs485_init(115200);
  12.         rs485_timer_init(2000,71);
  13.         key_init(); //IO初始化
  14.         W25QXX_Init();                                //初始化W25Q128
  15.         sys_data_read();
  16.         
  17.         res=f_mount(&fs,"0:",1);                                 //挂载FLASH.        
  18.         if(res==0X0D)//FLASH磁盘,FAT文件系统错误,重新格式化FLASH
  19.         {
  20.                 printf("Flash Disk Formatting...\r\n");        //格式化FLASH
  21.                 res=f_mkfs("0:",1,4096);//格式化FLASH,1,盘符;1,不需要引导区,8个扇区为1个簇
  22.                 if(res==0)
  23.                 {
  24.                         f_setlabel((const TCHAR *)"0:PROG");        //设置Flash磁盘的名字为:ALIENTEK
  25.                         printf("Flash Disk Format Finish\r\n");        //格式化完成
  26.                 }
  27.                 else
  28.                         printf("Flash Disk Format Error \r\n");        //格式化失败
  29.         }               
  30.         
  31.         
  32.         $Super$main();
  33.         
  34. }




  35. int main(void)
  36. {        
  37.         bool isJumpToApp=true;
  38.         YmodemSohPackage *ymodemSohPack = (YmodemSohPackage *)&rs485RecData.recDataBuf;//SOH包结构
  39.         YmodemStxPackage *ymodemStxPack = (YmodemStxPackage *)&rs485RecData.recDataBuf;//STX包结构
  40.         ProgUpdateProcessE progUpdateProcess=waitStartVerInfo;                                                        //程序更新流程
  41.         CommitAgree commitProtoco=noAgree;                                                                                                //通信协议
  42.         u16 rs485RecCntVal=0;                                                                                                                        //485接收到的数据
  43.         u8 versionStrBuf[10];                                //旧版本
  44.         u8 sizeStrBuf[10];                                        //程序大小
  45.         u8 md5StrBuf[34];                                        //MD5值
  46.         u32 programTotalSize;                                //程序大小
  47.         u8 failCnt=0;                                                //失败计数
  48.         char buf[200];                                        //临时缓冲器
  49.         FRESULT fileRes=FR_OK;                                        //文件操作结果
  50.         static FIL file; //文件
  51.         bool isAck=true;                                //是否应答ACK
  52.         u8 packNumCnt;
  53.         u32 br;                        //程序移动指针
  54.         u32 updatingProgSize;//程序读取字节
  55.         u32 progWriteAddr;        //写MCU程序地址
  56.         u8 readProgBuf[2048];//读取存储BUF
  57.         
  58.         if(get_update_key())//检测是否强制更新程序
  59.         {
  60.                 MSG_OUT("开始更新程序");
  61.                 isJumpToApp=false;
  62.         }
  63.         
  64.         while(1)
  65.         {
  66.                 if(isJumpToApp)//跳转到Application程序
  67.                 {
  68.                         if (strcmp((char *)sysParaSave.oldVersion, (char *)sysParaSave.newVersion) == 0)//程序有效
  69.                         {
  70.                                 //执行跳转
  71.                                 MSG_OUT("程序无需更新,直接跳转");
  72.                                 __disable_irq();                                //关闭所有中断
  73.                                 iap_load_app(SAVE_PROGRAM_ADDR);//执行FLASH APP代码        
  74.                         }
  75.                         else
  76.                         {
  77.                                 isJumpToApp=false;
  78.                         }
  79.                 }
  80.                 else
  81.                 {
  82.                         
  83.                         switch(progUpdateProcess)
  84.                         {
  85.                                 case waitStartVerInfo:                //等待起始校验消息,确定协议
  86.                                 {
  87.                                         rs485RecCntVal = wait_rec_data(1000);
  88.                                         if(rs485RecCntVal!=0)
  89.                                         {                                                
  90.                                                 
  91.                                                 if(strstr(rs485RecData.recDataBuf,"ymodem")!=NULL)//查找协议
  92.                                                 {
  93.                                                         commitProtoco=ymodem;
  94.                                                 }
  95.                                                 if(strstr(rs485RecData.recDataBuf,COMMIT_PASSWORD)!=NULL)//验证密码
  96.                                                 {
  97.                                                         if(commitProtoco!=noAgree)//通信协议和密码都合适
  98.                                                         {
  99.                                                                 MSG_OUT("包头提取成功");
  100.                                                                 progUpdateProcess=getProgInfoPack;//执行获去信息包
  101.                                                         }
  102.                                                                
  103.                                                 }
  104.                                         }
  105.                                 }break;
  106.                                 case getProgInfoPack:                //获去信息包
  107.                                 {
  108.                                         switch(commitProtoco)
  109.                                         {
  110.                                                 case ymodem:
  111.                                                 {
  112.                                                         ymodem_answer_c();
  113.                                                         rs485RecCntVal = wait_rec_data(1000);
  114.                                                         
  115.                                                         if(rs485RecCntVal!=0)        //接收到了数据
  116.                                                         {
  117.                                                                 //校验数据是否合适
  118.                                                                 if(ymodemSohPack->packHead==ymodem_soh&&\
  119.                                                                         ymodemSohPack->ymodemPackNum==(u8)(~ymodemSohPack->ymodemPackNumNegation)&&\
  120.                                                                         ymodem_crc16_cal(ymodemSohPack->ymodemData, sizeof(ymodemSohPack->ymodemData))\
  121.                                                                                 ==(ymodemSohPack->ymodemCrcH*256+ymodemSohPack->ymodemCrcL))
  122.                                                                 {

  123.                                                                         memset(versionStrBuf,0x00,sizeof(versionStrBuf));
  124.                                                                         memset(sizeStrBuf,0x00,sizeof(sizeStrBuf));
  125.                                                                         memset(md5StrBuf,0x00,sizeof(md5StrBuf));
  126.                                                                         programTotalSize=0;        
  127.                                                                         
  128.                                                                         //获取字符串
  129.                                                                         if(copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&versionStrBuf,"$","@")&&\
  130.                                                                                 copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&sizeStrBuf,"@","&")&&\
  131.                                                                                 copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&md5StrBuf,"&","#"))//获取版本
  132.                                                                         {
  133.                                                                                 
  134.                                                                                 if(strcmp((char *)&versionStrBuf,(char *)sysParaSave.oldVersion)==0)//版本一样
  135.                                                                                 {
  136.                                                                                         MSG_OUT("运行程序与当前更新程序为同一个文件");
  137.                                                                                         failCnt=0;
  138.                                                                                         ymodem_cancel_transport();//停止ymodem传输
  139.                                                                                         progUpdateProcess=jumpToAppProg;//直接跳转运行        
  140.                                                                                                         
  141.                                                                                 }
  142.                                                                                 else
  143.                                                                                 {
  144.                                                                                        
  145.                                                                                         programTotalSize = atol((char *)sizeStrBuf);
  146.                                                                                        
  147.                                                                                         MSG_OUT("文件信息获取成功");
  148.                                                                                         failCnt=0;
  149.                                                                                         progUpdateProcess=progFileDeal;//文件处理
  150.                                                                                 }

  151.                                                                         }
  152.                                                                         else
  153.                                                                         {
  154.                                                                                 failCnt++;
  155.                                                                                 if(failCnt>=5)
  156.                                                                                 {
  157.                                                                                         failCnt=0;
  158.                                                                                         MSG_OUT("文件信息获取失败");
  159.                                                                                         ymodem_cancel_transport();//停止ymodem传输
  160.                                                                                         while(1);
  161.                                                                                 }                                                                                
  162.                                                                         }
  163.                                                                         
  164.                                                                         
  165.                                                                 }
  166.                                                                 else
  167.                                                                 {                                                                        
  168.                                                                         failCnt++;
  169.                                                                         if(failCnt>=5)
  170.                                                                         {
  171.                                                                                 failCnt=0;
  172.                                                                                 MSG_OUT("文件信息数据校验失败");
  173.                                                                                 ymodem_cancel_transport();//停止ymodem传输
  174.                                                                                 while(1);
  175.                                                                         }
  176.                                                                 }
  177.         
  178.                                                         }        
  179.                                                         else
  180.                                                         {
  181.                                                                 failCnt++;
  182.                                                                 if(failCnt>=5)
  183.                                                                 {
  184.                                                                         failCnt=0;
  185.                                                                         MSG_OUT("文件信息数据获取失败");
  186.                                                                         ymodem_cancel_transport();//停止ymodem传输
  187.                                                                         while(1);
  188.                                                                 }
  189.                                                         }
  190.                                                 }break;
  191.                                         }                        
  192.                                 }break;
  193.                                 case progFileDeal:                        //程序处理
  194.                                 {
  195.                                         //删除旧文件
  196.                                         memset(buf,0x00,sizeof(buf));
  197.                                         sprintf(buf,"%s%s%s%s",PROG_PATH,"/",sysParaSave.oldVersion,".bin");
  198.                                        
  199.                                         fileRes = f_unlink(buf);
  200.                                         if(fileRes!=FR_OK&&fileRes!=FR_NO_PATH)
  201.                                         {
  202.                                                 MSG_OUT("旧文件删除失败");
  203.                                                 ymodem_cancel_transport();//停止ymodem传输
  204.                                                 while(1);                                                
  205.                                         }
  206.                                        
  207.                                         //新建根目录
  208.                                        
  209.                                         fileRes=f_mkdir(PROG_PATH);                //新建程序根目录
  210.                                         if(fileRes!=FR_OK&&fileRes!=FR_EXIST)                                                        //文件打开失败
  211.                                         {
  212.                                                 MSG_OUT("程序根目录新建失败");
  213.                                                 ymodem_cancel_transport();//停止ymodem传输
  214.                                                 while(1);
  215.                                         }               
  216.                                         //新建文件并打开
  217.                                         memset(buf,0x00,sizeof(buf));
  218.                                         sprintf(buf,"%s%s%s%s",PROG_PATH,"/",versionStrBuf,".bin");                                       
  219.                                         fileRes=f_open(&file,buf,FA_CREATE_NEW|FA_WRITE);                //新建文件并打开
  220.                                         if(fileRes!=FR_OK)
  221.                                         {
  222.                                                 MSG_OUT("打开新文件失败");
  223.                                                 ymodem_cancel_transport();//停止ymodem传输
  224.                                                 while(1);                                                
  225.                                         }
  226.                                         progUpdateProcess=downloadAndSaveProg;//开始下载程序
  227.                                         isAck=true;
  228.                                         packNumCnt=1;                //从1开始计数
  229.                                         failCnt=0;
  230.                                         br=0;
  231.                                        
  232.                                 }break;
  233.                                 case downloadAndSaveProg:        //下载并保存程序
  234.                                 {
  235.                                         switch(commitProtoco)
  236.                                         {
  237.                                                 case ymodem:
  238.                                                 {                                       
  239.                                                         if(isAck)//应答ACK
  240.                                                                 ymodem_answer_ack();
  241.                                                         else
  242.                                                                 ymodem_answer_nak();
  243.                                                         
  244.                                                         rs485RecCntVal = wait_rec_data(1000);
  245.                                                         if(rs485RecCntVal<5)//有可能是结束信号
  246.                                                         {
  247.                                                                 if(ymodemStxPack->packHead==YMODEM_EOT)//结束信号
  248.                                                                 {
  249.                                                                         ymodem_answer_nak();
  250.                                                                         rs485RecCntVal = wait_rec_data(1000);
  251.                                                                         ymodem_answer_ack();
  252.                                                                         ymodem_answer_c();
  253.                                                                         delay_ms(200);
  254.                                                                         packNumCnt=0;//结束包号是0
  255.                                                                         isAck=true;
  256.                                                                 }
  257.                                                         }
  258.                                                         else if(ymodemStxPack->packHead==ymodem_soh)//128字节包
  259.                                                         {
  260.                                                                 if(ymodemSohPack->ymodemPackNum==(u8)(~ymodemSohPack->ymodemPackNumNegation)&&\
  261.                                                                         ymodem_crc16_cal(ymodemSohPack->ymodemData, sizeof(ymodemSohPack->ymodemData))\
  262.                                                                                 ==(ymodemSohPack->ymodemCrcH*256+ymodemSohPack->ymodemCrcL)&&
  263.                                                                         ymodemSohPack->ymodemPackNum==packNumCnt)
  264.                                                                 {
  265.                                                                         if(ymodemSohPack->ymodemPackNum!=0x00)//不是结束包
  266.                                                                         {
  267.                                                                                 //读取成功了
  268.                                                                                 fileRes=f_write (&file, ymodemSohPack->ymodemData,sizeof(ymodemSohPack->ymodemData), &br);                //写入文件
  269.                                                                                 if(fileRes==FR_OK)
  270.                                                                                 {               
  271.                                                                                         MSG_OUT("写入成功");
  272.                                                                                         packNumCnt++;
  273.                                                                                         isAck=true; //应答、发送下一包
  274.                                                                                         failCnt=0;
  275.                                                                                 }
  276.                                                                                 else
  277.                                                                                 {
  278.                                                                                         isAck=false;//非应答、重新发送此包        
  279.                                                                                         failCnt++;
  280.                                                                                         if(failCnt>=5)
  281.                                                                                         {
  282.                                                                                                 failCnt=0;
  283.                                                                                                 MSG_OUT("文件写入失败");
  284.                                                                                                 ymodem_cancel_transport();//停止ymodem传输
  285.                                                                                                 while(1);
  286.                                                                                         }                                                                        
  287.                                                                                 }                                                                        
  288.                                                                         }
  289.                                                                         else//是结束包
  290.                                                                         {
  291.                                                                                 MSG_OUT("成功收到应答包");
  292.                                                                                 f_close (&file);//关闭文件
  293.                                                                                 progUpdateProcess = verifyDownloadProg;
  294.                                                                         }
  295.                                                                         
  296.                                                                 }
  297.                                                                 else
  298.                                                                 {
  299.                                                                         isAck=false;//非应答、重新发送此包
  300.                                                                         failCnt++;
  301.                                                                         if(failCnt>=5)
  302.                                                                         {
  303.                                                                                 failCnt=0;
  304.                                                                                 MSG_OUT("文件写入失败");
  305.                                                                                 ymodem_cancel_transport();//停止ymodem传输
  306.                                                                                 while(1);
  307.                                                                         }                                                        
  308.                                                                 }                                                        
  309.                                                         }
  310.                                                         else//1024 STX包
  311.                                                         {
  312.                                                                 if(ymodemStxPack->ymodemPackNum==(u8)(~ymodemStxPack->ymodemPackNumNegation)&&\
  313.                                                                         ymodem_crc16_cal(ymodemStxPack->ymodemData, sizeof(ymodemStxPack->ymodemData))\
  314.                                                                                 ==(ymodemStxPack->ymodemCrcH*256+ymodemStxPack->ymodemCrcL)&&\
  315.                                                                         ymodemStxPack->ymodemPackNum==packNumCnt)
  316.                                                                 {
  317.                                                                
  318.                                                                         //读取成功了
  319.                                                                         fileRes=f_write (&file, ymodemStxPack->ymodemData,sizeof(ymodemStxPack->ymodemData), &br);                //写入文件
  320.                                                                         if(fileRes==FR_OK)
  321.                                                                         {                                
  322.                                                                                 MSG_OUT("写入成功");
  323.                                                                                 packNumCnt++;
  324.                                                                                 isAck=true; //应答、发送下一包
  325.                                                                                 failCnt=0;
  326.                                                                         }
  327.                                                                         else
  328.                                                                         {
  329.                                                                                 isAck=false;//非应答、重新发送此包
  330.                                                                                 
  331.                                                                                 failCnt++;
  332.                                                                                 if(failCnt>=5)
  333.                                                                                 {
  334.                                                                                         failCnt=0;
  335.                                                                                         MSG_OUT("文件写入失败");
  336.                                                                                         ymodem_cancel_transport();//停止ymodem传输
  337.                                                                                         while(1);
  338.                                                                                 }
  339.                                                                                 
  340.                                                                         }
  341.                                                                 }
  342.                                                                 else
  343.                                                                 {
  344.                                                                         isAck=false;//非应答、重新发送此包
  345.                                                                         failCnt++;
  346.                                                                         if(failCnt>=5)
  347.                                                                         {
  348.                                                                                 failCnt=0;
  349.                                                                                 MSG_OUT("文件写入失败");
  350.                                                                                 ymodem_cancel_transport();//停止ymodem传输
  351.                                                                                 while(1);
  352.                                                                         }                                                        
  353.                                                                 }                                                        
  354.                                                         }
  355.                                                 }break;
  356.                                         }                                
  357.                                 }break;
  358.                                 case verifyDownloadProg:                //校验下载下来的程序
  359.                                 {               
  360.                                         fileRes=f_open(&file,buf,FA_READ);                //打开新文件
  361.                                         if(fileRes!=FR_OK)
  362.                                         {
  363.                                                 MSG_OUT("校验文件打开失败");
  364.                                                 while(1);                                                
  365.                                         }        
  366.                                         MSG_OUT("校验文件打开成功");
  367.                                        
  368.                                         if(file.fsize<programTotalSize)
  369.                                         {
  370.                                                 MSG_OUT("文件尺寸校验失败");
  371.                                                 f_close(&file);
  372.                                                 while(1);                                                
  373.                                         }
  374.                                         MSG_OUT("文件尺寸校验成功");
  375.                                        
  376.                                        
  377.                                         progUpdateProcess=carryProgToMcu;
  378.                                 }break;
  379.                                 case carryProgToMcu:                        //搬运程序进入MCU
  380.                                 {
  381.                                         MSG_OUT("开始更新程序");
  382.                                         updatingProgSize=programTotalSize;//程序读取字节
  383.                                         progWriteAddr=SAVE_PROGRAM_ADDR;        //程序写入MCU地址
  384.                                         __disable_irq();                                //关闭所有中断
  385.                                         while(1)//开始读取
  386.                                         {
  387.                                                 memset(buf,0x00,sizeof(buf));
  388.                                                 sprintf(buf,"程序已更新: %d/%d",(programTotalSize-updatingProgSize),programTotalSize);


  389.                                                 MSG_OUT(buf);
  390.                                                 if(updatingProgSize==0)                  //程序复制完成
  391.                                                 {
  392.                                                         MSG_OUT("程序更新完成");
  393.                                                         progUpdateProcess=verifyMcuProg;//执行校验程序
  394.                                                         
  395.                                                         f_close (&file);
  396.                                                         break;
  397.                                                 }                                                
  398.                                                 
  399.                                                 if(updatingProgSize<2048)
  400.                                                 {
  401.                                                         if(f_read (&file, &readProgBuf,updatingProgSize, &br)==FR_OK) //读取文件
  402.                                                         {
  403.                                                                 iap_write_appbin(progWriteAddr,readProgBuf,updatingProgSize);          //更新FLASH代码
  404.                                                                 updatingProgSize=0;
  405.                                                         }
  406.                                                         else
  407.                                                         {
  408.                                                                 MSG_OUT("程序文件读取失败!");
  409.                                                                 f_close (&file);
  410.                                                                 while(1);
  411.                                                         }
  412.                                                 }
  413.                                                 else
  414.                                                 {
  415.                                                         if(f_read (&file, &readProgBuf,2048, &br)==FR_OK) //读取文件
  416.                                                         {
  417.                                                                 iap_write_appbin(progWriteAddr,readProgBuf,2048);          //更新FLASH代码  
  418.                                                                 updatingProgSize-=2048;
  419.                                                                 progWriteAddr+=2048;
  420.                                                         }
  421.                                                         else
  422.                                                         {
  423.                                                                 MSG_OUT("程序文件读取失败!");
  424.                                                                 f_close (&file);
  425.                                                                 while(1);
  426.                                                         }
  427.                                                 }
  428.                                                 
  429.                                         }        
  430.                                         __enable_irq();                                //关闭所有中断
  431.                                 }break;
  432.                                 case verifyMcuProg:                        //校验搬运进入MCU的程序
  433.                                 {
  434.                                         MSG_OUT("开始MD5校验程序");
  435.                                         memset(buf,0x00,sizeof(buf));
  436.                                         get_bin_md5(SAVE_PROGRAM_ADDR,programTotalSize,buf);                        //MD5校验程序文件
  437.                                         if(strcmp((char *)md5StrBuf,buf)!=0)
  438.                                         {
  439.         
  440.                                                 MSG_OUT("程序MD5校验失败");
  441.                                                 while(1);
  442.                         
  443.                                         }                                       
  444.                                         MSG_OUT("MD5校验程序成功");
  445.                                         progUpdateProcess=recordProgInfo;//记录程序信息
  446.                                 }break;
  447.                                 case recordProgInfo:                        //记录程序信息
  448.                                 {
  449.                                         MSG_OUT("开始记录数据");
  450.                                        
  451.                                        
  452.                                         memset(sysParaSave.oldVersion,0x00,sizeof(sysParaSave.oldVersion));
  453.                                         memset(sysParaSave.newVersion,0x00,sizeof(sysParaSave.newVersion));
  454.                                         memset(sysParaSave.md5Val,0x00,sizeof(sysParaSave.md5Val));                                                
  455.                                        
  456.                                         memcpy(sysParaSave.oldVersion,versionStrBuf,sizeof(versionStrBuf));        //程序版本
  457.                                         memcpy(sysParaSave.newVersion,versionStrBuf,sizeof(versionStrBuf));        //程序版本
  458.                                         memcpy(sysParaSave.md5Val,md5StrBuf,sizeof(md5StrBuf));                                //MD5
  459.                                        
  460.                                         sysParaSave.programSize = programTotalSize;                                                        //程序大小
  461.                                        
  462.                                         if(sys_data_save()!=true)
  463.                                         {
  464.                                                 MSG_OUT("数据保存失败");
  465.                                                 while(1);
  466.                                         }
  467.                                         MSG_OUT("数据保存成功");
  468.                                         progUpdateProcess=jumpToAppProg;//执行跳转程序
  469.                                 }break;
  470.                                 case jumpToAppProg:                        //跳转到应用程序               
  471.                                 {
  472.                                         MSG_OUT("执行跳转");
  473.                                         __disable_irq();                                //关闭所有中断
  474.                                         iap_load_app(SAVE_PROGRAM_ADDR);//执行FLASH APP代码                                                
  475.                                 }break;                                
  476.                                 
  477.                         }
  478.                         
  479.                         
  480.                 }
  481.         }
  482. }
复制代码

五、主要说明


1、我用的是RS485协议,可以更改为SPI、IIC、串口、等。
2、程序自己已经在项目中使用,下面工程下载下来后可以直接使用,软件设置参考上面。
3、需要技术支持的可以在我的主页添加我的QQ、
4、项目中用到了FAFTS文件系统、MD5校验算法、在线IAP等知识。
5、项目中使用的存储介质是SPIFLASH(W25Q64),可以改为其他容量的。



收藏 评论0 发布时间:2022-4-20 20:40

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版