4
\$\begingroup\$

I am working on a firmware project in which i have to do a crc16 check for flash integrity.

Controller: MSP430 IDE: IAR EW 5.40 (Linker Xlink)

The crc is calculated using IAR Xlink linker and kept at the end of the flash. Again crc is calculated at run time from the code and compared with the stored value in the flash to check integrity. However, we can only calculate crc on the code segment of the flash memory. It's size may change whenever we make some changes in the code. Can i automate this process which i am manually doing right now?

from the .xcl linker file:

// ---------------------------------------------------------
// CRC16 Essentials: -H for fill,-J for checksum calculation
// ---------------------------------------------------------

-HFF         

-J2,crc16,,,CHECKSUM2,2=(CODE)5C00-FF7F;(CODE)10000-0x20A13

Here i need to change the end value of second code segment which is 0x20A13 right now. I get this value from the .map file, i.e on how much memory range my code is residing inside the flash. This is the 1st change i make.

Here i need to make 2nd change from code:

sum = fast_crc16(sum, 0x5C00, 0xFF7F-0x5C00+1);

  sum = fast_crc16(sum, 0x10000,0x20A13-0x10000+1); 

  //Check the crc16 values 
   if(sum != __checksum)
   {
    // Action to be taken if checksum doesn't match
   }

Please help automating this process!!

\$\endgroup\$
3
\$\begingroup\$

In don't know your linker, but the gcc linker can PROVIDE a label, which address can be used in the code. This feature is commonly used to inform the startupcode about the start and end of the DATA and BSS segments, so the BSS can be cleared and the DATA (in RAM) can be intialized from is copy in ROM.

Fragment from an (LPC1343) linkerscript I use:

.text :
{
    . = ALIGN(4);
    __text_start = .;
    PROVIDE(__text_start = __text_start);

            // all text segments are listed here

    . = ALIGN(4);
    __text_end = .;
    PROVIDE(__text_end = __text_end);
} > rom 

The label __text_end will be at the address beyond the text. It can be used in the code for the CRC calculation.

Two remarks:

  • You say you check the code segment. Do you check the DATA segment (initialised global values) too?

  • If this task was put onto me I would consider to arrange things that the unused flash locations are filled with a known value, and arrange the checksumn over the total flash.

\$\endgroup\$
  • \$\begingroup\$ We can define labels for certain segments in the linker and use them in code, but that is useful when address ranges are fixed. I was actually finding if there was any way that would reflect the changes in the code address range other than the map file so as to avoid manually editing linker file. \$\endgroup\$ – OnkarK Aug 27 '12 at 9:08
  • \$\begingroup\$ You can pass a value that is determined by the linker (in your case: the end of the code segment) 'back' to the code as a label. See fragment in my updated answer. \$\endgroup\$ – Wouter van Ooijen Aug 27 '12 at 10:20
  • \$\begingroup\$ 1. Data segment is not being checked. 2. -HFF linker command is to fill unused flash with 0xFF. Calculating checksum over entire flash is working well but its taking some extra time. Over 1 sec :( Unacceptable. \$\endgroup\$ – OnkarK Aug 27 '12 at 13:30
  • \$\begingroup\$ Why not check the data segment? I would think the initial values of global variables are as important as the code! \$\endgroup\$ – Wouter van Ooijen Sep 1 '12 at 19:40
2
\$\begingroup\$

I'm using EW8051, but it also uses Xlink. There are two sizes to keep in mind: one is the size of the CODE segment, which you generally won't change; and the other is the size that your code takes up, which will vary (usually growing) as you update your program and compile link.

For example, here from my linker .xcl file you can see the size of the CODE segment is 0x8000:

/
//    CODE
//    ----
-D_CODE0_START=0x000000
-D_CODE0_END=0x007FFF         // CC1111F32 has 32 kB code (flash)

However the portion of that actually used by my code is listed in the .map file:

30 739 bytes of CODE  memory

Looking at the checksum calculation section of the IAR Linker and Library Tools Reference Guide, it appears that you would normally instruct the linker to calculate the checksum over the entire CODE segment (all 0x8000 bytes in my case). This is the example code they provide:

Calculating a checksum in your source code
This source code gives an example of how the checksum can be calculated:
/* Start and end of the checksum range */
/* Must exclude the checksum itself */
unsigned long ChecksumStart = 0x8000+2;
unsigned long ChecksumEnd = 0x8FFF;

/* The checksum calculated by XLINK */
extern unsigned short __checksum;

void TestChecksum()
{
    unsigned short calc = 0;
    /* Run the checksum algorithm */
    calc = slow_crc16(0,
                      (unsigned char *) ChecksumStart,
                      (ChecksumEnd - ChecksumStart+1));
    /* Rotate out the answer */
    unsigned char zeros[2] = {0, 0};
    calc = slow_crc16(calc, zeros, 2);

   /* Test the checksum */
   if (calc != __checksum)
   {
       abort(); /* Failure */
    }
}

The start and end addresses strongly suggest to me that the checksum is to be calculated over the entire segment.

In documenting the -J flag, the reference states "Note: If you do not specify any ranges explicitly, all bytes in the final application are included in the calculation." I admit there is some ambiguity in what "all bytes" means -- the entire CODE segment, or just the used portion.

Of course the only way this scheme can work would be if any unused bytes in the CODE segment are zero-initialized. You should verify this. :^)

In summary: use the -J flag to checksum the entire CODE segment, do the same in your code, and see if that works (after verifying with the debugger, e.g., that the unused portion of the CODE segmentment isn't filled with garbage).

\$\endgroup\$
  • \$\begingroup\$ -H flag is used for the fill. It fills the unused code segment portion with 0xFF, so the checksum works for entire flash. This also has an overhead of increased calculation time. I just wanted to know if we can autimatically set the ranges. \$\endgroup\$ – OnkarK Aug 27 '12 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.