Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Jun 01, 2009 - 08:06 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
Dear all,
I am attempting to implement the "Flash Range CRC" Feature as described in the xmega reference manual (page p370) for the ATxmega128A1.
Unfortunantly, the self-programming application note/driver (AVR1316) does not implement this particular function (indeed, does not even mention it in the PDF).
In theory (according to my logic), if the device is supplied with the same start and end addressess as the flash application, it should result in precisely the same calculation as the normal SP_ApplicationCRC and SP_BootCRC as supplied in the above application note.
I have coded a simple test harness to test this out:
Code:
#include "sp_driver.h"
#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>
// Target is the ATxmega128A1
#define APPLICATION_START_BYTE_ADDRESS 0x000000L
// #define APPLICATION_END_BYTE_ADDRESS 0x01FFFFL
#define APPLICATION_END_BYTE_ADDRESS 0x020000L
#define BOOTLOADER_START_BYTE_ADDRESS 0x020000L
// #define BOOTLOADER_END_BYTE_ADDRESS 0x021FFFL
#define BOOTLOADER_END_BYTE_ADDRESS 0x022000L
#define LED_PASS_PORT PORTB
#define LED_PASS_PIN_MASK (1 << 0)
#define LED_FAIL_PORT PORTB
#define LED_FAIL_PIN_MASK (1 << 1)
int main(void)
{
// Setup the LEDs
LED_PASS_PORT.OUTSET = LED_PASS_PIN_MASK;
LED_PASS_PORT.DIRSET = LED_PASS_PIN_MASK;
LED_FAIL_PORT.OUTSET = LED_FAIL_PIN_MASK;
LED_FAIL_PORT.DIRSET = LED_FAIL_PIN_MASK;
// Calculate the CRC of the application section
uint32_t applicationCRC = SP_ApplicationCRC();
SP_WaitForSPM();
// Calculate the CRC of the boot section
uint32_t bootloaderCRC = SP_BootCRC();
SP_WaitForSPM();
// Calculate the CRC of the application section using the CRC Range command
uint32_t applicationCRC_Range = SP_FlashRangeCRC(APPLICATION_START_BYTE_ADDRESS, APPLICATION_END_BYTE_ADDRESS);
// Calculate the CRC of the bootloader section using the CRC Range command
uint32_t bootloaderCRC_Range = SP_FlashRangeCRC(BOOTLOADER_START_BYTE_ADDRESS, BOOTLOADER_END_BYTE_ADDRESS);
// Check the results - the CRC calculations should match
bool ok = true;
ok = ok && (bootloaderCRC == bootloaderCRC_Range);
ok = ok && (applicationCRC == applicationCRC_Range);
// Give the result to the user
if (ok)
{
LED_PASS_PORT.OUTCLR = LED_PASS_PIN_MASK;
}
else
{
LED_FAIL_PORT.OUTCLR = LED_FAIL_PIN_MASK;
}
while(1) {}
}
With the custom part of the sp_driver.S (GCC Assembler):
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32t startAddress, uint32_t endAddress);
;
; Input:
; R25:R24:R23:R22 - Starting address for CRC, in bytes
; R21:R20:R19:R18 - Ending address for CRC, in bytes. CRC includes this address
;
; Returns:
; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bit used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; We're doing this after loading the registers to take advantage of common code
; Load the NVM CMD Register with the flash range CRC command
; ldi r26, NVM_CMD_FLASH_RANGE_CRC_gc
; sts NVM_CMD, r26
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r22
sts NVM_ADDR1, r23
sts NVM_ADDR2, r24
; Load the end address in the NVM data register
sts NVM_DATA0, r18
sts NVM_DATA1, r19
sts NVM_DATA2, r20
; Command the sequence
ldi r20, NVM_CMD_FLASH_RANGE_CRC_gc ; Prepare NVM command in R20.
rjmp SP_CommonCMD ; Jump to common NVM Action code.
EDIT: Adding the common SP code below
Code:
; ---
; This routine is called by several other routines, and contains common code
; for executing an NVM command, including the return statement itself.
;
; If the operation (NVM command) requires the NVM Address registers to be
; prepared, this must be done before jumping to this routine.
;
; Note that R25:R24:R23:R22 is used for returning results, even if the
; C-domain calling function only expects a single byte or even void.
;
; Input:
; R20 - NVM Command code.
;
; Returns:
; R25:R24:R23:R22 - 32-bit result from NVM operation.
; ---
.section .text
SP_CommonCMD:
sts NVM_CMD, r20 ; Load command into NVM Command register.
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
ret
EDIT 2: And the function protoype as follows:
Code:
/*! \brief Generate CRC for a given address range
*
* \param startAddress is the starting byte address of the range to perform the CRC
* \param endAddress is the ending byte address of the range to perform the CRC
*
* \retval 24-bit CRC value
*/
uint32_t SP_FlashRangeCRC(uint32_t startAddress, uint32_t endAddress);
I have included the entire project for reference below.
If anyone is able to suggest any pointers as to why this is misbehaving, I would be very much grateful. At the moment, I'm at a bit stuck on it.
-- Damien |
Last edited by damien_d on Jun 04, 2009 - 02:49 AM; edited 3 times in total
|
| |
|
|
|
|
|
Posted: Jun 03, 2009 - 09:50 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
Try giving the NVM controller a NVM_CMD_NO_OPERATION_gc (0x00)
command after each function call into sp_driver.S and see if that changes
anything for you.
There seems to be something not quite right about sp_driver.S,
but I've not put my figure on exactly what. I have noted that
my program goes off into the weeds when trying to read
calibration bytes using sp_driver.S, if I don't do a NVM no-op command, while this
code:
uint8_t SP_ReadCalibrationByteC( uint8_t index )
{
uint8_t result;
/* Load the NVM Command register to read the calibration row. */
NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc;
result = pgm_read_byte(index);
/* Clean up NVM Command register. */
NVM_CMD = NVM_CMD_NO_OPERATION_gc;
return( result );
}
always seems to work fine.
Something else I've found confusing is that the manual talks of
the "Production Signature Row":
"The Production Signature Row is a separate memory section for factory programmed data. It
contains calibration data for functions such as oscillators and analog modules..."
which the data sheet says is protected by the CCP, see section 3.12:
"the LPM instruction is protected when reading the fuses and signature row."
yet the software talks about the calibration row and does not use CCP.
In iox128a1 the calibration constants are in the production signature row,
see NVM_PROD_SIGNATURES_struct. So which is which, or is the manual wrong?
The following snippet does what I expect when I use my C function,
but not when using sp_driver.S.
/* Device serial number: */
hex8( SP_ReadCalibrationByteC( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM0 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM1 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM2 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM3 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM4 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM5 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, WAFNUM ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDX0 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDX1 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDY0 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, COORDY1 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, TEMPSENSE0 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, TEMPSENSE1 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCACAL0 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCACAL1 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCBCAL0 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, ADCBCAL1 ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACAOFFCAL ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACACAINCAL ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACBOFFCAL ) ) );
hex8( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, DACBGAINCAL ) ) );
[offsetof() is in stddef.h., hex8 displays a hex byte on the units lcd screen.] |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:00 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
bpaddock wrote:
Try giving the NVM controller a NVM_CMD_NO_OPERATION_gc (0x00)
command after each function call into sp_driver.S and see if that changes
anything for you.
There seems to be something not quite right about sp_driver.S,
but I've not put my figure on exactly what. I have noted that
my program goes off into the weeds when trying to read
calibration bytes using sp_driver.S, if I don't do a NVM no-op command
Unfortunantly no joy in just adding a nop to the end:
Code:
SP_CommonCMD:
sts NVM_CMD, r20 ; Load command into NVM Command register.
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
; Transfer the return result
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
; HACK: Adding nop to test for suggestion in thread
; NVM_CMD = NVM_CMD_NO_OPERATION_gc;
ldi r25, NVM_CMD_NO_OPERATION_gc
sts NVM_CMD, r25
clr r25
ret
(compare with the common routine).
I'm not confident with the assembly that I've written (Have I got the registers right for the gcc calling convention?). I'm wondering if I even have the parmeters correct in the first place
The watch variables below may offer a clue to someone... I wonder what's significant about the 0x0056xxxx ??
Sometime today, I'll add your results to my test harness and see what happens. |
Last edited by damien_d on Jun 04, 2009 - 02:05 AM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:03 AM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
| I think you have the parameters backwards. IIRC IAR starts with the first parameter at r16 and works up from there. |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:06 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
glitch wrote:
I think you have the parameters backwards. IIRC IAR starts with the first parameter at r16 and works up from there.
I'm using gcc rather than IAR. |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:09 AM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
yeah sorry, was just realizing that it may not be IAR, and was going to delete. Not sure why I thought it was IAR.
Move along, nothing to see here  |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:11 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
glitch wrote:
yeah sorry, was just realizing that it may not be IAR, and was going to delete. Not sure why I thought it was IAR.
No worries, I appreciate that you're looking  |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:46 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
glitch wrote:
The return value from SP_CommonCMD is also at R16-R19
According to the GCC calling conventions at http://www.nongnu.org/avr-libc/user-man ... reg_usage, the return registers are a little different (and hence, my original code):
Quote:
* Function call conventions:
Arguments - allocated left to right, r25 to r8. All arguments are aligned to start in even-numbered registers (odd-sized arguments, including char, have one free register above them). This allows making better use of the movw instruction on the enhanced core.
If too many, those that don't fit are passed on the stack.
Return values: 8-bit in r24 (not r25!), 16-bit in r25:r24, up to 32 bits in r22-r25, up to 64 bits in r18-r25. 8-bit return values are zero/sign-extended to 16 bits by the called function (unsigned char is more efficient than signed char - just clr r25). Arguments to functions with variable argument lists (printf etc.) are all passed on stack, and char is extended to int.
A question to the asm/gcc gurus, I've noticed that my return values share the same registers as some of the arguments to the function. How does the compiler get around this?
In either case, I tried your suggestion as follows, but with no luck:
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32t startAddress, uint32_t endAddress);
;
; Input:
; R19:R18:R17:R16 - Starting address for CRC, in bytes
; R23:R22:R21:R20 - Ending address for CRC, in bytes. CRC includes this address
;
; Returns:
; R19:R18:R17:R16 - 32-bit CRC result (actually only 24-bit used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r16
sts NVM_ADDR1, r17
sts NVM_ADDR2, r18
; Load the end address in the NVM data register
sts NVM_DATA0, r20
sts NVM_DATA1, r21
sts NVM_DATA2, r22
; Command the sequence
ldi r20, NVM_CMD_FLASH_RANGE_CRC_gc ; Prepare NVM command in R20.
; Common code reimplemented here
sts NVM_CMD, r20 ; Load command into NVM Command register.
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
; Transfer the return result
lds r16, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r17, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r18, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r19 ; Clear R25 in order to return a clean 32-bit value.
ret
|
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:49 AM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
Ok, for GCC it looks like they allocate starting at R25, and work down, so all you had was the start and end backwards. I also didn't like the double loading of the NVM_CMD register, so I replaced the jump to the code, with the remaining relevant code.
Sorry, don't have a xmega to try with.. so give this a go
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32t startAddress, uint32_t endAddress);
;
; Input:
; R21:R20:R19:R18 - Starting address for CRC, in bytes
; R25:R24:R23:R22 - Ending address for CRC, in bytes. CRC includes this address
;
; Returns:
; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bit used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; Load the NVM CMD Register with the flash range CRC command
ldi r25, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r25
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r18
sts NVM_ADDR1, r19
sts NVM_ADDR2, r20
; Load the end address in the NVM data register
sts NVM_DATA0, r22
sts NVM_DATA1, r23
sts NVM_DATA2, r24
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
ret
|
Last edited by glitch on Jun 04, 2009 - 03:12 AM; edited 2 times in total
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:50 AM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
|
damien_d wrote:
glitch wrote:
The return value from SP_CommonCMD is also at R16-R19
According to the GCC calling conventions at http://www.nongnu.org/avr-libc/user-man ... reg_usage, the return registers are a little different (and hence, my original code):
yeah you caught me in an edit... I posted and then realized I grabbed the IAR version, not the GCC version. See above for my corrected code. Sorry again for the confusion. |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:52 AM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
Just for completeness... this is the equivalent IAR version: (I deleted my previous post/edit hoping to avoid further confusion, but got quoted, so here is my final version)
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32t startAddress, uint32_t endAddress);
;
; Input:
; R19:R18:R17:R16 - Starting address for CRC, in bytes
; R23:R22:R21:R20 - Ending address for CRC, in bytes. CRC includes this address
;
; Returns:
; R19:R18:R17:R16 - 32-bit CRC result (actually only 24-bit used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
MODULE _SP_CommonSPM
PUBLIC SP_CommonSPM
RSEG BOOT
#include <ioavr.h>
SP_FlashRangeCRC:
; Load the NVM CMD Register with the flash range CRC command
ldi r23, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r23
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r16
sts NVM_ADDR1, r17
sts NVM_ADDR2, r18
; Load the end address in the NVM data register
sts NVM_DATA0, r20
sts NVM_DATA1, r21
sts NVM_DATA2, r22
; Command the sequence
Prepare NVM command in R20.
ldi r16, CCP_IOREG_gc ; Prepare Protect IO-register signature in R16.
ldi r17, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R17.
sts CCP, r16 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r17 ; Load bitmask into NVM Control Register A, which executes the command.
lds r16, NVM_DATA0 ; Load NVM Data Register 0 into R16.
lds r17, NVM_DATA1 ; Load NVM Data Register 1 into R17.
lds r18, NVM_DATA2 ; Load NVM Data Register 2 into R18.
clr r19 ; Clear R19 in order to return a clean 32-bit value.
ret
ENDMOD
|
Last edited by glitch on Jun 04, 2009 - 03:12 AM; edited 2 times in total
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:54 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
glitch wrote:
Sorry, don't have a xmega to try with.. so give this a go
Just implemented. No joy, sorry.
Interestingly, both calculated ranges return 0x00560000.
(As Implemented above for GCC)
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32t startAddress, uint32_t endAddress);
;
; Input:
; R21:R20:R19:R18 - Starting address for CRC, in bytes
; R25:R24:R23:R22 - Ending address for CRC, in bytes. CRC includes this address
;
; Returns:
; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bit used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r18
sts NVM_ADDR1, r19
sts NVM_ADDR2, r20
; Load the end address in the NVM data register
sts NVM_DATA0, r22
sts NVM_DATA1, r23
sts NVM_DATA2, r24
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
ret
|
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 03:03 AM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
umm, where did the initial load of NVM_CMD go?
The function should start like:
Code:
SP_FlashRangeCRC:
; Load the NVM CMD Register with the flash range CRC command
ldi r26, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r26
; Load the starting address in the NVM Address register
What I removed was the 2nd loading of NVM_CMD, which was happening in SP_CommonCMD
[edit]
on further reflection that should be using R25, to avoid any un-intended side-effects
Code:
SP_FlashRangeCRC:
; Load the NVM CMD Register with the flash range CRC command
ldi r25, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r25
; Load the starting address in the NVM Address register
I'll go back and update my codes above
[/edit]
[edit 2]
Ah, I see now, it was originally commented out and I didn't catch that... needs to be uncommented. I've adjusted all the code above accordingly
[/edit] |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 06:05 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
Ah yes, I have fixed it, but no luck yet. I have tried both loading the NVM control before and after loading the individual addresses:
Code:
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r18
sts NVM_ADDR1, r19
sts NVM_ADDR2, r20
; Load the end address in the NVM data register
sts NVM_DATA0, r22
sts NVM_DATA1, r23
sts NVM_DATA2, r24
; Load the NVM CMD Register with the flash range CRC command
ldi r25, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r25
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
ret
And again with loading the command before setting off:
Code:
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; Load the NVM CMD Register with the flash range CRC command
ldi r25, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r25
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r18
sts NVM_ADDR1, r19
sts NVM_ADDR2, r20
; Load the end address in the NVM data register
sts NVM_DATA0, r22
sts NVM_DATA1, r23
sts NVM_DATA2, r24
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
ret
Both yield the magic 0x00560000 value we've seen before. |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 12:43 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
|
damien_d wrote:
Ah yes, I have fixed it, but no luck yet. I have tried both loading the NVM control before and after loading the individual addresses:
Code:
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
What do you get if you replace CPP_IOREG_gc
with CCP_SPM_gc? To me it seems logical that the
CRC hardware would do something like a LPM access
to read the flah bytes. See section 3.12.2 in the manual.
I'll see what CRC values I get out of my xmega. |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:05 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
I tried several variations of the followin code,
such as adding NO_OPERATION, setting the address/data before
and after the command, even both etc:
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32_t startAddress, uint32_t endAddress);
;
; Input:
; R21:R20:R19:R18 - Starting address for CRC, in bytes
; R25:R24:R23:R22 - Ending address for CRC, in bytes. CRC includes this address
;
; Returns:
; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bit used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
ldi r25, NVM_CMD_NO_OPERATION_gc
sts NVM_CMD, r25
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r18
sts NVM_ADDR1, r19
sts NVM_ADDR2, r20
; Load the end address in the NVM data register
sts NVM_DATA0, r22
sts NVM_DATA1, r23
sts NVM_DATA2, r24
ldi r25, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r25
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r18
sts NVM_ADDR1, r19
sts NVM_ADDR2, r20
; Load the end address in the NVM data register
sts NVM_DATA0, r22
sts NVM_DATA1, r23
sts NVM_DATA2, r24
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r18, 0x9D
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
ldi r25, NVM_CMD_NO_OPERATION_gc
sts NVM_CMD, r25
; clr r25 ; Clear R25 in order to return a clean 32-bit value.
ldi r25,0x42 ; Show the code ran
ret
The most significant thing I found was that the value written to
CCP makes no difference *at all*, even writing 0x00 to CPP, in the
results I see using this code:
Code:
// Target is the ATxmega128A1
#define APPLICATION_START_BYTE_ADDRESS 0x000000L
#define APPLICATION_END_BYTE_ADDRESS 0x01FFFFL
//#define APPLICATION_END_BYTE_ADDRESS 0x020000L
#define BOOTLOADER_START_BYTE_ADDRESS 0x020000L
#define BOOTLOADER_END_BYTE_ADDRESS 0x021FFFL
//#define BOOTLOADER_END_BYTE_ADDRESS 0x022000L
/* hex32() displays a 32 bit hex number on the units LCD */
buf_ptr_u8 = buffer_u8;
SP_WaitForSPM(); hex32( SP_ApplicationCRC() ); *buf_ptr_u8++= (uint8_t) ' ';
SP_WaitForSPM(); hex32( SP_FlashRangeCRC(APPLICATION_START_BYTE_ADDRESS, APPLICATION_END_BYTE_ADDRESS) ); *buf_ptr_u8++= (uint8_t) ' ';
*buf_ptr_u8 = 0;
lcd_text(SCRN_LEFT+0, SCRN_TOP+12, FONT_FIVE_DOT, (char *) buffer_u8);
buf_ptr_u8 = buffer_u8;
SP_WaitForSPM(); hex32( SP_BootCRC() ); *buf_ptr_u8++= (uint8_t) ' ';
SP_WaitForSPM(); hex32( SP_FlashRangeCRC(BOOTLOADER_START_BYTE_ADDRESS, BOOTLOADER_END_BYTE_ADDRESS) ); *buf_ptr_u8++= (uint8_t) ' ';
hex32( 0x12345678 );
*buf_ptr_u8 = 0;
lcd_text(SCRN_LEFT+0, SCRN_TOP+18, FONT_FIVE_DOT, (char *) buffer_u8);
lcd_update(SCRN_TOP,SCRN_BOTTOM);
The values I always got are along the lines of:
Code:
00989DCC 00980000
00261F77 00260000
The bottom 16 bits of FlashRange always returned zero, while the upper 16 bits
always matched, and varied with each compile.
Does anyone have C code that returns the same CRC results as the xmega hardware results? |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 02:47 PM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
| As a test, try loading the fixed values, in the assembly code itself, into the registers to see if it makes any difference. This should tell us if we are receiving the parameters correctly or not. (though looking at the other functions in the driver, it should be correct) |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 03:25 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
|
Quote:
As a test, try loading the fixed values, in the assembly code itself, into the registers to see if it makes any difference. This should tell us if we are receiving the parameters correctly or not. (though looking at the other functions in the driver, it should be correct)
Made no difference. I tried reversing the start/end which did change the result,
the lower 16 bits now always have 0xFFFF rather than 0x0000.
I think it is more telling of a hardware problem that the value written
to CCP doesn't make any difference. Is there any official Atmel
code, known to work, that shows how to use FlashRange?
Code:
; Use one of the following sets:
ldi r22, 0x00 ; 0
ldi r23, 0x00 ; 0
ldi r24, 0x00 ; 0
ldi r25, 0x00 ; 0
ldi r18, 0xFF ; 255
ldi r19, 0xFF ; 255
ldi r20, 0x01 ; 1
ldi r21, 0x00 ; 0
; end/start:
ldi r18, 0x00 ; 0
ldi r19, 0x00 ; 0
ldi r20, 0x00 ; 0
ldi r21, 0x00 ; 0
ldi r22, 0xFF ; 255
ldi r23, 0xFF ; 255
ldi r24, 0x01 ; 1
ldi r25, 0x00 ; 0
|
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 04:19 PM |
|


Joined: Jan 12, 2002
Posts: 7832
Location: Canada
|
|
Ok, now I'm starting to read all the docs instead of working off of the provided code.
Question: What are your boot lock bits programmed as? |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2009 - 04:26 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
They are not programmed, per footnote #3.
I have read the docs. They are inconsistent in places. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2009 - 06:19 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
glitch wrote:
Question: What are your boot lock bits programmed as?
Sorry, for the long time between replies. All lock bit are unprogrammed, as per the requirements for calling the function. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2009 - 06:23 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
bpaddock wrote:
They are not programmed, per footnote #3.
I have read the docs. They are inconsistent in places.
For clarity, This refers to the following footnote for the FLASH_RANGE_CRC command:
Quote:
3. This command is qualified with the Lock BIts, and requires that the Boot Lock Bits are unprogrammed
|
|
|
| |
|
|
|
|
|
Posted: Jun 09, 2009 - 01:24 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
|
damien_d wrote:
Dear all,
I am attempting to implement the "Flash Range CRC" Feature as described in the xmega reference manual (page p370) for the ATxmega128A1.
Give it up, it is officially broken, actually doesn't exist a all
in the ATxmega128A1 RevH:
From avr(at)atmel.com:
"The 'Flash Range CRC' functionality is an added feature
currently present in the latest xmega A3 and A4 series. However
this is intended to be added to A1 in revision J.
This information is currently missing from the documentation,
but will be added for the next documentation release."
-- Best Regards, Jon Anders Haugum, Atmel Technical Support Team
So what else in Xmega land can we waste valuable time on that is not documented?  |
|
|
| |
|
|
|
|
|
Posted: Jun 09, 2009 - 01:32 PM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
bpaddock wrote:
Give it up, it is officially broken, actually doesn't exist a all in the ATxmega128A1 RevH:
Dear Admins,
What language is acceptable for use on these forums? I'd like to use some words that my mother would frown at.
At least we now know. I'll link this thread to the "Gotchas" sticky. |
|
|
| |
|
|
|
|
|
Posted: Jun 27, 2009 - 03:11 AM |
|


Joined: Nov 06, 2006
Posts: 292
Location: Wa, USA
|
|
|
bpaddock wrote:
damien_d wrote:
Dear all,
I am attempting to implement the "Flash Range CRC" Feature as described in the xmega reference manual (page p370) for the ATxmega128A1.
Give it up, it is officially broken, actually doesn't exist a all
in the ATxmega128A1 RevH:
From avr(at)atmel.com:
"The 'Flash Range CRC' functionality is an added feature
currently present in the latest xmega A3 and A4 series. However
this is intended to be added to A1 in revision J.
This information is currently missing from the documentation,
but will be added for the next documentation release."
-- Best Regards, Jon Anders Haugum, Atmel Technical Support Team
So what else in Xmega land can we waste valuable time on that is not documented?
Is this still the current state of things? I had a lot of problems getting this to work on RevH, but I think I am getting reasonable 24-bit values for both flash and bootloader sections. One thing I found that would prevent some kind of PC corruption is putting a SP_WaitForSPM() after each NVM command that used LVM. I know that isn't right and might just serve a small delay. I haven't verified that. I also had to do the SP_WaitForSPM() for reading/writing User Sig Row, Production Row. Those both verify with what AVR Studio reports.
Here is sample crcs, bootloader is always the same, and application only changes when I update it.
application crc: 0x0054b9cc
bootloader crc : 0x00cd2554
Is the problem just that it can't be verified against the algorithm or is everyone still having problems getting 24-bit values from the commands? I can provide source if anybody is interested.
I also found a related error in A manual and avr-libc,
see here
http://www.avrfreaks.net/index.php?name ... mp;t=80689
[edit]
I just realized that I implied that the crc commands were LPM commands. They aren't. They are NVM CMD functions. I also just checked and I don't need the SP_WaitForSPM() after each CRC CMD to make it work correctly. I only had to do that after the LPM Commands like User Sig R/W, and Production Row.
[edit2] Here is another nice 24-bit crc after application update
application crc: 0x00489168
bootloader crc : 0x00cd2554 |
|
|
| |
|
|
|
|
|
Posted: Jun 27, 2009 - 10:17 PM |
|


Joined: Nov 06, 2006
Posts: 292
Location: Wa, USA
|
|
|
bpaddock wrote:
Give it up, it is officially broken, actually doesn't exist a all in the ATxmega128A1 RevH:
Is it possible that someone made an error in their reply from Atmel? I am getting random-looking, but consistent 24-bit crc everytime I update the application on a Rev H Xmega128A1. |
|
|
| |
|
|
|
|
|
Posted: Jul 02, 2009 - 08:19 PM |
|


Joined: Sep 27, 2001
Posts: 206
Location: North of Pittsburgh
|
|
|
telliott wrote:
bpaddock wrote:
Give it up, it is officially broken, actually doesn't exist a all in the ATxmega128A1 RevH:
Is it possible that someone made an error in their reply from Atmel? I am getting random-looking, but consistent 24-bit crc everytime I update the application on a Rev H Xmega128A1.
Are you speaking of the CRC command(s) (0x38/0x39),
or the CRC Range command (0x3A)? CRC works fine.
It is the CRC Range command that is broken. |
|
|
| |
|
|
|
|
|
Posted: Jul 02, 2009 - 09:49 PM |
|


Joined: Nov 06, 2006
Posts: 292
Location: Wa, USA
|
|
|
bpaddock wrote:
Are you speaking of the CRC command(s) (0x38/0x39),
or the CRC Range command (0x3A)? CRC works fine.
It is the CRC Range command that is broken.
Sorry Bob, I was confused on that. Thanks for clearing that up. |
|
|
| |
|
|
|
|
|
Posted: Jul 03, 2009 - 09:29 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
Success on a ATxmega32A4!
Code:
#include "sp_driver.h"
#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "usart_driver.h"
/*
// Target is the ATxmega128A1
#define APPLICATION_START_BYTE_ADDRESS (0x000000L )
#define APPLICATION_START_WORD_ADDRESS (APPLICATION_START_BYTE_ADDRESS >> 1)
#define APPLICATION_END_BYTE_ADDRESS (0x020000L - 1L) // End in bytes
#define APPLICATION_END_WORD_ADDRESS (APPLICATION_END_BYTE_ADDRESS >> 1) // End in words
#define BOOTLOADER_START_BYTE_ADDRESS 0x020000L
#define BOOTLOADER_START_WORD_ADDRESS (BOOTLOADER_START_BYTE_ADDRESS >> 1)
#define BOOTLOADER_END_BYTE_ADDRESS (0x022000L - 1L)
#define BOOTLOADER_END_WORD_ADDRESS (BOOTLOADER_END_BYTE_ADDRESS >> 1)
*/
// Target is the ATxmega32A4
#define APPLICATION_START_BYTE_ADDRESS (0x000000L )
#define APPLICATION_START_WORD_ADDRESS (APPLICATION_START_BYTE_ADDRESS >> 1)
#define APPLICATION_END_BYTE_ADDRESS (0x0008000L - 1L) // End in bytes
#define APPLICATION_END_WORD_ADDRESS (APPLICATION_END_BYTE_ADDRESS >> 1) // End in words
#define BOOTLOADER_START_BYTE_ADDRESS 0x008000L
#define BOOTLOADER_START_WORD_ADDRESS (BOOTLOADER_START_BYTE_ADDRESS >> 1)
#define BOOTLOADER_END_BYTE_ADDRESS (0x09000L - 1L)
#define BOOTLOADER_END_WORD_ADDRESS (BOOTLOADER_END_BYTE_ADDRESS >> 1)
// LED Pin Masks
#define LED_PASS_PORT PORTB
#define LED_PASS_PIN_MASK (1 << 0)
#define LED_FAIL_PORT PORTB
#define LED_FAIL_PIN_MASK (1 << 1)
// Global access for Serial Transmission
uint32_t applicationCRC;
uint32_t bootloaderCRC;
uint32_t applicationCRC_Range;
uint32_t bootloaderCRC_Range;
// Serial Buffers
char bootSerialBuffer[128];
char applicationSerialBuffer[128];
// Function prototypes
void UART_Setup();
void UART_SendString(char* buffer, int length);
bool TestHarness_FlashRangeCRC()
{
// Calculate the CRC of the application section
applicationCRC = SP_ApplicationCRC();
SP_WaitForSPM();
// Calculate the CRC of the boot section
bootloaderCRC = SP_BootCRC();
SP_WaitForSPM();
// Calculate the CRC of the application section using the CRC Range command
applicationCRC_Range = SP_FlashRangeCRC(APPLICATION_START_BYTE_ADDRESS, APPLICATION_END_BYTE_ADDRESS);
// applicationCRC_Range = SP_FlashRangeCRC(APPLICATION_END_BYTE_ADDRESS, APPLICATION_START_BYTE_ADDRESS);
// Calculate the CRC of the bootloader section using the CRC Range command
bootloaderCRC_Range = SP_FlashRangeCRC(BOOTLOADER_START_BYTE_ADDRESS, BOOTLOADER_END_BYTE_ADDRESS);
// Check the results - the CRC calculations should match
bool ok = true;
ok = ok && (bootloaderCRC == bootloaderCRC_Range);
ok = ok && (applicationCRC == applicationCRC_Range);
return ok;
}
int main(void)
{
// Setup the LEDs
LED_PASS_PORT.OUTSET = LED_PASS_PIN_MASK;
LED_PASS_PORT.DIRSET = LED_PASS_PIN_MASK;
LED_FAIL_PORT.OUTSET = LED_FAIL_PIN_MASK;
LED_FAIL_PORT.DIRSET = LED_FAIL_PIN_MASK;
bool ok = TestHarness_FlashRangeCRC();
// Create the results to send out the serial
sprintf(applicationSerialBuffer, "Application: Range = 0x%08lX, Calc = 0x%08lX\r\n", applicationCRC_Range, applicationCRC);
sprintf(bootSerialBuffer, "Boot: Range = 0x%08lX, Calc = 0x%08lX\r\n\r\n", bootloaderCRC_Range, bootloaderCRC);
// Give the result to the user
if (ok)
{
LED_PASS_PORT.OUTCLR = LED_PASS_PIN_MASK;
}
else
{
LED_FAIL_PORT.OUTCLR = LED_FAIL_PIN_MASK;
}
// Spit the results out the serial port
UART_Setup();
UART_SendString(applicationSerialBuffer, strlen(applicationSerialBuffer));
UART_SendString(bootSerialBuffer, strlen(bootSerialBuffer));
while(1) {}
}
/*! Define that selects the Usart used in example. */
#define USART USARTC0
// Spit the results out the serial port
void UART_Setup()
{
// PortC Tx as output
PORTC.DIRSET = PIN3_bm;
// USARTC0, 8 Data bits, No Parity, 1 Stop bit
USART_Format_Set(&USART, USART_CHSIZE_8BIT_gc, USART_PMODE_DISABLED_gc, false);
// 9600bps @ 2MHz
USART_Baudrate_Set(&USART, 12 , 0);
// Enable the transmitter
USART_Tx_Enable(&USART);
}
void UART_SendString(char* buffer, int length)
{
int i;
for (i = 0 ; i < length ; ++i)
{
while(!USART_IsTXDataRegisterEmpty(&USART))
{
}
USART_PutChar(&USART, buffer[i]);
}
}
And, the SP routine to do it (gcc)
Code:
;--------------------------------------------------------------------------------------------------
; This routine calculates a CRC for a given range of flash
;
; C Prototype:
; uint32_t SP_FlashRangeCRC(uint32t startAddress, uint32_t endAddress);
;
; Input:
; R21:R20:R19:R18 - Ending address for CRC, in bytes
; R25:R24:R23:R22 - Starting address for CRC, in bytes. CRC Includes this address
;
; Returns:
; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bits used)
;
; Side Effects:
;
;--------------------------------------------------------------------------------------------------
;
; 30.11.2.6 Flash Range CRC
;
; The Flash Range CRC command can be used to verify the content in an address range in Flash
; after a self-programming.
;
; 1. Load the NVM CMD register with the Flash Range CRC command.
; 2. Load the start byte address in the NVM Address Register (NVM ADDR).
; 3. Load the end byte address in NVM Data Register (NVM DATA).
; 4. Set the CMDEX bit in the NVM CTRLA register. This requires the timed CCP sequence
; during self-programming.
;
; The BUSY flag in the NVM STATUS register will be set, and the CPU is halted during the execution
; of the command.
; The CRC checksum will be available in the NVM DATA register.
; In order to use the Flash Range CRC all the Boot Lock Bits must be unprogrammed (no locks).
; The command execution will be aborted if the Boot Lock Bits for an accessed location are set.
;--------------------------------------------------------------------------------------------------
.section .text
.global SP_FlashRangeCRC
SP_FlashRangeCRC:
; Load the NVM CMD Register with the flash range CRC command
ldi r25, NVM_CMD_FLASH_RANGE_CRC_gc
sts NVM_CMD, r25
; Load the starting address in the NVM Address register
sts NVM_ADDR0, r22
sts NVM_ADDR1, r23
sts NVM_ADDR2, r24
; Load the end address in the NVM data register
sts NVM_DATA0, r18
sts NVM_DATA1, r19
sts NVM_DATA2, r20
; Command the sequence
ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18.
ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19.
sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles).
sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command.
lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22.
lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23.
lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24.
clr r25 ; Clear R25 in order to return a clean 32-bit value.
ret
Outputs the following over serial:
Code:
Application: Range = 0x00FCD714, Calc = 0x00FCD714
Boot: Range = 0x00BDA0A3, Calc = 0x00BDA0A3
-- Damien. |
|
|
| |
|
|
|
|
|
Posted: Jul 03, 2009 - 04:08 PM |
|


Joined: Feb 19, 2001
Posts: 26115
Location: Wisconsin USA
|
|
|
Quote:
...on a ATxmega32A4...
OK, 'fess up--ordered from distis? Samples?
I put in for samples the day there was a link and no word since. (But I think they cut back the rep in my area that used to do the follow-up.)
Lee |
|
|
| |
|
|
|
|
|
Posted: Jul 04, 2009 - 01:55 AM |
|

Joined: Dec 15, 2008
Posts: 923
Location: Brisbane, Australia
|
|
|
Quote:
OK, 'fess up--ordered from distis? Samples?
Samples from disti. But our HQ guy has been asking for them since December, probably required all sorts of dirty tricks to get them.
That, and the TQFP44 adaptor board didn't come with the correct sandwich card, so that needed to get ordered in.
4 weeks later. Grrr.... |
|
|
| |
|
|
|
|
|
Posted: Nov 06, 2011 - 04:46 PM |
|

Joined: Feb 03, 2007
Posts: 2
|
|
|
Code:
/******************************************************************************
*
* Function Name: XmegaCrcCalculation
*
* Description: This calculates an XMEGA CRC over the specified range.
*
*****************************************************************************/
static int XmegaCrcCalculation( int startAddr, int endAddr )
{
// Polynomial for use with Xmega 'A' devices
const int CRC32_POLY = 0x0080001B;
int wordAddr;
int dataWord, tmpVar1, tmpVar2;
int crc = 0;
// Calculate the CRC over the specified address range
for( wordAddr = startAddr; wordAddr < endAddr; wordAddr += 2 )
{
tmpVar1 = crc << 1;
tmpVar1 &= 0x00FFFFFE; // Always act as 24-bit variable
tmpVar2 = crc & (1 << 23);
if ( tmpVar2 != 0 )
{
tmpVar2 = 0x00FFFFFF;
}
// Read a single (2-byte) word from memory
dataWord = (int) flashImage[wordAddr]
| ((int) flashImage[wordAddr + 1] << 8);
crc = ( tmpVar1 ^ dataWord ) ^ ( tmpVar2 & CRC32_POLY );
crc = crc & 0x00FFFFFF;
}
// Return the calculated CRC
return crc;
}
|
|
|
| |
|
|
|
|
|
|
|
|