CRC integrity check of ARM Cortex flash memory

The program and data contained in a micro controller flash memory can become corrupted over time. The integrity can be verified by running a CRC test over the flash. This post describes how to automatically add the correct CRC to a binary file and later let the micro controller perform the check.This has been tested on an stm32f103 device, but should work on all controllers in this series. Other makers of Cortex M3 devices also often include a CRC unit in their devices, but I do not know if this procedure applies to those.

The stm32f CRC unit has a 32 bit interface register, that is, it’s fed a full word at a time. The unit therefore only works for data buffers that are a multiple of four long. This is the case for program and data saved in the flash if properly 4-byte aligned by the linker. But I cannot see how this hardware can be used to check buffers of arbitrary length, e.g. communication messages, if not both the sender and receiver use a common padding pattern to ensure 4-byte alignment while calculating the CRC. I think the CRC module is primarily implemented for flash integrity verification, as mandated by the IEC60730 safety standard for household appliances, see e.g. Using IEC 60730 for Safe and Reliable Operation of Stellaris Devices (AN01272).

Another problem with the CRC unit is the byte order. CRC is usually calculated over a linear byte sequence, but this unit uses a linear word sequence where the most significant byte of the word is consumed first. The Cortex M3 processor is little endian, so this makes the effective byte sequence to be  3,2,1,0,7,6,5,4,…, different from the usual 0,1,2,3,4,5,6,7.

Two stages are involved with the flash memory CRC check:

  1. Calculate the CRC of the binary file to be flashed and append this CRC to the file
  2. Verify the flash during the micro controller startup or periodically during operation

Calculate the CRC

The flash image file length must be a multiple of 4 for this to work, this is the responsibility of the linker script.

A project make file often specifies an elf output file which in addition to the flash image also holds information used by the debugger. The flashing program can use this elf file, but may as well use only the clean binary image file. The image file is produced by this makefile rule, which also appends the CRC

flashprg.bin:flashprg.elf
        $(OBJCOPY)  flashprg.elf -O binary flashprg.bin
        cortex_crc flashprg.bin

OBJCOPY will likely be set to something like arm-none-eabi-objdump.

cortex_crc is a program which reads in the given file, calculates the CRC and appends the CRC to the file. cortex_crc is a standard CRC-calculation program, but with a small modification.

for (idx=0; idx < len; idx++) {
        bp = src  + (idx^0x3);
        crc = ( crc << 8 ) ^ crctab[ ( ( crc >> 24 ) ^ *bp ) & 0xFF ];
}

Instead of going through the buffer in a linear sequence, the XOR operation inverts the two least significant bits of idx to produce the wanted sequence 3,2,1,0,7,6,5,4,11,10,9,8 … In this way cortex_crc calculates the CRC in the same way as the cortex processor. You may download the source code for cortex_crc.

Verify the flash

The linker file must define some global labels that enables the micro controller to find the end of the image.  This snippet from the ST library  STM32_SEC_FLASH.ld illustrates this

.isr_vector :
{
        . = ALIGN(4);
        KEEP(*(.isr_vector))   
        . = ALIGN(4);
} >FLASH
.text :
{
        . = ALIGN(4);
        *(.text)                   
        *(.text.*)                  
        *(.rodata)                
        *(.rodata*)
        *(.glue_7)
        *(.glue_7t)
        . = ALIGN(4);
        _etext = .;
        _sidata = _etext;
} >FLASH
.data  : AT ( _sidata )
{
        . = ALIGN(4);
        _sdata = . ;
        *(.data)
        *(.data.*)
        . = ALIGN(4);
        _edata = . ;
} >RAM

Observe that all segments are 4-byte aligned at the beginning and end. Three segments are defined here: .isr_vector, .text and .data. The program code resides in the .isr_vector and .text segments, initialized variables in .data, all three segments are stored in the flash. The length of the flash image is given by the address of the  end of the program labeled _etext plus the length of the initialized variables range given by the difference of the  _edata and _sdata label addresses. These three labels are used by the micro controller to find what part of the flash to check. The  names of these labels may vary between linker scripts and you may provide your own if you wish. A pointer to such a label is found by using the & operator. Here is a flash check procedure example:

extern uint32_t _edata[], _etext[], _sdata[];
uint32_t CheckCrc32(void)
{
        uint32_t end;
        uint32_t crc;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
        /* end is what the linker thinks is the end of the image. 
            We later add one word to include the crc. */
        end= (uint32_t)((uint32_t)&_etext + (uint32_t)&_edata - 
                (uint32_t)&_sdata);
        CRC_ResetDR();
        crc= CRC_CalcBlockCRC((uint32_t*)0, end/4+1);
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, DISABLE);
        return crc ;
}

This function calculates the end of the image and feeds the CRC unit with words starting at address 0 and ending at the CRC address. By including the CRC in the calculation the returned value is zero if and only if the flash is correct. RCC_AHBPeriphClockCmd enables and disables the clock for the CRC unit.

0 Responses to “CRC integrity check of ARM Cortex flash memory”


Comments are currently closed.