Production Signature Row registers are not defined in iox64d3.h when I create a new xmega64d3 project with atmel studio 6.2, why?

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

hello, there

 

I'm programming for the chip xmega64d3 with atmel studio 6.2. When i create a new GCC C Executable Project, i find that 

Production Signature Row registers are not defined in the header file iox64d3.h. When i need to load a calibration value

from signature row register, e.g. for ADC, then i can't find ADCACA0 register and ADCACAL1 register in file iox64d3.h. So i

need to define the registers myself like:

 

#define PRODSIGNATURES_ADCACAL0  _SFR_MEM8(0x0020)
#define PRODSIGNATURES_ADCACAL1  _SFR_MEM8(0x0021)

 

My main problem is that i don't understand why there're no definitions for Production Signature Row registers in header file iox64d3.h

for the chip xmega64d3 but there're definitions in header file iox64a3u.h for the chip xmega64a3u. Maybe i'm stupid enough but i really

need an explanation to eliminate my doubt.

 

Thanks in advance!

 

This topic has a solution.

Last Edited: Tue. May 12, 2015 - 04:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's in my header file

 

/* Production Signatures */
typedef struct NVM_PROD_SIGNATURES_struct
{
    register8_t RCOSC2M;  /* RCOSC 2MHz Calibration Value */
    register8_t reserved_0x01;
    register8_t RCOSC32K;  /* RCOSC 32kHz Calibration Value */
    register8_t RCOSC32M;  /* RCOSC 32MHz Calibration Value */
    register8_t reserved_0x04;
    register8_t reserved_0x05;
    register8_t reserved_0x06;
    register8_t reserved_0x07;
    register8_t LOTNUM0;  /* Lot Number Byte 0, ASCII */
    register8_t LOTNUM1;  /* Lot Number Byte 1, ASCII */
    register8_t LOTNUM2;  /* Lot Number Byte 2, ASCII */
    register8_t LOTNUM3;  /* Lot Number Byte 3, ASCII */
    register8_t LOTNUM4;  /* Lot Number Byte 4, ASCII */
    register8_t LOTNUM5;  /* Lot Number Byte 5, ASCII */
    register8_t reserved_0x0E;
    register8_t reserved_0x0F;
    register8_t WAFNUM;  /* Wafer Number */
    register8_t reserved_0x11;
    register8_t COORDX0;  /* Wafer Coordinate X Byte 0 */
    register8_t COORDX1;  /* Wafer Coordinate X Byte 1 */
    register8_t COORDY0;  /* Wafer Coordinate Y Byte 0 */
    register8_t COORDY1;  /* Wafer Coordinate Y Byte 1 */
    register8_t reserved_0x16;
    register8_t reserved_0x17;
    register8_t reserved_0x18;
    register8_t reserved_0x19;
    register8_t reserved_0x1A;
    register8_t reserved_0x1B;
    register8_t reserved_0x1C;
    register8_t reserved_0x1D;
    register8_t reserved_0x1E;
    register8_t reserved_0x1F;
    register8_t ADCACAL0;  /* ADCA Calibration Byte 0 */
    register8_t ADCACAL1;  /* ADCA Calibration Byte 1 */
    register8_t reserved_0x22;
    register8_t reserved_0x23;
    register8_t ADCBCAL0;  /* ADCB Calibration Byte 0 */
    register8_t ADCBCAL1;  /* ADCB Calibration Byte 1 */

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Thank you for your warmheartedness, John. Perhaps I have found out the cause of this problem.

Beause my programming method is different from Atmel's given examples based on its development boards,

I need to define the signature row registers directly if there're no definitons without using atmel's firmware.

I'm a beginner and i don't like the complicated, nested relationships of functions given by atmel's firmware.

So because of your help, i've got a bit of understanding. Thank you very much and if i want to sovle the problem

completely then i need to study atmel's firmware.

 

 

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

Good_natured,

 

I fear you have misunderstood how to access these calibration bytes.

 

As John says the .h file typedef's a struct layout for NVM_PROD_SIGNATURES but if you look further through the header you won't find that struct definition actually being applied to any particular address (and it sure cannot be MEM8(0x20), it's actually in a different address space)

 

But when you Google "NVM_PROD_SIGNATURES" you will find out why. Atmel are only defining the struct so you can then use offsetof() with a routine such as the ReadCalibrationByte() shown here:

 

https://eewiki.net/download/atta...

 

uint8_t ReadCalibrationByte(uint8_t index) {
	
	uint8_t result;
	NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc;
	result = pgm_read_byte(index);
	
	NVM_CMD = NVM_CMD_NO_OPERATION_gc;
	
	return(result);
}

Notice how he uses it here:


	// Calibration values are stored at production time
	// Load stored bytes into the calibration registers
	// First NVM read is junk and must be thrown away
	ADCB.CALL = ReadCalibrationByte( offsetof(NVM_PROD_SIGNATURES_t, ADCBCAL0) );
	ADCB.CALH = ReadCalibrationByte( offsetof(NVM_PROD_SIGNATURES_t, ADCBCAL1) );
	ADCB.CALL = ReadCalibrationByte( offsetof(NVM_PROD_SIGNATURES_t, ADCBCAL0) );
	ADCB.CALH = ReadCalibrationByte( offsetof(NVM_PROD_SIGNATURES_t, ADCBCAL1) );

that's when the entries in the typedef'd struct in the .h file come into play.

 

There is a tutorial on this very site with something similar (though not ADC calibration in this case):

 

https://www.avrfreaks.net/forum/t...

 

but sadly the forum migration has lead to the <> in the #include's being lost. The original is here:

 

http://legacy.avrfreaks.net/inde...

 

but note that is relying on SPM routines from AVR1316 as well.

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

Of course if one doesn't understand or can't use structures there is always the assembler .inc file for sane people...  wink

 

.equ NVM_PROD_SIGNATURES_RCOSC2M_offset = 0x00		// RCOSC 2MHz Calibration Value
.equ NVM_PROD_SIGNATURES_RCOSC32K_offset = 0x02		// RCOSC 32kHz Calibration Value
.equ NVM_PROD_SIGNATURES_RCOSC32M_offset = 0x03		// RCOSC 32MHz Calibration Value
.equ NVM_PROD_SIGNATURES_LOTNUM0_offset = 0x08		// Lot Number Byte 0, ASCII
.equ NVM_PROD_SIGNATURES_LOTNUM1_offset = 0x09		// Lot Number Byte 1, ASCII
.equ NVM_PROD_SIGNATURES_LOTNUM2_offset = 0x0A		// Lot Number Byte 2, ASCII
.equ NVM_PROD_SIGNATURES_LOTNUM3_offset = 0x0B		// Lot Number Byte 3, ASCII
.equ NVM_PROD_SIGNATURES_LOTNUM4_offset = 0x0C		// Lot Number Byte 4, ASCII
.equ NVM_PROD_SIGNATURES_LOTNUM5_offset = 0x0D		// Lot Number Byte 5, ASCII
.equ NVM_PROD_SIGNATURES_WAFNUM_offset = 0x10		// Wafer Number
.equ NVM_PROD_SIGNATURES_COORDX0_offset = 0x12		// Wafer Coordinate X Byte 0
.equ NVM_PROD_SIGNATURES_COORDX1_offset = 0x13		// Wafer Coordinate X Byte 1
.equ NVM_PROD_SIGNATURES_COORDY0_offset = 0x14		// Wafer Coordinate Y Byte 0
.equ NVM_PROD_SIGNATURES_COORDY1_offset = 0x15		// Wafer Coordinate Y Byte 1
.equ NVM_PROD_SIGNATURES_ADCACAL0_offset = 0x20		// ADCA Calibration Byte 0
.equ NVM_PROD_SIGNATURES_ADCACAL1_offset = 0x21		// ADCA Calibration Byte 1
.equ NVM_PROD_SIGNATURES_ADCBCAL0_offset = 0x24		// ADCB Calibration Byte 0
.equ NVM_PROD_SIGNATURES_ADCBCAL1_offset = 0x25		// ADCB Calibration Byte 1

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

As you said john, i've tried asm language to get calibration value. laugh

Also, it's an easy way to get this calibration value directly from my PDI Programmer.

Last Edited: Fri. May 15, 2015 - 08:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the old days such calibration values were not visible at runtime (tiny/mega) so what you actually did was read out the calibration with your programmer (in that case ISP not PDI) then you might write it back into a storage area that was easily accessed at runtime (typically EEPROM). The app code then just started by picking up the calibration from the EEPROM. If all else fails the same approach would work for an Xmega and these calibration values too.

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

Got it. Thank you very much, clawson.

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

Well you marked it as a solution. I'm not sure I agree. I'd call it "the solution of last resort for when all else fails". Really you should be able to achieve this using the offsetof() approach I already gave some links/details of.

 

Your misunderstanding seems to be that you think the CAL values are just going to be visible at fixed addresses at any time. They are not. They are at fixed addresses but clearly in a memory space that is not normally visible. So you have to use the NVM controller to map that memory space into visibility. Then you use pgm_read_byte() or other LPM, flash access technique, to read the now mapped value.

 

As the addresses seem to be 0 based it looks like the CAL value are mapped to appear at 0. If so that would seem to suggest that, while visible, they are replacing the interrupt vector table. If that's really true then presumably you have to make the access with interrupts disabled?

 

OTOH perhaps the Xmega is clever enough to still use the "hidden" IVT in the event of an interrupt occurring?

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

These are the routines I have collected to deal with the NVM, hope they are correct. smiley

 

; On entry temp must contain the address of the calibration byte to read.
; Calibration byte returned in temp.
Read_calibration_byte:
	mov	ZL, temp				; Point Z to required signature byte
	clr	ZH
	ldi	temp, NVM_CMD_READ_CALIB_ROW_gc
	STORE	NVM_CMD, temp				; Load command into NVM Command register.
	lpm	temp, Z
	rjmp	NVM_CMD_NO_OP				; Reset NVM and return

; On entry temp must contain the address of the fuse to read (0-7).
; Fuse value returned in temp.
Read_FUSEBYTE:
	clr	temp1
	STORE	NVM_ADDR0, temp				; Put fuse address in address register 0 and
	STORE	NVM_ADDR1, temp1			; clear the other 2 not used registers
	STORE	NVM_ADDR2, temp1
	ldi	temp, NVM_CMD_READ_FUSES_gc
	STORE	NVM_CMD, temp				; Load command into NVM Command register.
	ldi	temp, CCP_IOREG_gc			; Prepare Protect IO-register signature in temp. 
	ldi	temp1, NVM_CMDEX_bm			; Prepare bitmask for setting NVM Command Execute bit into temp1. 
	STORE	CPU_CCP, temp				; Enable IO-register operation (this disables interrupts for 4 cycles). 
	STORE	NVM_CTRLA, temp1			; Load bitmask into NVM Control Register A, which executes the command. 
	LOAD	temp, NVM_DATA0				; Load NVM Data Register 0 into temp
; Can read other NVM_DATAx registers here if needed.
	rjmp	NVM_CMD_NO_OP

;Resets NVM to no operation and return
NVM_CMD_NO_OP:
	ldi	temp1, NVM_CMD_NO_OPERATION_gc
	STORE	NVM_CMD, temp1
	ret

; Wait until NVN is not busy.
nvm_wait_until_ready:
	SKBC	NVM_STATUS, NVM_NVMBUSY_bp, temp2	; Is NVM ready?
	rjmp	nvm_wait_until_ready
	ret

 

 

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Fri. May 15, 2015 - 10:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is odd that the definitions you want are in iox64a3u.h, especially since they're fundamentally incorrect (the signature bytes are NOT in the SFR memory space!)

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As you said, it's my misunderstanding to think that the CAL values are visible at fixed addresses at first.

They're actually in a seperate memory space. I should take clawson's suggestions to use the offsetof() approach

or the NVM controller. Because every chip has it's own unique CAL values so it's the last resort to use PDI Programmer

to get a CAL value and then write it back into EEPROM or store it into a variable and I'll become so tired to prepare CAL values for

every xmega chip. So is it the right understanding?