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

更新

0924,一些潜在的bug解决方案

前言

这周一直想做一个IAP固件升级的上位机,然后把升级流程全都搞懂。

我用的单片机型号是STM32F103VET6,FLASH容量是512K,FLASH单页是2K。

有纰漏请指出,转载请说明。

学习交流请发邮件 1280253714@qq.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	0x08010000U
#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


0924更新

之前的演示,终于能把新固件下载到单片机,并在单片机上面跑新固件。

可是有很多问题待解决

1.上位机怎么知道单片机接收到了正确的数据?

2.如果单片机接收的固件大于APP空间,该怎么处理?

3.升级过程,如果数据传输的通路断掉了(单片机挂了,上位机崩溃了,连接断开了),该怎么处理?

4.进入APP程序,发现不产生中断了?

5.如果待传输的新固件与当前的固件是同一个版本,还有必要传输吗?

6.之前的演示只能跑新固件,但是没有预留升级的接口,如何在APP写一份接口,支持可重复升级?

7.上位机怎么知道单片机固件升级结束?

待我一一道来

1.上位机怎么知道单片机接收到了正确的数据?

这个问题可难可简,最常见的是加校验,之前已经做了串口数据帧的校验,基本上是不会出错了。但如果要保证数据传输的准确性,还需要加一种校验,可以是CRC32、奇偶校验。如果还要进一步保证整个固件的准确性,需要再加一个文件校验可以是 MD5、SHA1等等。

这部分的工作由网上各位大神来做,我这里只提一嘴。

[CRC校验]手算与直观演示_哔哩哔哩_bilibili

MD5为何不再安全_哔哩哔哩_bilibili

2.如果单片机接收的固件大于APP空间,该怎么处理?

这种要看情况,如果只是用户给APP分配过小,可以考虑增大APP空间;如果是有两个APP代码,可以考虑空间合并,只跑一份APP。

3.升级过程,如果数据传输的通路断掉了(单片机挂了,上位机崩溃了,连接断开了),该怎么处理?

参考我之前写的博客

单片机IAP升级的一些问题与经验_iap更新_TianYaKe-天涯客的博客-CSDN博客

4.进入APP程序,发现不产生中断了?

需要设置中断向量表

stm32从bootloader跳转到app不进中断问题分析_bootloader不进中断_桉恺的博客-CSDN博客

Stm32 bootloader 与APP 跳转的方式和问题点。_stm32f030app里跳转boot实现烧录_JamesZhang88的博客-CSDN博客

5.待传输的新固件与当前的固件是同一个版本,还有必要传输吗?

首先这个问题很容易回答,没必要,但这不是关键。

这里有几个问题,

怎么知道新老固件的版本号?

版本号如何比对?

如何在传输过程中附带版本号信息?

我的解决办法是,在固件传输前,也就是上位机给单片机发开始传输的起始信号时,附带上版本号信息。然后单片机接受到后,跟存放在用户FLASH空间的版本号进行比对。

6.如何在APP写一份接口,支持可重复升级?

最简单的办法是,APP只做固件版本号判断和跳转到IAP的升级接口。

7.上位机怎么知道单片机固件升级结束?

最保险的办法是,在IAP跳转到APP后,由APP发送升级结束的信号。

不然可能出现IAP全部接收到固件,但是出现跳转失败的情况。

IAP固件升级,Qt上位机,支持重复升级、故障再升级_哔哩哔哩_bilibili

IAP固件升级,Qt上位机,支持重复升级、故障再升级

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32程序IAP(In-Application Programming)是一种在单片机运行时通过串口进行自动升级的技术。IAP的实现需要涉及到单片机端的源码和上位机端的源码。 在单片机端,需要编写实现IAP功能的源码。这段代码通常会包括接收上位机发送的升级文件,并将其存储到单片机的内存中。之后,单片机会进行校验和解析升级文件,将其写入到flash或者其他存储器中,完成程序的升级。同时,也需要实现一些监测和保护机制,用于保证升级的安全性和可靠性。 在上位机端,需要编写用于发送升级文件给单片机的源码。这段代码通常会包括打开串口、读取升级文件、片发送给单片机等操作。同时,还需要实现一些协议和通信机制,用于与单片机进行数据交互,并实时监测升级状态,确保升级过程的正确执行。 整套资料包括单片机端和上位机端的源码、协议文档、使用说明等。这些资料可以作为开发人员参考和学习,用于了解和实现STM32程序IAP自动升级功能。通过这些资料,开发人员可以快速上手,熟悉并掌握IAP的实现方法,提高开发效率。 总之,STM32程序IAP自动升级涉及到单片机端和上位机端的源码,别负责实现单片机升级功能和与单片机进行通信。整套资料的提供为开发人员提供了学习和实践的基础,帮助他们快速掌握和应用这一技术。 ### 回答2: STM32程序IAP是指通过串口升级的方式对单片机程序进行自动升级IAP(In Application Programming)是一种在应用程序运行期间对单片机进行编程的技术。 在STM32单片机中,使用IAP技术可以通过串口接口进行固件升级。整个升级过程可以为两部单片机源码和上位机源码。 单片机源码负责接收上位机发送的固件数据,并进行解析和存储。它包括串口接收中断的设置和数据解析、Flash存储管理以及固件升级的触发条件等功能。单片机源码需要根据具体的需求进行开发,并且需要考虑到升级过程中的容错处理和异常情况的处理。 上位机源码负责将需要升级固件数据发送给单片机。它包括串口通信的设置、文件读取和发送的功能。上位机源码可以使用各种编程语言进行开发,如Python、C#等,并根据具体的需求进行定制和优化。 整套资料包括单片机源码、上位机源码、使用说明以及示例固件等内容。这些资料提供了完整的升级解决方案,使用户可以根据自己的需求进行开发和定制。 通过使用STM32程序IAP自动升级,可以方便地实现单片机固件升级,提高了开发效率和产品的可维护性。同时,这种方式还可以避免由于硬件设计不当或者其他原因导致的固件更新困难的问题。 ### 回答3: STM32是一种广泛应用于嵌入式系统中的微控制器,它具有出色的性能和强大的功能。在STM32中,可以使用IAP(In-Application Programming)技术来实现自动升级。自动升级通过串口来进行,这意味着可以通过与计算机连接的串口进行单片机程序的升级。 在实现自动升级的过程中,需要编写 STM32 单片机的程序代码以及上位机的源码。 首先,需要编写单片机程序的源码。这个程序需要能够通过串口接收到来自上位机升级指令,并且能够将升级文件下载到单片机中进行更新。在编写单片机程序时,需要使用 STM32 的串口通信库函数,以实现与上位机的数据交互。同时,还需要编写代码来处理接收到的升级文件,并将其写入到单片机的 Flash 存储器中,实现程序的升级。 其次,还需要编写上位机的源码。这个上位机程序需要能够与单片机进行串口通信,并且能够将升级文件发送给单片机。在编写上位机程序时,需要使用计算机的串口通信库函数,以实现与单片机的数据交互。同时,还需要编写代码来读取本地的升级文件,并将其发送给单片机,实现程序的升级。 整套资料包括单片机程序源码和上位机程序源码。这些源码需要详细注释,以便其他开发人员能够理解和使用。此外,还需要提供详细的操作说明,包括如何编译、下载和运行单片机程序,以及如何编译和运行上位机程序。此外,还可以提供相关的参考资料和示例代码,以帮助开发人员更好地理解和使用该自动升级系统。 综上所述,实现STM32程序IAP自动升级串口升级需要编写单片机程序和上位机程序的源码,并提供整套资料,包括源码、操作说明和参考资料等,以便其他开发人员能够使用和理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值