;**** A P P L I C A T I O N   N O T E   A V R 1 0 0  ************************
;*
;* Title:		Accessing the EEPROM
;* Version:		2.0
;* Last updated:	98.10.14
;* Target:		AT90S8515
;* Suitable for:	Any AVR with internal EEPROM
;*
;* Support E-mail:	avr@atmel.com
;*
;* DESCRIPTION
;* This Application note shows how to read data from and write data to the
;* EEPROM. Both random access and sequential access routines are listed.
;* The code is written for 8515. To modify for 90S4414,90S2313,90S2323...
;* apply the following changes:
;*	- Remove all entries to EEPROM Address Register High Byte EEARH
;*
;* To modify for 90S1200, apply the changes above. In addition:
;*	- Remove all writes to EEMWE
;*
;*
;* Change log
;*	V2.0	98.10.14 (jboe)		Bugfix, changed to support AT90S8515 
;*	V1.1	97.07.04 (gk)		Created
;***************************************************************************
.include "8515def.inc"

	rjmp	RESET		;Reset Handle
	
;***************************************************************************
;* 
;* EEWrite
;*
;* This subroutine waits until the EEPROM is ready to be programmed, then
;* programs the EEPROM with register variable "EEdwr" at address "EEawr:EEawr"
;*
;* Number of words	: 9 + return
;* Number of cycles	: 11 + return (if EEPROM is ready)
;* Low Registers used	: None
;* High Registers used:	; 3 (EEdwr,EEawr,EEawrh)
;*
;***************************************************************************

;***** Subroutine register variables

.def	EEdwr	=r16		;data byte to write to EEPROM
.def	EEawr	=r17		;address low byte to write to
.def	EEawrh	=r18		;address high byte to write to

;***** Code

EEWrite:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EEWrite		;    wait more

	out 	EEARH,EEawrh	;output address high byte, remove if no high byte exists
	out	EEARL,EEawr	;output address low byte
		

	out	EEDR,EEdwr	;output data
	cli			;disable global interrupts	
	sbi 	EECR,EEMWE	;set master write enable, remove if 90S1200 is used	
	sbi	EECR,EEWE	;set EEPROM Write strobe
				;This instruction takes 4 clock cycles since
				;it halts the CPU for two clock cycles
	sei			;enable global interrupts
	ret

;***************************************************************************
;* 
;* EERead
;*
;* This subroutine waits until the EEPROM is ready to be programmed, then
;* reads the register variable "EEdrd" from address "EEardh:EEard"
;*
;* Number of words	: 6 + return
;* Number of cycles	: 7 + return (if EEPROM is ready)
;* Low Registers used	: 1 (EEdrd)
;* High Registers used:	: 2 (EEard,EEardh)
;*
;***************************************************************************

;***** Subroutine register variables

.def	EEdrd	=r0		;result data byte
.def	EEard	=r17		;address low to read from
.def	EEardh	=r18		;address high to read from

;***** Code

EERead:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EERead		;    wait more

	out 	EEARH,EEardh	;output address high byte, remove if no high byte exists
	out	EEARL,EEard	;output address low byte


	sbi	EECR,EERE	;set EEPROM Read strobe
				;This instruction takes 4 clock cycles since
				;it halts the CPU for two clock cycles
	in	EEdrd,EEDR	;get data
	ret

		
;***************************************************************************
;* 
;* EEWrite_seq
;*
;* This subroutine increments the EEPROM address by one and waits until the 
;* EEPROM is ready for programming. It then programs the EEPROM with 
;* register variable "EEdwr_s".

;* Number of words	: 12 + return
;* Number of cycles	: 15 + return (if EEPROM is ready)
;* Low Registers used	: None
;* High Registers used:	: 3 (EEdwr_s,EEwtmp,EEwtmph)
;*
;***************************************************************************

;***** Subroutine register variables

.def	EEwtmp	=r24		;temporary storage of address low byte
.def	EEwtmph	=r25		;temporary storage of address high byte
.def	EEdwr_s	=r18		;data to write

;***** Code

EEWrite_seq:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EEWrite_seq	;   wait more

	in	EEwtmp,EEARL	;get address low byte
	in	EEwtmph,EEARH	;get address high byte, remove if no high byte exists
 	adiw	EEwtmp,0x01	;increment address
	out	EEARL,EEwtmp	;output address low byte
	out	EEARH,EEwtmph	;output address byte, remove if no high byte exists
	

	out	EEDR,EEdwr_s	;output data
	cli			;disable global interrupts
	sbi 	EECR,EEMWE	;set master write enable, remove if 90S1200 is used	
	sbi	EECR,EEWE	;set EEPROM Write strobe
				;This instruction takes 4 clock cycles since
				;it halts the CPU for two clock cycles
	sei			;enable global interrupts
	ret

;***************************************************************************
;* 
;* EERead_seq
;*
;* This subroutine increments the address stored in EEAR and reads the 
;* EEPROM into the register variable "EEdrd_s".

;* Number of words	: 9 + return
;* Number of cycles	: 13 + return (if EEPROM is ready)
;* Low Registers used	: 1 (EEdrd_s)
;* High Registers used:	: 2 (EErtmp,EErtmph)
;*
;***************************************************************************

;***** Subroutine register variables

.def	EErtmp	=r24		;temporary storage of low address
.def	EErtmph	=r25		;temporary storage of high address
.def	EEdrd_s	=r0		;result data byte

;***** Code

EERead_seq:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EERead_seq	;   wait more
; The above sequence for EEWE = 0 can be skipped if no write is initiated.

; Read sequence
	in	EErtmp,EEARL	;get address low byte
	in	EErtmph,EEARH	;get address high byte, remove if no high byte exists
	adiw	EErtmp,0x01	;increment address
	out	EEARL,EErtmp	;output address low byte
	out	EEARH,EErtmph	;output address high byte, remove if no high byte exists


	sbi	EECR,EERE	;set EEPROM Read strobe
				;This instruction takes 4 clock cycles since
				;it halts the CPU for two clock cycles
	in	EEdrd_s,EEDR	;get data
	ret



;****************************************************************************
;*
;* Test/Example Program
;*
;****************************************************************************

;***** Main Program Register variables

.def	counter	=r19
.def	temp	=r20

;***** Code

RESET:
;***** Initialize stack pointer
;* Initialize stack pointer to highest address in internal SRAM
;* Comment out for devices without SRAM

	ldi	r16,high(RAMEND) ;High byte only required if 
	out	SPH,r16	         ;RAM is bigger than 256 Bytes
	ldi	r16,low(RAMEND)	 
	out	SPL,r16

;***** Initialize portB
;* Port B is used to verify the operation of the EEPROM read 
;* and write routines.

	ldi	r16,0xff	; DDRB=0xff ->PortB=output
	out	DDRB,r16

;***** Initialize portD
; bit0 of PortD  is used to start the test program

	ldi	r16,0xff	; Enable all PortD pull-ups
	out	PORTD,r16

;***** Program start 
;*
 
main:	in	r16,PIND	; Wait for user to push button on PD0
	sbrc	r16,0
	rjmp	main



;***** Program a random location

	ldi	EEdwr,$aa
	ldi	EEawrh,$00
	ldi	EEawr,$10
	rcall	EEWrite		;store $aa in EEPROM location $0010

;***** Read from a random location

	ldi	EEardh,$00
	ldi	EEard,$10
	rcall	EERead		;read address $10
	out	PORTB,EEdrd	;output value to Port B

;***** Fill the EEPROM address 1..64 with bit pattern $55,$aa,$55,$aa,...

EEWrite_wait:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EEWrite_wait	;   wait more
; The above sequence for EEWE = 0 can be skipped if it is guaranteed that no write is
; running when now changing the EEARL and EEARH registers.

	ldi	counter,63	;init loop counter
	clr 	temp
	out	EEARH,temp	;EEARH <- $00
	clr	temp		
	out	EEARL,temp	;EEARL <- $00 (start address - 1)

loop1:	ldi	EEdwr_s,$55	
	rcall	EEWrite_seq	;program EEPROM with $55
	ldi	EEdwr_s,$aa		
	rcall	EEWrite_seq	;program EEPROM with $aa
	dec	counter		;decrement counter
	brne	loop1		;and loop more if not done

;***** Copy 10 first bytes of EEPROM to r1-r11

EERead_wait:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EERead_wait	;   wait more
; The above sequence for EEWE = 0 can be skipped if it is guaranteed that no write is
; running when we later change the EEARL and EEARH registers.

	clr 	temp
	out	EEARH,temp	;EEARH <- $00
	ldi	temp,$00	
	out	EEARL,temp	;EEARL <- $00 (start address - 1)

	clr 	ZH
	ldi	ZL,1		;Z-pointer points to r1

loop2:	rcall	EERead_seq	;get EEPROM data
	st	Z,EEdrd_s	;store to SRAM
	inc	ZL
	cpi	ZL,12		;reached the end?
	brne	loop2		;if not, loop more

forever:
	rjmp	forever		;This is the end. On completion, the program ends up here
