打印
[学习资料]

.Hex文件直接解析的实现_PIC芯片

[复制链接]
475|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zljiu|  楼主 | 2023-7-19 15:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.问题
        bootloader写成后,需要处理传送过来的.Hex,或者等价的文件的烧录。MicroChip官方并未给出一个.Hex转为.Bin的处理策略。在它的Bootloader代码中,我们可以大致看到它的实现机制,它定义了一组命令。上位机在处理升级时,与Bootloader要通过这组指令进行信息传递。这是一个交互式的协议。如果我们抛开这个交互协议,**自己处理升级过程,那么,需要对.Hex文件本身进行处理。然后才能让bootloader解析。

2.分析
2.1     Hex文件格式
Microchip给出了这个定义,参见:

MPLAB® IPE Intel HEX File Format | Microchip Technology
Learn what records are contained within a hex file and where the records are within the file.
https://www.microchip.com/en-us/education/developer-help/learn-tools-software/mcu-mpu/mplab-ipe/sqtp-file-format-specification/intel-hex

重点如下:

Hex文件被拆分为一条条记录。
每条记录头部固定,分别是
Byte0: ":"
Byte1: 数据字段长度
Byte2-3:数据要放置到的内存区域地址:两字节,这是英特尔固有的格式MSB,高位前,注意。
Byte4:这是类型,对PIC而言,只有3种类型:0,1,4。
0是实际的内存写入
1是文件结束标记。
4是一个高位地址设定指令,文件里地址位只有2Bytes.这条指令可以把地址空间扩展到32Bits.一般仅仅用来写控制字。
Byte5开始,是有效载荷。总长度= Byte1
最后一个字段是校验和,校验和从Byte1开始,至有效载荷结束。校验和要保证,从Byte1到它自身的值=0.
2.2     字节流分帧解析
//与Hex分帧相关的数据结构
#define FLASH_WRITE_BLOCK 64
#define HEX_MAX_RECORD 16
#define HEX_RECORD_STR_MAX (1+5*2+0x10*2)
struct _HexRecorderFilterObj
{
    uint16_t targetAddr;
    uint8_t write_block[FLASH_WRITE_BLOCK]; //注意類型
    uint8_t write_block_offset;
    uint8_t frame_cache[HEX_RECORD_STR_MAX+1];
    uint8_t frame_cache_offset;
    uint16_t debugCnt[4]; /*line, 0cnt, 1cnt, 4cnt*/
    uint32_t file_len;
}hexRecorderFilterObj;

//Hex分帧数据结构初始化
void HexRecordFilter_Init(void)
{
    //hexRecorderFilterObj.write_block_offset = 0;
    //hexRecorderFilterObj.frame_cache_offset = 0;
    memset(&hexRecorderFilterObj, 0, sizeof(hexRecorderFilterObj));
}

//辅助函数,将缓冲区中相邻的一个Hex字节读出来
//未考虑小写字符,未考虑容错
uint8_t Hex2Byte(uint8_t *buf)
{
    uint8_t ret;
    if((*buf>='0')&& (*buf<='9')) ret = (*buf - '0');
    else ret = (*buf - 'A') + 10;
    buf++;
    ret<<=4;
    if((*buf>='0')&& (*buf<='9')) ret |= (*buf - '0');
    else ret |= (*buf - 'A')+ 10;
    return ret;
}

//这里传入是已经是.hex的一个完整的帧
bool Decode_a_hex_frame(uint8_t *frame, uint32_t len)
{
//:1057E000FFFFFF00FFFFFF00FFFFFF00FFFFFF00C5
    if(Hex2Byte(frame+1)*2+5*2+1 != len) return false;
    hexRecorderFilterObj.file_len += len;
    hexRecorderFilterObj.debugCnt[0]++;
    switch(Hex2Byte(frame+7))
    {
        case 0x01: hexRecorderFilterObj.debugCnt[2]++; break;
        case 0x04: hexRecorderFilterObj.debugCnt[3]++; break;
        case 0x00: hexRecorderFilterObj.debugCnt[1]++; break;
        default:
            return false;
    }
    return true;
}

//一个统计函数
void PrintHexFileFilterDesc(void)
{
    xlog("total rec:%d, f0:%d,f1:%d,f4:%d; filelen=%d\r\n",
            hexRecorderFilterObj.debugCnt[0],
            hexRecorderFilterObj.debugCnt[1],
            hexRecorderFilterObj.debugCnt[2],
            hexRecorderFilterObj.debugCnt[3],
            hexRecorderFilterObj.file_len);
}

//顶层函数,传入Hex的分段读入的信息
//已适当考虑容错
HAL_StatusTypeDef HexRecordFilter(uint8_t *buf, uint32_t len)
{
//:1057F00000000000FFFF0000EE2300007F3E0000DD
    do
    {
        if(hexRecorderFilterObj.frame_cache_offset>0)
        {
            if(hexRecorderFilterObj.frame_cache_offset>HEX_RECORD_STR_MAX)
            {
                hexRecorderFilterObj.file_len+=hexRecorderFilterObj.frame_cache_offset;
                hexRecorderFilterObj.frame_cache_offset = 0;
            }
            else if((*buf=='\r') || (*buf == '\n'))
            {
                hexRecorderFilterObj.frame_cache[hexRecorderFilterObj.frame_cache_offset] = 0;
                if(!Decode_a_hex_frame(hexRecorderFilterObj.frame_cache, hexRecorderFilterObj.frame_cache_offset))
                {
                    //return HAL_ERROR;
                }
                hexRecorderFilterObj.file_len++;
                hexRecorderFilterObj.frame_cache_offset = 0;
            }
            else hexRecorderFilterObj.frame_cache[hexRecorderFilterObj.frame_cache_offset++] = *buf;
        }
        else if(*buf == ':')
        {
            hexRecorderFilterObj.frame_cache[0] = *buf;
            hexRecorderFilterObj.frame_cache_offset = 1;
        }
        else
        {
            hexRecorderFilterObj.file_len++;
        }
        buf++;
        len--;
    }while(len>0);
    return HAL_OK;
}

3.实现结果
total rec:292, f0:289,f1:1,f4:2; filelen=13056

实际的文件: filelen:12956字节。记录292行。无误。

附录A .hex文件的三类记录的官方示例
MPLAB IPE Example SQTP File | Microchip Technology
————————————————
版权声明:本文为CSDN博主「子正」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/twicave/article/details/131574314

使用特权

评论回复
沙发
xinxianshi| | 2023-7-19 15:56 | 只看该作者
有没有文档说明。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

3323

帖子

3

粉丝