更新
0924,一些潜在的bug解决方案
前言
这周一直想做一个IAP固件升级的上位机,然后把升级流程全都搞懂。
我用的单片机型号是STM32F103VET6,FLASH容量是512K,FLASH单页是2K。
有纰漏请指出,转载请说明。
学习交流请发邮件 @.com
IAP原理
IAP的原理我就不多赘述了,这里贴上几位大佬的文章
STM32CubeIDE IAP原理讲解,及UART双APP交替升级IAP实现-CSDN博客
STM32 IAP升级固件 + 上位机 例程 | 码农家园
IAR环境下STM32+IAP方案的实现
之前做过IAP,也讲解了一些存在的问题,参考之前我写的博客
单片机IAP升级的一些问题与经验_iap更新_TianYaKe-天涯客的博客-CSDN博客
0923初版
Qt读取二进制文件
读取二进制文件,将内容放在binRawData里
void MainWindow::readFw() { QFileDialog dlg(this); QString fileName = dlg.getOpenFileName(this, tr("Open"), "./", tr("Bin File(*.bin)")); if( fileName == "" ) { return; } QFile file(fileName); QFileInfo fileInfo(fileName); fwFileLen = fileInfo.size(); fwPackNum = fwFileLen/fwPackLength + 1; if(file.open(QIODevice::ReadOnly)) { binRawData = file.readAll(); ui->lineEdit_fwUpdateFile->setText(fileName); ui->textEdit_fwUpdateFile->append(binRawData.toHex()); file.close(); ui->pushButton_startFwUpdate->setEnabled(true); ui->pushButton_stopFwUpdate->setEnabled(false); } else { QMessageBox::warning(this, tr("Error"), tr("Fail to open file!")); } }
讯享网
将binRawData拆包,并调用串口发送
讯享网connect(fwUpdateTimer,&QTimer::timeout,[=](){ if(fwUpdateState == 1) { QByteArray fwSendBuff = binRawData.mid(fwPackIndex*fwPackLength+1,fwPackLength); fwPackIndex++; serialPort->write(fwSendBuff); if(fwPackIndex>fwPackNum) { fwUpdateTimer->stop(); fwUpdateState = 3; } } });

加上固件传输的协议

发送开始指令,发送固件包大小
void MainWindow::startFwUpdate() { ui->pushButton_startFwUpdate->setEnabled(false); ui->pushButton_stopFwUpdate->setEnabled(true); fwUpdateState = fwStart; QByteArray startCmd; uchar startCmd1 = 0xAB; uchar startCmd2 = 0xf0; startCmd = loadTxMsg(startCmd1, startCmd2, &startCmd); serialPort->write(startCmd); delay_ms(1000); uchar cmd1 = 0xAB; uchar cmd2 = 0xf1; uchar uData[2]; uint16_t u16FwPackNum = fwPackNum; *(uint16_t *)&uData[0] = *(uint16_t *)&u16FwPackNum; QByteArray txFwData; txFwData.append(uData[0]); txFwData.append(uData[1]); txFwData = loadTxMsg(cmd1, cmd2, &txFwData); serialPort->write(txFwData); fwUpdateTimer->start(100); }
通过定时器逐帧传输,传输结束后发送结束信号
讯享网connect(fwUpdateTimer,&QTimer::timeout,[=](){ if(fwUpdateState == fwStart) { QByteArray fwSendBuff = binRawData.mid(fwPackIndex*fwPackLength,fwPackLength); fwSendBuff.insert(0,fwSendBuff.length()); QByteArray fwSendProtocolBuff = loadFwPackData(&fwSendBuff); serialPort->write(fwSendProtocolBuff); fwPackIndex++; QString fwDataString = ByteArrayToHexString(fwSendProtocolBuff).toLatin1(); ui->textEdit_fwInfo->clear(); ui->textEdit_fwInfo->setWordWrapMode(QTextOption::WordWrap); ui->textEdit_fwInfo->insertPlainText(QString("[")); ui->textEdit_fwInfo->insertPlainText(QString::number(fwPackIndex)); ui->textEdit_fwInfo->insertPlainText(QString("] ")); ui->textEdit_fwInfo->insertPlainText(fwDataString); if(fwPackIndex>=fwPackNum) { fwUpdateState = fwComplete; fwUpdateTimer->stop(); QByteArray stopCmd; uchar stopCmd1 = 0xAB; uchar stopCmd2 = 0xf3; stopCmd = loadTxMsg(stopCmd1, stopCmd2, &stopCmd); serialPort->write(stopCmd); } } });
STM32代码部分
iap.h
#ifndef __IAP_H #define __IAP_H #include "includes.h" #define __APP_START_ADDR 0x0U #define __APP_SIZE 0x10000U typedef enum { IAP_START, IAP_TRANFER, IAP_COMPLETE, } IAP_Status; typedef struct { u8 u8Length; // 当前接受到数据帧的帧长 u8 u8Data[64]; // 当前接受到的数据 } RcvFrame_S; typedef struct { IAP_Status state; // ipa升级当前状态 RcvFrame_S stRcvFrame; // 接受到的数据 u16 u16FwFrameNum; // 固件数据帧总量 u16 u16FwFrameIndex; // 固件数据帧偏移 u32 u32WriteAddrIndex; // 写地址偏移 } IAP_S; extern IAP_S stIap; void IapRcvDataProc(u8 *MsgData); typedef void (*Application)(void); void JumpToApplication(void); #endif //__IAP_H
iap.c
讯享网#include "includes.h" IAP_S stIap; void IapRcvDataProc(u8 *MsgData) { u8 cmd = MsgData[3]; u8 i = 0; switch(cmd) { case 0xF1: EraseFwSpace(__APP_START_ADDR,__APP_SIZE/__FLASH_PAGE_SIZE); memcpy(&stIap.u16FwFrameNum, &MsgData[4], 2); break; case 0xF2: stIap.u16FwFrameIndex++; stIap.stRcvFrame.u8Length = MsgData[6]; memcpy(&stIap.stRcvFrame.u8Data, &MsgData[7], stIap.stRcvFrame.u8Length); for(i = 0; i < stIap.stRcvFrame.u8Length; i += 4) //一次写入是4个字节 { FlashWriteWord(__APP_START_ADDR+stIap.u32WriteAddrIndex, *(u32 *)&stIap.stRcvFrame.u8Data[i]); stIap.u32WriteAddrIndex += 4; //写入的地址加4 } break; case 0xF3: JumpToApplication(); } } void JumpToApplication(void) { Application application; __set_FAULTMASK (1); application = (Application)(*(__IO u32*)(__APP_START_ADDR+4)); __set_MSP(*(__IO u32*)(__APP_START_ADDR)); SCB->VTOR = __APP_START_ADDR; application(); }
视频演示
IAP固件升级(Qt上位机)最初版0923_哔哩哔哩_bilibili
IAP固件升级(Qt上位机)最初版0923

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/46040.html