ATxmega128A1 software CRC that matches hardware CRC

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Device: ATxmega128A1

 /* * The Xmega manual Rev G lists the CRC Polynomial * as: x^24 + 4x3 + 3x +1. * * Based on some untested code supplied by avr(at)atmel.com, * I believe the correct Polynomial is: * x^19 + x^4 + x^3 + x^1 + 1 * * At any rate after cleaning up their code issues, the following C * code generates the same values as the XMega 128A1 hardware. * * Any math grues out there than can tells how * strong this non-standard Polynomial is? * * The hardware initializes the CRC register to all zeros, * rather than all ones. This can lead to missing the * detection of inserted leading zeros. * * - Bob Paddock * */ #include #include #include #include "sp_driver.h" static inline LED_GREEN_TOGGLE( void ) { /* Put your LED code here */ } static inline LED_RED_TOGGLE( void ) { /* Put your LED code here */ } #define CRC32_POLY (0x0080001BUL) /* Polynomial for use with Xmega 'A' devices */ /* This CRC Routine is the corresponding routine implemented in Xmega hardware: */ uint32_t CRC_Reference( uint32_t startWord_u32, uint32_t endWord_u32 ) { uint32_t addr_u32, data_reg_u32, help_a_u32, help_b_u32; uint32_t crc_reg_u32 = 0; for( addr_u32 = startWord_u32; addr_u32 <= endWord_u32; addr_u32 += 2 ) { help_a_u32 = crc_reg_u32 << 1; help_a_u32 &= 0x00FFFFFEUL; /* Always act as 24-bit variable */ help_b_u32 = crc_reg_u32 & (1UL << 23); if( help_b_u32 > 0 ) { help_b_u32 = 0x00FFFFFFUL; } data_reg_u32 = SP_ReadWord( addr_u32 ); crc_reg_u32 = (help_a_u32 ^ data_reg_u32) ^ (help_b_u32 & CRC32_POLY); crc_reg_u32 = crc_reg_u32 & 0x00FFFFFFUL; } return( crc_reg_u32 ); } int main( void ) { uint32_t crc_u32; crc_u32 = SP_BootCRC(); if( crc_u32 != CRC_Reference( BOOT_SECTION_START, (BOOT_SECTION_END-1) ) ) /* END-1 is due to use of words, not bytes */ { for(;;)/* Boot CRC missmatch */ { _delay_ms(500.0); LED_GREEN_TOGGLE(); } } crc_u32 = SP_ApplicationCRC(); if( crc_u32 != CRC_Reference( APP_SECTION_START, (APP_SECTION_END-1) ) ) /* END-1 is due to use of words, not bytes */ { for(;;)/* Application CRC missmatch */ { _delay_ms(500.0); LED_RED_TOGGLE(); } } /* CRCs match if we get here */ } 

Last Edited: Thu. May 28, 2015 - 09:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow, that was a "5 minute job" getting this far! Well done.

You might consider putting the polynomial note onto the sticky thread about undocumented errata.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm impressed! Coding up a test harness now....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Confirmed code to work on an ATxmega32A4.

-- Damien.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bpaddock wrote:

At any rate after cleaning up their code issues, the following C code generates the same values as the XMega 128A1 hardware.

It sure does.. Thanks for posting this Bob. Having an implementation of the on-board algorithm makes it very easy (and fast) to verify an application firmware image on an SD Flash card.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Apologies for the necro but I thought I would post a little mod I made to run the code in Visual C. Handy for bootloaders and the like.


#define CRC32_POLY (0x0080001BUL) /* Polynomial for use with Xmega 'A' devices */

unsigned char buffer[BUFFER_SIZE];


/* This CRC Routine is the corresponding routine implemented in Xmega hardware: */
unsigned int CRC_Reference(int start_address, int end_address)
{
	int	address;
	unsigned int	data_reg, help_a, help_b;
	unsigned int	crc_reg = 0;

	for(address = start_address; address <= end_address; address += 2)		// works on words
	{
		help_a	= crc_reg << 1;
		help_a &= 0x00FFFFFEUL; /* Always act as 24-bit variable */

		help_b	= crc_reg & (1UL << 23);

		if( help_b > 0 )
		{
			help_b = 0x00FFFFFFUL;
		}

		data_reg = ((buffer[address+1] << 8) | buffer[address]) & 0xFFFF;

		crc_reg = (help_a ^ data_reg) ^ (help_b & CRC32_POLY);
		crc_reg = crc_reg & 0x00FFFFFFUL;
	}

	return( crc_reg );
}

Remember to fill the unused buffer area with 0xFF if you want to CRC the entire flash memory.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For the almost last word in CRC's, see: http://www.tty1.net/pycrc/

madGambol

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think this Thread originated before the existence of the Xmega Sub-Forum.

 

Perhaps, however, a Moderator to could now move it to its rightful spot.

 

JC

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Done!

 

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Has anybody done this for the Hardware CRC-CCITT 16, as i am having an issue using the CRC16, and cannot replicate the generated code by the Atmel Xmega onboard CRC calculator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought I had CRC-16 code, I know that I have checked it conforms to CRC-CCITT before so it should work fine if your desktop code is correct.

 

Anyway, have a CRC32 generator as consolation prize:

 

/**************************************************************************************************
* Reverse bits in a uint32
*/
uint32_t reverse(uint32_t x)
{
	x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
	x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
	x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
	x = (x << 24) | ((x & 0xFF00) << 8) |
		((x >> 8) & 0xFF00) | (x >> 24);
	return x;
}

/**************************************************************************************************
* Slow but correct CRC32
*/
uint32_t crc32(uint8_t *buffer, uint32_t buffer_length)
{
	int32_t i, j;
	uint32_t byte, crc;

	i = 0;
	crc = 0xFFFFFFFF;

	while (buffer_length--)
	{
		byte = *buffer++;
		byte = reverse(byte);

		for (j = 0; j < 8; j++)
		{
			if ((int32_t)(crc ^ byte) < 0)
				crc = (crc << 1) ^ 0x04C11DB7;
			else
				crc <<= 1;
			byte <<= 1;
		}
		i++;
	}

	return reverse(~crc);
}