2014-01-15 12:14 PM
Hello,
I know this has been discussed before, but reading through it all, I am still unable to grasp the solution of my problem: What I am trying to do is check the integrity of the flash (code) on the STM32L1xx chip at startup. Since I need to calculate the CRC only at startup, I have decided not to use the built in CRC peripheral (mostly because of the 4 bytes step). So instead I used 1 byte step CRC with lookup table using the same polynomial (reversed actually, i.e. 0xEDB88320) to calculate the CRC of the .hex file. Now, I am trying to insert the calculated CRC in the .hex file to upload it to stm32 and perform the check. My questions are: 1.) How can I insert the CRC to a specific address, so that I will be able to access the same address via the code/function in the program? Can I do it simply in a hex editor? 2.) The flash address (default) begins at 0x08000000 and ends at 0x0801FFFF. My code is shorter. How can I calculate the CRC only for the code portion and not the entire flash at runtime? If I calculate the CRC for the entire flash it would be different right? I was thinking about moving the flash start address for 4 bytes forward and write the CRC in the blank spot, so the address would be known. Any suggestions please? Thank you and best regards, K #i-accept-paypal2014-01-17 09:42 AM
Hello Mr. sung.chen_chung,
So step 1: I am using Keil, which outputs a .hex but can be configured post build to output .bin also (using fromelf). Step 2: For validation I would preferably like to use the STM32's inbuilt CRC calculation. I have configured the CRC peripheral and also wrote a custom function which calculates the CRC in the same way. I've tested the outputs of both on the same data (entire ROM) and the output was the same. Step 3, 4, 5 -> here is where my problem lies. It seems I do not know how to properly calculate the CRC for the .bin image and inject it to the end of the image. @ Mr.clive1: So if I calculate the CRC of the entire ROM minus 4 bytes and append the calculated 4 byte CRC at the end, and then use the same CRC algorithm on the entire ROM, the result will not be zero? Guess that was my first fundamental mistake... The algorithm you provided should give the same output as the one I attached in the last post (minus the last 4 bytes), right? Again, my main problem is I do not know how to properly fill the entire ROM, i.e. the .hex/.bin file (minus the last 4 bytes), calculate the CRC and append it to the end. It seems strange to me that there is so little information regarding this on the internet. The document of the STM32 states that the CRC is used for flash integrity check, but there are no examples or guidelines how to do this. As I have read, IAR has this integrated in the SW. I would just need some standard procedure on how to verify the flash integrity using the CRC peripheral. Thank you for your help and best regards, K2014-01-17 10:05 AM
Hi
''So step 1: I am using Keil, which outputs a .hex but can be configured post build to output .bin also (using fromelf).'' Good ''Step 2: '' By Step 2 - I meant you have to chose a method, the STM32's inbuilt CRC calculation, whether to calculate just the binary or he whole Flash space - 4bytes Set 3 - sounds like you are already calculating something - just on the wrong thing. Now that you have figure out how to get the raw binary, you should be able to check the code/HW works. (Assuming you do it just for the binary length) Do it manually first with the debugger. Before you download and debug, take a note of the binary length (from .map file or somewhere from Keil). In the debugger, put a break point somewhere convient, say at a call to the calculation. Manually change the start address and then length (to what you noted down). The output should be the same from the debugger as for your calc on the binary. If not - then something is wrong. Step 4 Where to store the calc value? Step 5 Getting the compiler/linker to do the work for you. Let cover step 4 & 5 after you have got 1-3 working. By the way this link (although not about this problem) has example on how to add a tag/location into the linker file: http://www.atollic.com/index.php/kb/1-kb_building/29-kb_float_sprintf2014-01-17 11:53 AM
Posted on January 17, 2014 at 20:53
If you want to use the on-board CRC, you have to use that polynomial, shift direction and data alignment.
________________
Attachments :
//****************************************************************************
//
// STM32ROM - CRC32 Computation on the ST Micro STM32 binary ROM image
// Copyright (C) 2014, All rights reserved
//
// sourcer32@gmail.com
//
//****************************************************************************
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
//****************************************************************************
uint32_t Crc32(uint32_t Crc, uint32_t Data)
{
int i;
Crc = Crc ^ Data;
for(i=0; i<32; i++)
if (Crc & 0x80000000)
Crc = (Crc << 1) ^ 0x04C11DB7; // Polynomial used in STM32
else
Crc = (Crc << 1);
return(Crc);
}
//****************************************************************************
uint32_t Crc32Fast(uint32_t Crc, uint32_t Data)
{
static const uint32_t CrcTable[16] = { // Nibble lookup table for 0x04C11DB7 polynomial
0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,
0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD };
Crc = Crc ^ Data; // Apply all 32-bits
// Process 32-bits, 4 at a time, or 8 rounds
Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // Assumes 32-bit reg, masking index to 4-bits
Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // 0x04C11DB7 Polynomial used in STM32
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
return(Crc);
}
//****************************************************************************
uint32_t Crc32FastBlock(uint32_t Crc, uint32_t Size, uint32_t *Data)
{
while(Size--)
Crc = Crc32Fast(Crc, *Data++); // 32-bit at a time
return(Crc);
}
//****************************************************************************
#define ROMSIZE 0x40000
int main(int argc, char **argv)
{
FILE *f;
char *fnameout;
uint32_t Size;
uint8_t *Buffer;
uint32_t Crc;
uint32_t i;
printf( "STM32ROM - Copyright (C) 2014, All rights reserved, sourcer32@gmail.com\n"
"CRC32 Computation on the ST Micro STM32 binary ROM image\n\n");
if (argc < 2)
{
fprintf(stderr, "USAGE: stm32rom <input .BIN> [<output .BIN>]\n");
return(1);
}
// Read input binary image
f = fopen(argv[1],"rb");
if (f)
{
fseek(f, 0, SEEK_END);
Size = ftell(f);
fseek(f, 0, SEEK_SET);
Buffer = malloc(max(Size, ROMSIZE));
if (!Buffer)
{
fprintf(stderr, "ERROR: Memory allocation failed\n");
return(1);
}
memset(Buffer, 0xFF, ROMSIZE); // Define Fill Pattern
fread(Buffer, Size, 1, f);
fclose(f);
printf("Compiled for ROMSIZE of %d\n", ROMSIZE);
if (Size > ROMSIZE)
fprintf(stderr, "WARNING: Size of Image (%d) exceeds ROMSIZE\n", Size);
Crc = *((uint32_t *)&Buffer[ROMSIZE - sizeof(uint32_t)]);
printf("%08X Current CRC in File\n", Crc);
Crc = Crc32FastBlock(0xFFFFFFFF, (ROMSIZE - sizeof(uint32_t))/sizeof(uint32_t), (void *)Buffer);
*((uint32_t *)&Buffer[ROMSIZE - sizeof(uint32_t)]) = Crc;
printf("%08X Computed CRC for File\n", Crc);
Crc = Crc32FastBlock(0xFFFFFFFF, ROMSIZE/sizeof(uint32_t), (void *)Buffer);
printf("%08X Computed CRC across image, should be zero\n", Crc);
// Write out new binary image
if (argc > 2)
fnameout = argv[2];
else
fnameout = "OUT.BIN";
f = fopen(fnameout,"wb");
if (f)
{
fwrite(Buffer, ROMSIZE, 1, f);
fclose(f);
}
else
{
fprintf(stderr, "ERROR: Unable to open '%s'\n", fnameout);
return(1);
}
}
else
{
fprintf(stderr, "ERROR: Unable to open '%s'\n", argv[1]);
return(1);
}
return(0);
}
//****************************************************************************
#ifdef STM32_SIDE_IMPLEMENTATION
uint32_t CrcRom(void)
{
uint32_t Crc;
uint32_t *Buffer = (uint32_t *)0x08000000;
uint32_t Size = ROMSIZE / sizeof(uint32_t);
// Enable the CRC peripheral clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
// Reset the CRC data register (initial value 0xFFFFFFFF)
CRC_ResetDR();
// Calculate CRC32 for the entire flash block
while(Size--)
CRC->DR = *Buffer++;
// Final CRC32 should resolved to ZERO
Crc = CRC->DR;
// Disable the CRC peripheral clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, DISABLE);
return(Crc);
}
#endif
//****************************************************************************
2014-01-17 03:33 PM
Dear Mr.Clive,
I cannot thank you enough for your help. The most ironic thing is that I had the correct code for the file calculation a few posts back (and yes, the code was written in less than 2 hours), but since I have not been listening to you I have been calculating the CRC for the .hex file instead of the .bin. The code below (C++) produces the same file and CRC output as the one you so unselfishly shared:// STM32_CRC32_fileCalculation.cpp : Defines the entry point for the console application.
#include <
iostream
>
#include <
fstream
>
#include <
string
>
#include <
iomanip
>
using namespace std;
#define uint32_t unsigned int
#define uint8_t unsigned char
uint32_t CRCvalue;
// Functions prototype declaration
uint32_t STM_crc_32_update(uint32_t crc, uint32_t data);
int main() {
// Type used for buffer and file positioning
streampos fileSize_original;
streampos fileSize_new = 0x00040000 - 4; // THIS IS THE SIZE OF THE ENTIRE FLASH MINUS THE 4 BYTES FOR THE CRC32
streampos fileSize_new_CRC = 0x00040000; // THIS IS THE SIZE OF THE ENTIRE FLASH
// The size of the output file
streampos fileSize_output;
// Pointer to char for address where the data is stored
uint8_t *data;
// Input full file path
string filePath;
cout << ''Enter full file path of .bin file (without extension):'' <<
endl
;
getline(cin,filePath);
filePath
= filePath + ''.bin'';
cout << endl << endl;
// Open file for input/output operations and set the flag position to the file end (also specify binary to keep the data stream as it is)
fstream file(filePath,ios::in|ios::out|ios::ate|ios::binary);
// Check if file opened successfully
if(file.is_open()) {
// Get file size (get position)
fileSize_original
= file.tellg();
// Allocate memory to hold the file the entire data (with padding)
data
=
new
uint8_t[fileSize_new_CRC];
// Set the flag position to the beginning
file.seekg(0,ios::beg);
// Read the file to data memory block
file.read((char*) data,fileSize_original);
// Initialize the rest of the data (minus the CRC location) to a known character -> PAD WITH SPACE!!!
for(int i=fileSize_original;i<fileSize_new;i++) {
data[i] = 0xFF;
}
// Calculate the CRC (STM32 version) with initialization 0xFFFFFFFF
CRCvalue = 0xFFFFFFFF;
// Pointer to data to process 4 bytes at a time
uint32_t *pD = (uint32_t*) &data[0];
for(int i=0;i<fileSize_new/4;i++,pD++) {
CRCvalue = STM_crc_32_update(CRCvalue,*pD);
}
// Write the calculated CRC to the end of the file (4 additional bytes)
uint8_t *pCRC = (uint8_t*) &CRCvalue;
for(int i=fileSize_new;i<fileSize_new_CRC;i++,pCRC++) {
data[i] = (*pCRC);
}
// Set the flag position to the beginning
file.seekg(0,ios::beg);
// Write the entire data block to the file
file.write((char*) data,fileSize_new_CRC);
// Set the flag position to the end
file.seekg(0,ios::end);
// Determine final size
fileSize_output = file.tellg();
// Close the file
file.close();
// Delete the memory block
delete[] data;
// Output file size and CRC (check if the length is correct)
if(fileSize_output == fileSize_new_CRC) {
cout << ''File size in Bytes: '' << fileSize_output << '' OK!'' << endl;
cout << ''CRC value (hex): '' << hex << uppercase << setw(8) << setfill('0') << CRCvalue << endl << endl;
cout << ''Press any key to exit...'' << endl << endl;
}
else cout << ''File size incorrect!'' << endl << ''Press any key to exit...'' << endl << endl;
}
// If file not opened successfully
else {
cout << ''Error, file not opened!'' << endl;
cout << ''Press any key to exit...'' << endl << endl;
}
cin.get();
return 0;
}
// CRC32 calculation compatibe with the STM32 HW peripheral
uint32_t STM_crc_32_update(uint32_t crc, uint32_t data)
{
crc = crc ^ data;
for(uint32_t i=0;i<32;i++)
if (crc & 0x80000000)
crc = (crc << 1) ^ 0x04C11DB7;
else
crc = (crc << 1);
return(crc);
}
I will try this first thing on Monday, when I will have access to the STM chip. I will get back to you.
Anyway, could you please elaborate how does this paypal stuff work? :)
Thank you and best regards,
K
2014-01-20 03:49 AM
Hello,
I have finally manged to get the flash CRC check working using the CRC peripheral on the STM32 chip. The procedure is actually very simple, but it took me 5 days (and a lot of help from clive1 and also sung.chen_chung) to figure it out. Mostly because of misunderstanding the concept... So, I am posting the code (SW) for calculating the CRC of the input .axf file (actually its .bin and .hex, but the SW does the conversions automatically), producing the output .hex file that can be directly uploaded to the flash. See:http://www.keil.com/support/man/docs/uv4/uv4_fl_hexdownload.htm
on how to upload the final .hex file to the chip. And the code written in C++ (with comments and all prerequisites):/************************************************************************************************************
SW WRITTEN BY KP
(FROMELF -> KEIL INSTALLATION)
(BIN2HEX -> http://www.keil.com/download/docs/asp (1.2014)
*************************************************************************************************************/
/* INPUTING THE .AXF FILE, THE PROGRAM CONVERTS IT TO .BIN FILE (FROMELF), PADS THE DATA (0xFF) TO MATCH THE
FLASH SIZE OF THE STM32L1xx MEDIUM DENSITY DEVICES (256 kB), APPENDS THE CALCULATED CRC (CRC IS CALCULATED ON THE
ENTIRE FILE SIZE minus 4 BYTES) OF THE FILE AT THE LOCATION OF LAST FOUR BYTES AND CONVERTS THE FILE BACK
TO .HEX (BIN2HEX) FOR UPLOADING TO THE CHIP. THE RESULT OF THE CRC CHECK MUST BE ZERO */
/* CHECK THE LOCATION OF THE FROMELF.EXE (LINE 56)
BIN2HEX.EXE HAS TO BE IN THE SAME PLACE AS THE .EXE OF THE SW */
/* COMPATIBLE WITH STM32 HW CRC CALCULATION -> CALCULATE THE CRC ON THE ENTIRE FLASH. THE RESULT MUST BE ZERO */
// INCLUDES
#include <
iostream
>
#include <
fstream
>
#include <
string
>
#include <
iomanip
>
#include <
Windows.h
>
using namespace std;
// DEFINITIONS
#define uint32_t unsigned int
#define uint8_t unsigned char
// Global variables
uint32_t CRCvalue, CRCvalue_check;
// Functions prototype declaration
uint32_t STM_crc_32_update(uint32_t crc, uint32_t data);
int main() {
// Type used for buffer and file positioning
streampos fileSize_original;
streampos fileSize_new = 0x00040000 - 4; // THIS IS THE SIZE OF THE ENTIRE FLASH MINUS THE 4 BYTES FOR THE CRC32
streampos fileSize_new_CRC = 0x00040000; // THIS IS THE SIZE OF THE ENTIRE FLASH
// The size of the output file
streampos fileSize_output;
// Pointer to char for address where the data is stored
uint8_t *data;
// Input the name of the .axf file
string filePath;
cout << ''Enter the name of the .axf file (without extension):'' <<
endl
;
getline(cin,filePath);
cout << endl;
// Convert to .bin using fromelf (integrated into Keil) in cmd
string
command_in
=
''C:\\Keil\\ARM\\ARMCC\\bin\\fromelf.exe --bin ''
+ filePath + ''.axf'' + '' --output '' + ''tmp1.bin'';
// char pointer to the string beggining
char *pC = (char*) &command_in[0];
// Execute cmd command
system(pC);
// Open .bin file for reading operations and set the flag position to the file end (also specify binary to keep the data stream as it is)
fstream file_in(''tmp1.bin'',ios::in|ios::ate|ios::binary);
// Check if file opened successfully
if(file_in.is_open()) {
// Get file size
fileSize_original
=
file_in
.tellg();
// Check if the file size exceedes the ROM size
if(fileSize_original > fileSize_new_CRC) {
cout << ''Size of image '' << fileSize_original << '' bytes exceeds ROM size '' << fileSize_new_CRC << '' bytes!'' << endl;
cout << ''Press any key to exit...'';
cin.get();
return -1;
}
// Allocate memory to hold the file the entire data (with padding and CRC)
data = new uint8_t[fileSize_new_CRC];
// Initialize the data (minus the CRC location) to a known value
for(int i=0;i<fileSize_new_CRC;i++) {
data[i] = 0xFF;
}
// Set the flag position to the beginning
file_in.seekg(0,ios::beg);
// Read the file to data memory block
file_in.read((char*) data,fileSize_original);
// Calculate the CRC (STM32 version) with initialization 0xFFFFFFFF
CRCvalue = 0xFFFFFFFF;
// Pointer to data to process 4 bytes at a time
uint32_t *pD = (uint32_t*) &data[0];
for(int i=0;i<fileSize_new/4;i++,pD++) {
CRCvalue = STM_crc_32_update(CRCvalue,*pD);
}
// Write the calculated CRC to the last 4 bytes of the file
uint8_t *pCRC = (uint8_t*) &CRCvalue;
for(int i=fileSize_new;i<fileSize_new_CRC;i++,pCRC++) {
data[i] = (*pCRC);
}
// Close the file
file_in.close();
// Output the new temporary .bin file
// Open file for writing operations (also specify binary to keep the data stream as it is)
fstream file_out(''tmp2.bin'',ios::out|ios::binary);
if(file_out.is_open()) {
// Calculate the new CRC, which must be equal to zero
CRCvalue_check = 0xFFFFFFFF;
// Pointer to data to process 4 bytes at a time
pD = (uint32_t*) &data[0];
// Calculate CRC of the entire data (must be zero)
for(int i=0;i<fileSize_new_CRC/4;i++,pD++) {
CRCvalue_check = STM_crc_32_update(CRCvalue_check,*pD);
}
// If CRC check fails
if(CRCvalue_check != 0) {
// Delete the memory block
delete[] data;
cout << ''Error, CRC not equal to 0: '' << CRCvalue_check << endl;
cout << ''Press any key to exit...'';
cin.get();
return -1;
}
// Set the flag position to the beginning
file_out.seekg(0,ios::beg);
// Write the entire data block to the output file
file_out.write((char*) data,fileSize_new_CRC);
// Set the flag position to the end
file_out.seekg(0,ios::end);
// Get file size of the output file
fileSize_output = file_out.tellg();
// Close the file
file_out.close();
}
else cout << ''Error, output file not written!'' << endl;
// Delete the memory block
delete[] data;
// Everything calculated OK!
cout << ''File size in Bytes: '' << fileSize_output << endl;
cout << ''CRC value (hex): '' << hex << uppercase << setw(8) << setfill('0') << CRCvalue << endl;
cout << ''CRC value check (hex): '' << hex << uppercase << setw(8) << setfill('0') << CRCvalue_check << endl << endl;
cout << ''Press any key to generate the final intel .hex file...'';
cin.get();
// Generate final intel hex386 file to upload to STM32
string command_out = ''BIN2HEX tmp2.bin /4 /O0x08000000 FLASH.hex'';
pC = (char*) &command_out[0];
system(pC);
cout << endl << endl;
cout << ''New file written to: FLASH.hex'' << endl << endl;
// Delete the unneeded files
remove(''tmp1.bin'');
remove(''tmp2.bin'');
cout << ''DONE! Press any key to exit...'';
cin.get();
return 0;
}
// If file not opened successfully
else {
cout << ''Error, input file not opened!'' << endl << endl;
cout << ''Press any key to exit...'';
cin.get();
return -1;
}
}
// CRC32 calculation compatible with the STM32 HW peripheral
uint32_t STM_crc_32_update(uint32_t crc, uint32_t data)
{
crc = crc ^ data;
for(uint32_t i=0;i<32;i++)
if (crc & 0x80000000)
crc = (crc << 1) ^ 0x04C11DB7;
else
crc = (crc << 1);
return(crc);
}
The STM32's side of the corresponding CRC implementation over the entire flash is posted a couple of posts above.
I am sharing this in hope that it helps someone without the frustration I had to endure.
Best regards,
K