1、擦除要升级的flash
#define FMC_PAGE_SIZE ((uint16_t)0x800U)
#define FMC_WRITE_START_ADDR ((uint32_t)0x08003000U)
#define FMC_WRITE_END_ADDR ((uint32_t)0x0807FFFF)
void fmc_erase_pages(void)
{
uint32_t EraseCounter;
fmc_unlock();
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
for(EraseCounter = 0; EraseCounter < PageNum; EraseCounter++)
{
fmc_page_erase(FMC_WRITE_START_ADDR + (FMC_PAGE_SIZE * EraseCounter));
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
fmc_lock();
}
2、之后读取hex里面的数据
hex文件解析:
数据:n字节数据序列,由2个n十六进制数字表示;
校验码:(两个十六进制数字),可以用来验证记录没有错误的计算值;
注意校验和算法:累加和=校验码之前所有16进制,校验和=0x100-累加和。
第一行020000040804EE中,可以看做是0x02 0x00 0x00 0x04 0x08 0x04 0xEE,
02:代表本行有2个字节数据
0000:表示偏移地址或无用填0
04:扩展线性地址标识,表面后面2个字节数据是后面数据的基地址
注:由于每行标识数据地址的只有2Byte,所以最大只能到64K,为了可以保存高地址的数据,故有了扩展线性地址记录也叫作32位地址记录或HEX386记录.这些记录含数据的高16位,扩展线性地址记录总是有两个数据字节。
0804:是扩展地址 (0x0804 << 16) = 0x08040000后面的数据记录都以这个地址为基地址。
EE: 记录本行校验和 EE=0x100-(0x02+0x04+0x08+0x04)
第二行也按格式切分开为 10 0000 00 A8990020C1010408830B040839080408 DA
10:本行有0x10个Byte数据(即16个Byte数据)
0000:表示本行数据起始地址为0x08040000。下一行则是0x08040010依次类推
00:数据类型,表示后面字节为记录的数据
A8990020C1010408830B040839080408:16个byte的数据
DA: 校验和
00类型的行都大差不差,只是地址和数据不同而已,就不多赘述,以此类推即可。
uint8_t char2byte_back(char ch)
{
if(ch=='0') return 0x00;
if(ch=='1') return 0x01;
if(ch=='2') return 0x02;
if(ch=='3') return 0x03;
if(ch=='4') return 0x04;
if(ch=='5') return 0x05;
if(ch=='6') return 0x06;
if(ch=='7') return 0x07;
if(ch=='8') return 0x08;
if(ch=='9') return 0x09;
if(ch=='A'||ch=='a') return 0x0A;
if(ch=='B'||ch=='b') return 0x0B;
if(ch=='C'||ch=='c') return 0x0C;
if(ch=='D'||ch=='d') return 0x0D;
if(ch=='E'||ch=='e') return 0x0E;
if(ch=='F'||ch=='f') return 0x0F;
return 0;
}
uint8_t char2byte_front(char ch)
{
if(ch=='0') return 0x00;
if(ch=='1') return 0x10;
if(ch=='2') return 0x20;
if(ch=='3') return 0x30;
if(ch=='4') return 0x40;
if(ch=='5') return 0x50;
if(ch=='6') return 0x60;
if(ch=='7') return 0x70;
if(ch=='8') return 0x80;
if(ch=='9') return 0x90;
if(ch=='A'||ch=='a') return 0xA0;
if(ch=='B'||ch=='b') return 0xB0;
if(ch=='C'||ch=='c') return 0xC0;
if(ch=='D'||ch=='d') return 0xD0;
if(ch=='E'||ch=='e') return 0xE0;
if(ch=='F'||ch=='f') return 0xF0;
return 0;
}
void crc_compare(uint8_t* data,uint8_t len)
{
uint16_t sum_data = 0;
for(uint8_t i=0;i<len-1;i++)
{
sum_data += data[i];
}
uint8_t diff = 0x100-sum_data;
if(diff==data[len-1])
{
printf("data right\r\n");
//CRC校验没问题,之后应该将数据写进flash里面去才行
//第一个字节:是数量(即有多少个字节要写入flash中)
//第二和第三个字节:表示偏移地址
//第四个字节:表示功能,0x00就要写入flash ,0x04就要提取基址 ,0x05 开始线性地
uint8_t func_byte = data[3];
static uint32_t base_addr=0x00000000;
if(func_byte==0x04)
{
base_addr = (data[4]<<24)| (data[5]<<16);
}
if(func_byte==0x00)
{
uint32_t flash_addr = base_addr|((data[1]<<8)|data[2]);
fmc_unlock();
fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
for(uint8_t j=0;j<data[0];j=j+4)
{
//一次向32的地址写入32位的数据,数据是小端模式(低位在低地址,高位在高地址)
uint32_t temp_flash_data = 0x00000000;
temp_flash_data |= data[j+4+3]<<24;
temp_flash_data |= data[j+4+2]<<16;
temp_flash_data |= data[j+4+1]<<8;
temp_flash_data |= data[j+4+0]<<0;
printf("地址%#x : 接收的数据是 %#x\r\n",flash_addr, temp_flash_data);
fmc_word_program(flash_addr, temp_flash_data);
fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
flash_addr += 4U; //地址+4个字节,因为地址是32位的
}
flash_addr += 4U;
}
}
else
{
printf("data error\r\n");
}
}
void deal_hex_data(uint8_t data,uint8_t data_len)if(ch=='3') return 0x30;
{
uint8_t data[data_len/2];
for(uint8_t i=0;i<data_len-1;i=i+2)
{
uint8_t temp_i = char2byte_front(cdc->data[i]);
uint8_t temp_j = char2byte_back(cdc->data[i+1]);
data[i/2] = temp_i+temp_j;
}
crc_compare(data,data_len/2);
}