stm32同时编译多个固件

stm32同时编译多个固件,第1张

为满足日常开发需求,现在很多情况下一个片子需要通过BootLoader和Application两段程序组成。

Bootloader:一般用作用户升级Application用户程序用,程序的起始地址为:0x08000000,当遇到Application程序有更新的情况下,可以很方便和友好的通过BootLoader程序来对其进行更新。Bootloader更新Application的方式和途径有很多,比如串口的IAP、U盘的IAP等等,本人常用U盘进行升级。

Application:用户程序。一般起始地址并不是再0x08000000。

调试烧写hex固件的方式我一般选择的是Jflash,方式也很多,比如,Stlink的烧写软件,串口的烧写软件(MCUISP挺好用)等等。

第一步:将多个HEX文件合并成一个HEX文件。

这里以两个HEX为例,其中一个为BootLoader,另一个为Application。

1.新建一个文本文档,并命名成XXX.hex

2.通过各种编辑器分别打开BootLoader.hex、Application.hex和XXX.hex。我这里用的是notepad++。

3.把Bootloader里面的内容全部复制到XXX.hex中

4.删除XXX.hex中的最后一行(:00000001FF)

5.将Application.hex中的内容全部复制并添加到XXX.hex的结尾

6.保存,此时的XXX.hex文件就是一个合并了Bootloader和Application的固件。

第二步:烧写固件

烧写固件比较简单,但是要注意两个hex的文件要确保烧写的地址。

hex文件格式是可以烧写到单片机中,被单片机执行的一种文件格式。

生成Hex文件的方式有很多种,可以通过不同的编译器将C程序或者汇编程序编译生成hex。Hex文件如果用特殊的程序来查看(一般记事本就可以实现)。打开后可发现,整个文件以行为单位,每行以冒号开头,内容全部为16进制码(以ASCII码形式显示)。

Intel HEX文件由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和常量数据的十六进制编码数字组成。

扩展资料:

一个Intel HEX文件必须有一个文件结束记录,这个记录的类型域必须是01,Intel hex 文件常用来保存单片机或其他处理器的目标程序代码。它保存物理程序存储区中的目标代码映象。一般的编程器都支持这种格式。

Intel hex 文件记录中的数字都是16进制格式,两个16进制数字代表一个字节。CC域是数据域中的实际字节数,地址、记录类型和校验和域没有计算在内。校验和是取记录中从数据字节计数域CC到数据域最后一个字节的所有字节总和的 2 的补码。

参考资料来源:百度百科——hex文件格式

hex文件是用ASCII来表示二进制的数值,十六进制数组成的指令或者数据,每一行就是一个hex记录。由于单片机执行的只能是二进制指令和数据,而hex文件是十六进制数,所以烧录器的工作必然有一个进制转换机制。

hex文件的内容都是有规律的编码,我们可以对它进行解析,以第一行 :020000040800F2 为例:

1) 每一行都以 :(0x3A)开头

2) 第1个字节0x02 ,表示数据区的字节个数

3) 第2、3字节0x00, 0x00 ,表示偏移地址或无用填0

4) 第4个字节0x04, 表示本行记录的数据类型

‘00’ Data Record                  :用来记录数据, HEX文件的大部分记录都是数据记录

‘01’ End of File Record              :用来标识文件结束,放在文件的最后,标识HEX文件的结尾

‘02’ Extended Segment Address Record  :用来标识扩展段地址的记录

‘03’ Start Segment Address Record    :段地址 STM32不用

‘04’ Extended Linear Address Record  :用来标识扩展线性地址

‘05’ Start Linear Address Record    :程序启动运行的地址

5) 第5、6个字节0x08, 0x00即是数据

6) 第7个字节0xF2是校验字节,校验和的算法为:计算从0x3A 以后(不包括0x3A)的所有各字节的和模256的余。即各字节二进制算术和,不计超过256的溢出值,然后用0x100减去这个算数累加和,得出得值就是此行得校验和。

7) 每条数据最后还有<0x0d>(回车键)、 <0x0a>(换行键)

<0x3a>  [数据长度-1Byte] [数据地址-2Byte] [数据类型-1Byte] [数据-nByte] [验证码-1Byte] <0x0d><0x0a>

注意:由于每行标识数据地址的只有2Byte,所以最大只能到64K,为了可以保存高地址的数据,就有了Extended Linear Address Record。如果这行的数据类型是0x04,那么,这行的数据就是随后数据的基地址。例如:

第一行,是Extended Linear Address Record,里面的数据,也就是基地址是0x0004,

第二行是Data Record,里面的地址值是0x0000。那么数据18F09FE518F09FE518F09FE518F09FE5要写入FLASH中的地址为(0x0004 <<16) | 0x0000,也就是写入FLASH的0x40000这个地址。

第三行的数据的写入地址为0x40010。当一个HEX文件的数据超过7k的时候,文件中就会出现多个Extended Linear Address Record。

----------------------------------------------------

:020000040008F2

:10000400FF00A0E314209FE5001092E5011092E5A3

:00000001FF      

-----------------------------------------------------

对上面的HEX文件进行分析:

第1条记录的长度为02,LOAD

OFFSET为0000,RECTYPE为04,说明该记录为扩展段地址记录。数据为0008,校验和为F2。从这个记录的长度和数据,我们可以计算出一个基地址,这个地址为(0x0008

<<16)。后面的数据记录都以这个地址为基地址。

第2条记录的长度为10(16),LOAD

OFFSET为0004,RECTYPE为00,说明该记录为数据记录。数据为FF00A0E314209FE5001092E5011092E5,共16个BYTE。这个记录的校验和为A3。此时的基地址为0X80000,加上OFFSET,这个记录里的16BYTE的数据的起始地址就是0x80000

+ 0x0004 = 0x80004.

第3条记录的长度为00,LOAD OFFSET为0000,TYPE = 01,校验和为FF。说明这个是一个END OF FILE RECORD,标识文件的结尾。

在上面这个例子里,实际的数据只有16个BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址为0x0004.

计算从(0x3a)以后的所有各字节的和模256的余。

即各字节二进制算术和,不计超过256的溢出值,然后用0x100减去这个算数累加和,得出的值就是此行校验码。举一个简单的例子,

如第一行020000040800F2

0x02+0x00+0x00+0x00+0x04+0x08+0x00 = 0x0E

0x100 – 0x0E = 0xF2

for (i = 0i <pHexFileFormat->DataSizei++)

{

     tempCheckSum += pHexFileFormat->bData[i]

}

tempCheckSum = 0x100 - tempCheckSum

if (tempCheckSum != pHexFileFormat->CheckSum)

{

     //Error

}

#ifndef CHEX_H

#define CHEX_H

#include <QFile>

const quint8 MIN_HEX_LINE_COUNT_LENGHT = 12

typedef enum __tagHexErrorCode

{

    HEX_NO_ERROR = 0,

    HEX_FORMAT_ERROR,

    HEX_VERIFY_ERROR,

    HEX_LENGHT_ERROR,

    HEX_USERPAPR_EEROR,

}EHexErrorCode

typedef enum __tagHexType

{

    RECORD_DATA = 0,

    RECORD_END_OF_FILE,

    RECORD_EXTENDED_SEGMENT_ADDRESS,

    RECORD_START_SEGMENT_ADDRESS,

    RECORD_EXTENDED_LINEAR_ADDRESS,

    RECORD_START_LINEAR_ADDRESS,

    RECORD_HEX_MAX,

}emHexType

typedef struct __tagHexLineData

{

    emHexType  type

    quint8      count

    quint32    address

    quint8      data[80]

    quint8      checksum

    quint8      datalen

}stHexLineData

class CHex

{

public:

    CHex()

    EHexErrorCode getHexLineData(QByteArray bydata,stHexLineData *p)

private:

    char ConvertHexChar(char ch)

}

#endif // CHEX_H

#include "chex.h"

const QString HexTypeTable[6] =

{

    "00","01","02","03","04","05",

}

CHex::CHex()

{

}

char CHex::ConvertHexChar(char ch)

{

    if((ch >= '0') &&(ch <= '9'))

        return (ch-0x30)

    else if((ch >= 'A') &&(ch <= 'F'))

        return ((ch-'A')+10)

    else if((ch >= 'a') &&(ch <= 'f'))

        return ((ch-'a')+10)

    else return (-1)

}

EHexErrorCode CHex::getHexLineData(QByteArray bydata,stHexLineData *p)

{

    quint8 i = 0

    quint8 cs_temp = 0

    QString str(bydata)

    char *pcdata = bydata.data()

    quint32 linelen = str.size()

    if((linelen <MIN_HEX_LINE_COUNT_LENGHT)) {return HEX_LENGHT_ERROR}

    if(*pcdata != 0x3A) {return HEX_FORMAT_ERROR}//必须以":"号开始

    //获取Type

    QString stype = str.mid(7,2)

    for(i = 0i <RECORD_HEX_MAXi++)

    {

        if(stype == HexTypeTable[i])

        {

            p->type = (emHexType)i

            break

        }

    }

    if(i == RECORD_HEX_MAX) {qDebug("HEX_FORMAT_ERROR")return HEX_FORMAT_ERROR}

    cs_temp += (ConvertHexChar(*(pcdata + 7)) <<4) | ConvertHexChar(*(pcdata + 8))

    //获取count

    p->count = (ConvertHexChar(*(pcdata + 1)) <<4) | ConvertHexChar(*(pcdata + 2))

    cs_temp += p->count

    if(p->count != (((linelen - 2) / 2) - 5)) {qDebug("HEX_FORMAT_ERROR")return HEX_FORMAT_ERROR}

    //获取address

    p->address = (ConvertHexChar(*(pcdata + 3)) <<12) | (ConvertHexChar(*(pcdata + 4)) <<8) | (ConvertHexChar(*(pcdata + 5)) <<4) | ConvertHexChar(*(pcdata + 6))

    cs_temp += (p->address >>8) &0xFF

    cs_temp += p->address &0xFF

    //获取data

    for(i = 0i <p->counti++)

    {

        p->data[i] = (ConvertHexChar(*(pcdata + 2*i + 9)) <<4) | ConvertHexChar(*(pcdata + 2*i + 10))

        cs_temp += p->data[i]

    }

    p->checksum = (ConvertHexChar(*(pcdata + 2*i + 9)) <<4) | ConvertHexChar(*(pcdata + 2*i + 10))

    if(p->checksum != ((0x100 - cs_temp) &0xFF))

    {

        qDebug("HEX_VERIFY_ERROR")

        return HEX_VERIFY_ERROR

    }

    p->datalen = p->count

    return HEX_NO_ERROR

}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/12101955.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存