乐于分享
好东西不私藏

Microchip单片机Flash地址说明及hexmate工具使用

Microchip单片机Flash地址说明及hexmate工具使用

文章末尾获取此Demo源代码文件资料↓
软件平台:MCC v5.5.2、MPLAB X IDE v6.25
硬件平台:PIC18F46Q84

dsPIC33单片机地址说明

在hex文件中地址是按照字节对齐的而dsPIC33单片机的flash地址是按照字对齐的,所以hex地址是flash地址的2倍。hex文件中04是地址扩展标志,当Flash地址大于一定范围时就会使用。比如:地址大于0x7FFF时

按小端模式保存:低地址保存数据低位,高地址保存数据高位。

dsPIC的程序存储器是按照word(2个字节)对齐而hex文件中则是按照字节对齐的。在MPLAB X IDE的Program Memory窗口中地址是按word对齐,所以dsPIC33EP256MU810的指令占用的存储空间范围:87552*2 = 175104 words,所以地址范围为0x00-0x2AC00

Flash地址(字对齐)转换成hex地址(字节对齐)

hex文件中地址 = 需要包含的Flash地址的下1个地址值*2-1,如:我们需要获取0x00-0x5EFA(包含边界0x5EFA存储区域内容)则其对应的hex地址范围:0x00-(0x5EFC*2-1)即0x00-0xBDF7

编译后生成的Hex文件地址分布与dsPIC33CK32MP502的地址分布对应关系如下所示,配置字开始地址是0x5F00在hex文件中对应的地址是0x5F00*2 = 0xBE00

hex文件中配置字地址和dsPIC33CK32MP502手册中对应关系

CRC32算法说明

多项式方向:使用 MSB-first(左移算法),通常为 crc = (crc << 8) ^ table[(crc >> 24) ^ byte]。使用查表法,相应的C代码如下:

#define IMAGE_HEX_START_ADDRESS     (0x0UL)#define IMAGE_HEX_END_ADDRESS       (0x5EFEUL)#define IMAGE_HEX_SIZE              (IMAGE_HEX_END_ADDRESS - IMAGE_HEX_START_ADDRESS + 1)#define POLYNOMIAL_VALUE            (0x814141ABUL)#define INIT_VALUE                  (0x00000000UL)    // flash range include endAddrByteuint32_tCRCFlash_Fast(uint32_t crc, uint32_t startAddrByte, uint32_t endAddrByte){    uint32_t flashWord;    while(startAddrByte <= endAddrByte)    {        flashWord = FLASH_ReadWord24(startAddrByte);        // byte 0        crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (uint8_t)(flashWord & 0xFF)) & 0xFF];        // byte 1        crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (uint8_t)((flashWord >> 8) & 0xFF)) & 0xFF];        // byte 2        crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (uint8_t)((flashWord >> 16) & 0xFF)) & 0xFF];        // byte 3        crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ (uint8_t)((flashWord >> 24) & 0xFF)) & 0xFF];        startAddrByte += 2// word align    }    return crc;}

注意:当MCU中CRC32校验算法计算dsPIC33CK32MP502整个flash(0x00-0x5EFE)的CRC32值与hexmate命令计算得到的CRC32值不一样时,检查因为多项式方向是否不同,hexmate中使用的CRC32算法是MSB-First的多项式。

编译生成的Hex文件说明

使用MPLAB X IDE编译生成的hex文件中会删除没有使用的Flash区域内容,这样可以节省下载时间。但是在一些情况下,我们需要完整的Flash内容,比如验证Flash是否有损坏时需要使用CRC32算法计算整个Flash的CRC32值,这时就可以使用-FILL选项来实现将没有使用的Flash区域填充为Flash擦除后的值。如下所示:

hexmate ${ImagePath} -o${ImagePath} -FILL=w1:0xFF,0xFF,0xFF,0x00@0x0000:0xBDFF +-CK=0-BDF7@0xBDFCw-4g5p814141AB -LOGFILE=finaldsPIC.hxl

hexmate工具使用

计算0x0-0xBDFF地址范围内容的CRC32值hexmate命令:
hexmate ${ImagePath} -o${ImagePath}_crc.hex +-CK=0-BDFF@0w-4g5p814141AB -LOGFILE=finaldsPIC.hxl
将上述hexmate命令添加到IDE的after build中

因为从hex文件中可以看出来最大的flash地址只到0-0x30D6(包含边界),而实际flash范围0-0x5EFE(包含边界)。

使用-FILL命令填充后Flash整个区域的内容都会生成在hex文件中。

QT中CRC32表生成代码

// Microchip的CRC32表voidMainWindow::generateCRC32Table_MSB(uint32_t polynomial, uint32_t table[256]){    for (uint32_t i = 0; i < 256; ++i) {        uint32_t crc = i << 24;      // 将字节放到最高8位        for (int bit = 0; bit < 8; ++bit) {            if (crc & 0x80000000)    // 检查最高位                crc = (crc << 1) ^ polynomial;            else                crc <<= 1;        }        table[i] = crc;    }}uint32_t table[256];generateCRC32Table_MSB(POLY, table);QDebug debug = qDebug();debug << "uint32_t CRC32_814141AB_table[256] = {";for (int i = 0; i < 256; ++i) {   debug << QString::asprintf("0x%08X", table[i]);   if (i != 256 - 1) debug << ", ";}  debug << "};";
使用hexmate加工hex文件
.${_/_}generate_hex$(ShExtension) $(MP_CC_DIR) ${ProjectDir} ${ImageDir} ${ImageName} ${IsDebug} && cd ${ProjectDir} 
使用hexmate进行hex镜像拼接时按照地址顺序从低地址到高地址依次拼接。上述Hexmate命令执行过程如下:

使用hexmate修改配置字中读保护位

hexmate ${ImagePath} -find=0xFFFFBD@0xBE00:0xBE03,replace=0xFFFFFF -o${ImagePath}
在MPLAB X IDE中使能读保护
查看编译后生成的hex文件内容,可以发现0x5F00(对应字节地址0xBE00-0xBE03)处的内容正好是我们代码中设置的内容。

将编译生成的hex文件放置于hexmate工具同一目录下,如果hexmate路径已经添加到环境变量中了就不用这么麻烦了。

使用以下hexmate命令将原本配置字地址0x5F00(字对齐地址)处4个字节的内容替换为0xFFFFFF,这样可以禁用读保护功能了。
hexmate ./crc32_flash.X.production.hex -find=FFFFBD@BE00-BE03,replace=0xFFFFFF -o./crc32_flash.X.production.hex
使用FF FF FF 00按照字节填充,因为dsPIC的flash单元大小有效空间为24bits用3个FF填充,而最高8bits一直是0x00,这个是芯片设计时就固定的。芯片Flash擦除后就是全FF,3个FF说明这是芯片擦除的默认值。
因为Flash的有效存储空间只有3个字节其最高1个字节全为0,所以此处的配置字只有24bits。
运行上述hexmate命令后,再查的相应的hex文件,可以发现0x5F00(字节地址:0xBE00-0xBE03)处4个字节的内容被替换为0x00FFFFFF

PIC16系列单片机地址说明

PIC16F1717手册中的Flash地址是按照字对齐的,8192 = 0x2000对应的地址范围为0x0000-0x1FFF。

PIC18系列单片机地址说明

从PIC18F47Q84的数据手册Memory Map图中可知其地址是按字节对齐的。64KW = 64 * 1024 *2 = 131,072 = 0x20000,地址范围为:0x00000-0x1FFFF。

在MPLAB X IDE的Program Memory窗口中显示的地址也是按字节对齐的。 

AVR系列单片机地址说明

AVR的Flash也是按照字对齐的,128KByte大小的Flash存储器地址范围:0x0000-0xFFFF。

如何将常量链接到特定的Flash地址?
使用address链接属性可以将相应的变量或者常量链接到RAM或者Flash相应地址处。如下所示将0-15的常量数据链接到0x1800的Flash地址处。
static __prog__ uint8_t flashTestPage[15*2] __attribute__((space(prog), aligned(15*2), address(0x18800))) = {    0123456789101112131415};
MCC工具中设置IOL1WAY配置寄存器
切换到Register窗口才能查看所有寄存器的设置
注“汤圆说电子”回复关键字:CRC32-Flash获取提取码

链接: https://pan.baidu.com/s/19FgFxgPVpVVQBpS1LRIRVw