前言
项目需要在IAR生成固件时自动生成校验码。网上的一些笔记不详细,所以总结一些经验分享。
参考文章
IAR设置
链接脚本
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08010000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08010000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0807FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x2001FFFF;
define symbol __ICFEDIT_region_CCMRAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_CCMRAM_end__ = 0x1000FFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x800;
define symbol __ICFEDIT_size_heap__ = 0x400;
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
define region CCMRAM_region = mem:[from __ICFEDIT_region_CCMRAM_start__ to __ICFEDIT_region_CCMRAM_end__];
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
initialize by copy { readwrite };
do not initialize { section .noinit };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place at end of ROM_region { readonly section .checksum };
place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block HEAP };
关键是加入place at end of ROM_region { readonly section .checksum };
编译验证
获取编译出来Bin文件的存储的Checksum。
$ xxd -s 0x0006FFFC -o 0x08010000 FirmwareForCrc16Test.bin
0807fffc: ffff a4c4 ...
其中0x0006FFFC = ( 0x0807FFFB - 0x08010000 ) + 1
。因为STM32是小端对齐,所以Checksum是0xC4A4.
C代码验证,读者可通过链接crc16_helper.zip下载代码测试。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "Checksum.c"
#define SIZE_MAX_SRC_FILE ( 10 * 1024 * 1024 )
typedef union
{
uint8_t ucContent[ SIZE_MAX_SRC_FILE ];
uint32_t ulContent[ SIZE_MAX_SRC_FILE / 4 ];
} Firmware_t;
static size_t ulGetFileContent( char *pucFile, uint8_t *pucContent )
{
size_t ulNum;
FILE *fIn;
fIn = fopen( pucFile, "rb" );
if ( fIn == NULL )
{
printf( "fopen %s failed( %s )!\n", pucFile, strerror( errno ) );
return -1;
}
ulNum = fread( pucContent,
sizeof( uint8_t ),
SIZE_MAX_SRC_FILE,
fIn
);
fclose( fIn );
return ulNum;
}
static Firmware_t xFirmeware = { .ucContent = { 0 } };
const int zero=0;
int main( int argc, char *argv[] )
{
uint32_t ulStartAddress = 0x08010000;
uint32_t ulEndAddress = 0x0807FFFB;
uint32_t ulIndex = 0;
size_t ulNum;
unsigned short sum=0;
// printf( "argv[ 1 ] : %s\n", argv[ 1 ] );
ulNum = ulGetFileContent( argv[ 1 ], &( xFirmeware.ucContent[ 0 ] ) );
if ( ulNum != ( ( ulEndAddress - ulStartAddress ) + 1 + 4 ) )
{
printf( "ulNum = %d\n", ulNum );
printf( "( ( ulEndAddress - ulStartAddress ) + 1 + 4 ) = %d\n",
( ( ulEndAddress - ulStartAddress ) + 1 + 4 )
);
return -1;
}
sum = 0;
sum = fast_crc16( sum,
(unsigned char *)&xFirmeware.ucContent[ ulIndex ],
ulNum - 4
);
printf( "fast sum = %04x\n", sum );
sum = 0;
sum = slow_crc16( sum,
(unsigned char *)&xFirmeware.ucContent[ ulIndex ],
ulNum - 4
);
sum = slow_crc16(sum,(unsigned char *)&zero, 2);
printf( "slow sum = %04x\n", sum );
sum = 0;
sum = sum | xFirmeware.ucContent[ ( ulEndAddress - ulStartAddress ) + 4 ];
sum = sum << 8;
sum = sum | xFirmeware.ucContent[ ( ulEndAddress - ulStartAddress ) + 3 ];
printf( "want sum = %04x\n", sum );
return 0;
}
$ gcc -static crc16_helper.c -o crc16_helper.exe
$ ./crc16_helper.exe FirmwareForCrc16Test.bin
fast sum = c4a4
slow sum = c4a4
want sum = c4a4