2025年单片机IAP固件升级分几步?(Qt上位机)

单片机IAP固件升级分几步?(Qt上位机)更新 0924 一些潜在的 bug 解决方案 前言 这周一直想做一个 IAP 固件升级的上位机 然后把升级流程全都搞懂 我用的单片机型号是 STM32F103VET FLASH 容量是 512K FLASH 单页是 2K 有纰漏请指出 转载请说明 学习交流请发邮件

大家好,我是讯享网,很高兴认识大家。

更新

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

小讯
上一篇 2025-02-21 17:00
下一篇 2025-03-13 14:54

相关推荐

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