STM32关于IAP程序升级几个小知识

1.bootLoader文件按正常工程编译。

2.app文件需要编译成bin格式文件。

   hex文件与bin文件区别

      a.hex文件中包含了数据和地址信息,bin文件中只包含了数据。

      b.bin文件右键单击属性可以看到其文件大小,hex文件看到的不是实际大小,其中包含了其他信息。

 bin文件格式

  对二进制文件而言,其实没有”格式”。文件只是包括了纯粹的二进制数据。

 

 hex文件格式

 

Record structure

 

  A record (line of text) consists of six fields (parts) that appear in order from left to right:

  1. Start code, one character, an ASCII colon ':'.
  2. Byte count, two hex digits, indicating the number of bytes (hex digit pairs) in the data field. The maximum byte count is 255 (0xFF). 16 (0x10) and 32 (0x20) are commonly used byte counts.
  3. Address, four hex digits, representing the 16-bit beginning memory address offset of the data. The physical address of the data is computed by adding this offset to a previously established base address, thus allowing memory addressing beyond the 64 kilobyte limit of 16-bit addresses. The base address, which defaults to zero, can be changed by various types of records. Base addresses and address offsets are always expressed as big endian values.
  4. Record type (see record types below), two hex digits, 00 to 05, defining the meaning of the data field.
  5. Data, a sequence of n bytes of data, represented by 2n hex digits. Some records omit this field (n equals zero). The meaning and interpretation of data bytes depends on the application.
  6. Checksum, two hex digits, a computed value that can be used to verify the record has no errors.
  7.  

 

   HEX文件都是由记录(RECORD)组成的。在HEX文件里面,每一行代表一个记录。记录的基本格式为:
         +---------------------------------------------------------------+
         |   RECORD  | RECLEN |  LOAD  | RECTYPE | INFO or DATA | CHKSUM |
         |  MARK ':' |        | OFFSET |         |              |        |
         +---------------------------------------------------------------+
         |  1-byte   | 1-byte | 2-byte | 1-byte  |    n-byte    | 1-byte |
         +---------------------------------------------------------------+

         记录类型包括:
         '00' Data Rrecord:用来记录数据,HEX文件的大部分记录都是数据记录
         '01' End of File Record: 用来标识文件结束,放在文件的最后,标识HEX文件的结尾
         '04' Extended Linear Address Record: 用来标识扩展线性地址的记录
         '02' Extended Segment Address Record: 用来标识扩展段地址的记录

         在上面的后2种记录,都是用来提供地址信息的。每次碰到这2个记录的时候,都可以根据记录计算出一个“基”地址。
         对于后面的数据记录,计算地址的时候,都是以这些“基”地址为基础的。

         数据记录的具体格式:
         +---------------------------------------------------------------+
         |   RECORD  | RECLEN |  LOAD  | RECTYPE | INFO or DATA | CHKSUM |
         |  MARK ':' |        | OFFSET |  '00'   |              |        |
         +---------------------------------------------------------------+
         |  1-byte   | 1-byte | 2-byte | 1-byte  |    n-byte    | 1-byte |
         +---------------------------------------------------------------+         

         看个例子:
        :020000040000FA
        :10000400FF00A0E314209FE5001092E5011092E5A3
        :00000001FF         

        对上面的HEX文件进行分析:
        第1条记录的长度为02,LOAD OFFSET为0000,RECTYPE为04,说明该记录为扩展段地址记录。数据为0000,校验和为
        FA。从这个记录的长度和数据,我们可以计算出一个基地址,这个地址为0X0000。后面的数据记录都以这个地址为基
        地址。
        第2条记录的长度为10(16),LOAD OFFSET为0004,RECTYPE为00,说明该记录为数据记录。
        数据为FF00A0E314209FE5001092E5011092E5,共16个BYTE。这个记录的校验和为A3。此时的基地址为0X0000,加上OFFSET,
        这个记录里的16BYTE的数据的起始地址就是0x0000 + 0x0004 = 0x0004.
        第3条记录的长度为00,LOAD OFFSET为0000,TYPE = 01,校验和为FF。说明这个是一个END OF FILE RECORD,标识
        文件的结尾。

 

 

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

 

3.uint8_t   UART_RX_BUF[1024]   __attribute__ ((at(0X20001000)));

//将接收到的app程序写入到ram 0x20001000之后的地方

//ram起始位置0x20000000 存放中断向量位置,所以从0x20001000存放app代码

__attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。

 

在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(紧凑模式)

在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非紧凑模式)

在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5

    __attribute__ ((packed))关键字  用指定变量或结构位域的特殊属性,该关键字后的双括弧中的内容是属性说明。

 

   at      关键字 用来设置变量的绝对地址,通过这个关键字指定某个变量处于内存里面的某个指定的地址。 

if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)

//判断是否为0X08XXXXXX.

//app程序计划放在起始位置为0x8010000

 

Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。

u16 iapbuf[1024];   //中转数组  2K内容

void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
u16 t;
u16 i=0;
u16 temp;
u32 fwaddr=appxaddr;//写入的地址
u8 *dfu=appbuf;  

for(t=0;t<appsize;t+=2)
{    
temp=(u16)dfu[1]<<8;
temp+=(u16)dfu[0]; //小端数据存储  整合为半字(16bit)  
dfu+=2;//偏移2个字节    //指向字节 需要跳过两字节
iapbuf[i++]=temp;    
if(i==1024)  //2k内容已经装满
{
i=0;
STMFLASH_Write(fwaddr,iapbuf,1024);
fwaddr+=2048;//偏移2048  跳到下一扇区 跳过2k
}
}

if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去. 

}

u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u32 secpos;   //扇区地址
u16 secoff;   //扇区内偏移地址(16位字计算)
u16 secremain;     //扇区内剩余地址(16位字计算)   
  u16 i;    
u32 offaddr;       //去掉0X08000000后的地址
if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
FLASH_Unlock(); //解锁
offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址. 与0x08000000偏移多少
secpos=offaddr/STM_SECTOR_SIZE; //扇区地址 第几个扇区 0~127 for STM32F103RBT6
        secoff=(offaddr%STM_SECTOR_SIZE)/2;//在扇区内的偏移(2个字节为基本单位.) 写入的起始地址与此扇区首地址偏移多少
secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小   
if(NumToWrite<=secremain)secremain=NumToWrite;//写入的数据小于2k
while(1) 
{
STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据  判断要写扇区是否全部为0xffff
{
if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除    
}
if(i<secremain)//需要擦除  说明中间有为擦除的地址 需要重新擦除
{
FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
for(i=0;i<secremain;i++)//复制
{
STMFLASH_BUF[i+secoff]=pBuffer[i];  
}
STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.   
if(NumToWrite==secremain)break;//写入结束  表示数据个数等于剩余的secremain 否则继续写
else//写入未结束
{
secpos++; //扇区地址增1  使用下个扇区
secoff=0; //偏移位置为0  从该扇区首地址写  
  pBuffer+=secremain;   //数据指针偏移  撇开先前写过的数据
WriteAddr+=secremain; //写地址偏移 跳下一扇区 跳过2k
  NumToWrite-=secremain; //字节(16位)数递减 减掉已经写过的数据个数
if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
else secremain=NumToWrite;//下一个扇区可以写完了
}  
};
FLASH_Lock();//上锁

}

void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   
{  
u16 i;
for(i=0;i<NumToWrite;i++)
{
FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
   WriteAddr+=2;//地址增加2.一次写2字节,跳过2个字节位置
}  

参考原子哥iap代码,芯片stm32c8t6https://download.csdn.net/download/goldbr/10646028

芯片stm32vct6https://download.csdn.net/download/goldbr/10646038

原理图就不上了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值