Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
damien_d
PostPosted: Jun 01, 2009 - 08:06 AM
Resident


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
 
 View user's profile Send private message  
Reply with quote Back to top
bpaddock
PostPosted: Jun 03, 2009 - 09:50 PM
Hangaround


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.]
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
damien_d
PostPosted: Jun 04, 2009 - 02:00 AM
Resident


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 Sad

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
 
 View user's profile Send private message  
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 02:03 AM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
Location: Canada

I think you have the parameters backwards. IIRC IAR starts with the first parameter at r16 and works up from there.
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jun 04, 2009 - 02:06 AM
Resident


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.
 
 View user's profile Send private message  
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 02:09 AM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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 Wink
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jun 04, 2009 - 02:11 AM
Resident


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 Smile
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jun 04, 2009 - 02:46 AM
Resident


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
 
 View user's profile Send private message  
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 02:49 AM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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
 
 View user's profile Send private message  
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 02:50 AM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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.
 
 View user's profile Send private message  
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 02:52 AM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jun 04, 2009 - 02:54 AM
Resident


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
 
 View user's profile Send private message  
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 03:03 AM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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]
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jun 04, 2009 - 06:05 AM
Resident


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.
 
 View user's profile Send private message  
Reply with quote Back to top
bpaddock
PostPosted: Jun 04, 2009 - 12:43 PM
Hangaround


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
bpaddock
PostPosted: Jun 04, 2009 - 02:05 PM
Hangaround


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?
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 02:47 PM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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)
 
 View user's profile Send private message  
Reply with quote Back to top
bpaddock
PostPosted: Jun 04, 2009 - 03:25 PM
Hangaround


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
glitch
PostPosted: Jun 04, 2009 - 04:19 PM
Raving lunatic


Joined: Jan 12, 2002
Posts: 7828
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?
 
 View user's profile Send private message  
Reply with quote Back to top
bpaddock
PostPosted: Jun 04, 2009 - 04:26 PM
Hangaround


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
damien_d
PostPosted: Jun 06, 2009 - 06:19 AM
Resident


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.
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jun 06, 2009 - 06:23 AM
Resident


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
 
 View user's profile Send private message  
Reply with quote Back to top
bpaddock
PostPosted: Jun 09, 2009 - 01:24 PM
Hangaround


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? Sad
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
damien_d
PostPosted: Jun 09, 2009 - 01:32 PM
Resident


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.
 
 View user's profile Send private message  
Reply with quote Back to top
telliott
PostPosted: Jun 27, 2009 - 03:11 AM
Hangaround


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? Sad


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
telliott
PostPosted: Jun 27, 2009 - 10:17 PM
Hangaround


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
bpaddock
PostPosted: Jul 02, 2009 - 08:19 PM
Hangaround


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
telliott
PostPosted: Jul 02, 2009 - 09:49 PM
Hangaround


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
damien_d
PostPosted: Jul 03, 2009 - 09:29 AM
Resident


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.
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Jul 03, 2009 - 04:08 PM
10k+ Postman


Joined: Feb 19, 2001
Posts: 25884
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
 
 View user's profile Send private message  
Reply with quote Back to top
damien_d
PostPosted: Jul 04, 2009 - 01:55 AM
Resident


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....
 
 View user's profile Send private message  
Reply with quote Back to top
dmanjacobs
PostPosted: Nov 06, 2011 - 04:46 PM
Newbie


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;
        }
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits