Verifying program content

I would like to write a routine to verify the program content. This is to ensure that when the Arduino starts, there has been no corruption. The eventual purpose of the board is to check something, so I would like to know that the board is loaded correctly.

Would this fragment work, assuming that I have a crc16 routine?
and how could I find TOP_OF_PROG, apart from looking at the .hex file?

byte *bp = 0;
crc16.init();
while (bp <= TOP_OF_PROG)
{
crc16.next(*bp);
bp ++;
}
int v = crc16.value();
Serial.println("crc"); Serial.println(v, HEX);

First, note that the AVR-LIBC libraries already have CRC calculation routines available. Not that there's anything wrong with yours, but in case you don't want to reinvent the wheel:

http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html

You can get the last address used in FLASH by your program as the special linker label '_etext':

extern unsigned _etext;
#define TOP_OF_PROG ((byte *)&_etext)

Then you can use your code as usual.

--
The Quick Shield: breakout all 28 pins to quick-connect terminals

Thanks for the link for the CRC. I've modified a routine I found, because I want to calculate the next CRC element for each character read it - because I am calling the CRC next element repeatedly in my main loop. All the examples do a complete CRC on a buffer.

The _etext thing seems to work, thank you. The crc changes if I change even one byte of the program. All I have to do now
is take the hex file, and see if that is actually the same as the
calculated crc to verify it!

/**************************************************************************
//
// crc16.c - generate a ccitt 16 bit cyclic redundancy check (crc)
/
//      The code in this module generates the crc for a block of data.
//
**************************************************************************/
/*
//                                16  12  5
// The CCITT CRC 16 polynomial is X + X + X + 1.
// In binary, this is the bit pattern 1 0001 0000 0010 0001, and in hex it
//  is 0x11021.
// A 17 bit register is simulated by testing the MSB before shifting
//  the data, which affords us the luxury of specifiy the polynomial as a
//  16 bit value, 0x1021.
// Due to the way in which we process the CRC, the bits of the polynomial
//  are stored in reverse order. This makes the polynomial 0x8408.
*/

/* RH: modified original routine to a class called one char at a time */

#define POLY 0x8408

/*
// note: when the crc is included in the message, the valid crc is:
//      0xF0B8, before the complement and byte swap,
//      0x0F47, after complement, before the byte swap,
//      0x470F, after the complement and the byte swap.
*/

  
  class calc_crc16 {
  private:
  unsigned int data;
  unsigned int crc;
  
  public:
  const static short crc_ok = 0X470F;

  calc_crc16() : crc ( 0XFFFF) 
  {
    
  } 
  
  void reset()
  {
        crc = 0XFFFF;
  }

  void next (char dval)
  {
    int i;
                  for (i = 0, data = (unsigned int)0xff & dval;
                  i < 8;
                  i++, data >>= 1) {
                    if ((crc & 0x0001) ^ (data & 0x0001))
                         {  crc = (crc >> 1) ^ POLY;}
                    else
                         {  crc >>= 1;}
                  }    
  }
  
  // taking copies of variables so this can be called validly more than once
  short get_crc() { 
       short crc1 = ~crc;      
       short data1 = crc1;
       crc1 = (crc1 << 8) | (data1 >> 8 & 0xFF);
       return crc1;
   }

  }
;
[/endcode]

shelleycat,

I didn't think that you could read flash memory just by using a byte pointer, since the Arduino uses a Harvard architecture. Are you sure that you're really looking at the program and not RAM? Making a change to your program could also be changing the content of RAM.

Regards,

-Mike

Good point Mike. The code should be:

crc16.next(pgm_read_byte(bp));

instead of:

crc16.next(*bp);

--
The Quick Shield: breakout all 28 pins to quick-connect terminals

Ah, thank you. I was getting non-constant results.

I had to include #include <avr/pgmspace.h> too, is that right?

Yes, good call, the <avr/pgmspace.h> include file is needed for the pgm_read_byte() and related functions.

--
Need a custom shield? Let us design and build one for you.

I've now used this function. It gives constant results - for a given sketch, but each different board gives a different results. I've tried it with a seeeduuino (Atmega 168p) and two Duamilanoves (Atmega 168).
This is with v18.

Should the initial value of bp be zero?

(print_report_header and _trailer just output some text, VERSION is just a macro for a string)

void query_prog()
{
print_report_header();
Serial.print(VERSION);
unsigned bp = 0;
crc16.reset();
while (bp <= _etext)
{
crc16.next(pgm_read_byte(bp));
bp++;
}
Serial.print("prog crc is:");
Serial.print(crc16.get_crc(), HEX);
print_report_trailer();
}