Assembler code for EEPROM of ATxmega32E5

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

Here you could see proved ASSEMBLER subroutines for XMEGA EEPROM read and write. Many thanks for “clawson”, “kabasan” and "mojo-chan" prompt help!

 

.INCLUDE "ATxmega32E5def.inc"

...

;CAUTION: AtmelStudio Simulator does not support EEPROM access !!!

EER:   ;eeprom_read y=EEPROM address (0...1023); r16 <- EEPROM byte contents

       ldi    zl,low(NVM_BASE)    ; Load base address of NVM

       ldi    zh,high(NVM_BASE)

EER1:  ;Wait until NVM is not busy

       ldd    r16, z+NVM_STATUS_offset

       sbrc   r16,NVM_NVMBUSY_bp  ; Non-volatile Memory Busy bit position

       rjmp   EER1

;EEPROM of Xmega E family is always memory mapped=it is not required to enable EEPROM mapping explicitly

       subi   yl,low(-MAPPED_EEPROM_START)      ;Load y with correct EEPROM address to read EEPROM data space

       sbci   yh,high(-MAPPED_EEPROM_START)

       ld     r16,y  ;reading one byte from EEPROM

;It is possible to modify y here and to read other byte/bytes in EEPROM (regardless EEPROM page boundaries)

       ret

 

EEW:   ;eeprom_write: r18 -> EEPROM, y=EEPROM address (0...1023)

       ldi    zl,low(NVM_BASE)    ;Load base address of NVM

       ldi    zh,high(NVM_BASE)

EEW1:  ;Wait until NVM is not busy

       ldd    r16,z+NVM_STATUS_offset

       sbrc   r16,NVM_NVMBUSY_bp  ; Non-volatile Memory Busy bit position

       rjmp   EEW1

       ldd    r16,z+NVM_STATUS_offset    ;Check the clearance of EEPROM page buffer.

       sbrs   r16,NVM_EELOAD_bp   ; EEPROM Page Buffer Active Loading bit position

       rjmp   EEW3                ; erase is not required

             ;Issue EEPROM Buffer Erase:

       ldi    r16,NVM_CMD_ERASE_EEPROM_BUFFER_gc      ; 0x36 Erase/flush EEPROM Page Buffer

       std    z+NVM_CMD_offset,r16       ;Command

       ldi    r17,NVM_CMDEX_bm    ; Command Execute bit mask

       ldi    r16,CCP_IOREG_gc    ; IO Register Protection

       in     xl,CPU_SREG         ; preserve Global Interrupt Flag

       cli

       out    CPU_CCP,r16

       std    z+NVM_CTRLA_offset, r17

       out    CPU_SREG,xl         ;restore Global Interrupt Flag

EEW2:  ;Wait until NVM is not busy.

       ldd    r16,z+NVM_STATUS_offset

       sbrc   r16,NVM_NVMBUSY_bp  ; Non-volatile Memory Busy bit position

       rjmp   EEW2

EEW3:  ;Load EEPROM Page Buffer: store required number of bytes (max.32) into the EEPROM Page Buffer

       movw   x,y          ;preserve EEPROM address

       andi   yl,0x1F      ; EEPROM Page Size=32, yl = 0...31

       ldi    yh,0x10      ;EEPROM always starts at the hexadecimal address 0x1000

       st     y,r18  ; store 1 byte to EEPROM Bufferu

       ;Modify y and store more byte to EEPROM Buffer (current Page) if needed

NVM2g:

       ldd          r16,z+NVM_STATUS_offset

       sbrc   r16,NVM_NVMBUSY_bp  ; = 7 ; Non-volatile Memory Busy bit position

       rjmp   NVM2g

;EEPROM page erase & write routine

       movw   y,x          ;restore EEPROM address

       subi   yl,low(-MAPPED_EEPROM_START)

       sbci   yh,high(-MAPPED_EEPROM_START)

       clr          r1

       sts          NVM_ADDR0,yl ; ee_adr_l

       sts          NVM_ADDR1,yh ; ee_adr_h

       sts          NVM_ADDR2,r1 ; 0

       ldi          yl, NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc

       sts          NVM_CMD,yl

       ldi          yh, NVM_CMDEX_bm

       ldi          yl, CCP_IOREG_gc

       in           r16,CPU_SREG        ;preserve Global Interrupt Flag

       cli

       out          CPU_CCP, yl

       sts          NVM_CTRLA, yh

       out          CPU_SREG,r16        ;restore Global Interrupt Flag

       ret

Last Edited: Sun. Jul 22, 2018 - 07:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

This is a proven erase & write routine I used for many years in xmega32E5.
Your code seems to lack NVM_ADR setting.

	sts		NVM_ADDR0, r24	; ee_adr_l
	sts		NVM_ADDR1, r25	; ee_adr_h
	sts		NVM_ADDR02, r1	; 0
	ldi		r24, 0x35		; NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc
	sts		NVM_CMD, r24
	ldi		r25, 0x01		; NVM_CMDEX_bm
	ldi		r24, 0xD8		; CCP_IOREG_gc
	out		CPU_CCP, r24
	sts		NVM_CTRL, r25

 

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

I don't get it, your code is clearly (almost!) copied from the LibC code I pointed you to in the previous thread. Your code is now:

;eeprom_write_byte r19****************************************************************

       ldi    ZL,low(NVM_BASE)    ;Load base address of NVM
       ldi    ZH,high(NVM_BASE)
NVM1c:                            ;Wait until NVM is not busy
       ldd    r16, Z+NVM_STATUS_offset
       sbrc   r16,NVM_NVMBUSY_bp  ; = 7 ; Non-volatile Memory Busy bit position
       rjmp   NVM1c
       ldd    r16,Z+NVM_STATUS_offset    ;Check the clearance of EEPROM page buffer.
       sbrs   r16,NVM_EELOAD_bp   ; = 1 EEPROM Page Buffer Active Loading bit position
       rjmp   NVM3f               ; erase is not required
;Issue EEPROM Buffer Erase:
       ldi    r16,NVM_CMD_ERASE_EEPROM_BUFFER_gc      ;= (0x36<<0) ; Erase/flush EEPROM page buffer
ETC.

and yet the LibC  code that you started with was:

  ; Prepare base address of NVM.
	ldi	ZL, lo8(NVM_BASE)
	ldi	ZH, hi8(NVM_BASE)

  ; Wait until NVM is not busy.
1:	ldd	r19, Z + NVM_STATUS - NVM_BASE
	sbrc	r19, NVM_NVMBUSY_bp
	rjmp	1b

  ; Disable EEPROM mapping into data space.
	ldd	r19, Z + NVM_CTRLB - NVM_BASE
	andi	r19, ~NVM_EEMAPEN_bm
	std	Z + NVM_CTRLB - NVM_BASE, r19

  ; Check the clearance of EEPROM page buffer.
	ldd	r19, Z + NVM_STATUS - NVM_BASE
	sbrs	r19, NVM_EELOAD_bp
	rjmp	3f			; erase is not required

  ; Note that we have only four clock cycles to write to the CCP
  ; protected register NVM_CTRLA, after writing to CCP.  The 'ldi'
  ; instruction always takes one clock to execute and 'std' instruction takes
  ; two clock cycles.  We fall within the four cycles that the CCP leaves
  ; us to write the command execution start bit to the NVM_CTRLA
  ; register.  Note that r18 must be preserved until written to NVM_DATA0

  ; Issue EEPROM Buffer Erase:
	ldi	r19, NVM_CMD_ERASE_EEPROM_BUFFER_gc
ETC.

So it seemed you just arbitrarily dropped a part of the code?

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

Dear “kabasan”, thank you for you code; after reparation of two small mistakes (NVM_ADDR2, NVM_CTRLA) the assembler of Atmel Studio 7 enabled debugging. I work with “Simulator”. I modified the contents of some EEPROM bytes from 0xFF to different values, nevertheless the contents of EEPROM stay unchanged - it does not change to 0xFF after running of you code (r1,r25,r24=0x001000 or 0x000000). What could be wrong?

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

Dear “clawson”, thank for your reply. I am ashamed for my lack of knowledge. I can use only assembler, I have written code for ATtiny, ATmega (but without macros); it was useful to find examples of assembler code in documentations of those devices. It is completely different for ATxmega32E5. And assembler examples ee*.S files on the page http://svn.savannah.nongnu.org/v... include lot of terms (ENTRY, lo8, strange labels,...) I can not find in my “AVR assembler guide 40001917A.pdf” and / or which are not defined in Atmel Studio 7 assembler. This is the reason why I had to modify the example codes.

 

In case that you would be so kind and could to help me, at first I need to repair my code for eeprom_read_byte, because I have find, that this code reads still only the first byte in EEPROM regardless I changed the EEPROM location from eFA to eFA1:

.ESEG

.ORG  EEPROM_START

eFA:   .BYTE 1

eFA1:  .BYTE 1

...

;eeprom_read_byte ****************************************************************

       ldi    ZL,low(NVM_BASE)    ;Load base address of NVM

       ldi    ZH,high(NVM_BASE)

NVM1b:                            ;Wait until NVM is not busy

       ldd    r16, Z+NVM_STATUS_offset

       sbrc   r16,NVM_NVMBUSY_bp  ; = 7 ; Non-volatile Memory Busy bit position

       rjmp   NVM1b

;EEPROM OD Xmega E family is always memory mapped=it is not required to enable EEPROM mapping explicitly

       ldi    zl,low(eFA1) ;Load Z with correct EEPROM address to read from data space

       ldi    zh,high(eFA1)

       subi   ZL,low(-MAPPED_EEPROM_START)

       sbci   ZH,high(-MAPPED_EEPROM_START)

       ld     r16,z  ;reading one byte from EEPROM

 

Note, that I work with “Simulator” of Atmel Studio 7 to develop code for EEPROM. Other code I already tested with my target and AVR JTAG ICE mkII.

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

EEPROM access is not reflected in the simulator.

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

Many thanks, I will apply the code in my target...