AVR EEPROM read, write and update routines for Arduino.
This is a demonstration of inline assembly functions for Arduino. As well there is disassembly of each function get by avr-objdump tool.
There are many similar functions like these around. Update function tries to limit writes to EEPROM as much possible and write or erase each
cell only when it is necessary. The details are in ATmega datasheets.
void setup()
{
asm volatile(
" .equ EECR, 0x1f \n"
" .equ EEDR, 0x20 \n"
" .equ EEARL, 0x21 \n"
" .equ EEARH, 0x22 \n"
" .equ SREG, 0x3f \n"
" .equ EERE, 0 \n"
" .equ EEPE, 1 \n"
" .equ EEMPE, 2 \n"
" .equ EERIE, 3 \n"
" .equ EEPM0, 4 \n"
" .equ EEPM1, 5 \n"
:::
);
}
// =====================================
// ========== EEPROM routines ==========
// =====================================
byte EEPROM_Read(word address)
{
byte value;
asm volatile(
"0: sbic EECR, EEPE \n"
" rjmp 0b \n"
" out EEARH, %B1 \n"
" out EEARL, %A1 \n"
" sbi EECR, EERE \n"
" in %0, EEDR \n"
: "=r" (value)
: "r" (address)
:
);
return value;
}
/*
0000012a <_Z11EEPROM_Readj>:
12a: f9 99 sbic 0x1f, 1 ; 31
12c: fe cf rjmp .-4 ; 0x12a <_Z11EEPROM_Readj>
12e: 92 bd out 0x22, r25 ; 34
130: 81 bd out 0x21, r24 ; 33
132: f8 9a sbi 0x1f, 0 ; 31
134: 80 b5 in r24, 0x20 ; 32
136: 08 95 ret
*/
void EEPROM_WriteEx(word address, byte value, byte flags)
{
asm volatile(
"0: sbic EECR, EEPE \n"
" rjmp 0b \n"
" out EEARH, %B0 \n"
" out EEARL, %A0 \n"
" out EEDR, %1 \n"
" in __tmp_reg__, SREG \n"
" cli \n"
" out EECR, %2 \n"
" sbi EECR, EEMPE \n"
" sbi EECR, EEPE \n"
" out SREG, __tmp_reg__ \n"
:
: "r" (address), "r" (value), "r" (flags)
:
);
}
/*
00000138 <_Z14EEPROM_WriteExjhh>:
138: f9 99 sbic 0x1f, 1 ; 31
13a: fe cf rjmp .-4 ; 0x138 <_Z14EEPROM_WriteExjhh>
13c: 92 bd out 0x22, r25 ; 34
13e: 81 bd out 0x21, r24 ; 33
140: 60 bd out 0x20, r22 ; 32
142: 0f b6 in r0, 0x3f ; 63
144: f8 94 cli
146: 4f bb out 0x1f, r20 ; 31
148: fa 9a sbi 0x1f, 2 ; 31
14a: f9 9a sbi 0x1f, 1 ; 31
14c: 0f be out 0x3f, r0 ; 63
14e: 08 95 ret
*/
void EEPROM_Erase(word address)
{
EEPROM_WriteEx(address, 0, 1 << EEPM0);
}
/*
00000150 <_Z12EEPROM_Erasej>:
150: 40 e1 ldi r20, 0x10 ; 16
152: 60 e0 ldi r22, 0x00 ; 0
154: 0c 94 9c 00 jmp 0x138 ; 0x138 <_Z14EEPROM_WriteExjhh>
*/
void EEPROM_WriteOnly(word address, byte value)
{
EEPROM_WriteEx(address, value, 1 << EEPM1);
}
/*
00000158 <_Z16EEPROM_WriteOnlyjh>:
158: 40 e2 ldi r20, 0x20 ; 32
15a: 0c 94 9c 00 jmp 0x138 ; 0x138 <_Z14EEPROM_WriteExjhh>
*/
void EEPROM_Write(word address, byte value)
{
EEPROM_WriteEx(address, value, 0);
}
/*
0000015e <_Z12EEPROM_Writejh>:
15e: 40 e0 ldi r20, 0x00 ; 0
160: 0c 94 9c 00 jmp 0x138 ; 0x138 <_Z14EEPROM_WriteExjhh>
*/
// if following routine calls EEPROM_WriteEx directly with relevant arguments
// it'd be less illustrative - but the compiled code would be shorter
void EEPROM_Update(word address, byte value)
{
byte oldvalue = EEPROM_Read(address);
if (oldvalue != value)
{
if (value == 0xff)
{
EEPROM_Erase(address); // Erase
}
else
{
if ((oldvalue & value) == value) // only zeroes are to be written
EEPROM_WriteOnly(address, value); // Write only
else
EEPROM_Write(address, value); // Erase & write
}
}
}
/*
00000164 <_Z13EEPROM_Updatejh>:
164: 1f 93 push r17
166: cf 93 push r28
168: df 93 push r29
16a: ec 01 movw r28, r24
16c: 16 2f mov r17, r22
16e: 0e 94 95 00 call 0x12a ; 0x12a <_Z11EEPROM_Readj>
172: 81 17 cp r24, r17
174: c9 f0 breq .+50 ; 0x1a8 <_Z13EEPROM_Updatejh+0x44>
176: 1f 3f cpi r17, 0xFF ; 255
178: 31 f4 brne .+12 ; 0x186 <_Z13EEPROM_Updatejh+0x22>
17a: ce 01 movw r24, r28
17c: df 91 pop r29
17e: cf 91 pop r28
180: 1f 91 pop r17
182: 0c 94 a8 00 jmp 0x150 ; 0x150 <_Z12EEPROM_Erasej>
186: 68 2f mov r22, r24
188: 61 23 and r22, r17
18a: 61 13 cpse r22, r17
18c: 06 c0 rjmp .+12 ; 0x19a <_Z13EEPROM_Updatejh+0x36>
18e: ce 01 movw r24, r28
190: df 91 pop r29
192: cf 91 pop r28
194: 1f 91 pop r17
196: 0c 94 ac 00 jmp 0x158 ; 0x158 <_Z16EEPROM_WriteOnlyjh>
19a: 61 2f mov r22, r17
19c: ce 01 movw r24, r28
19e: df 91 pop r29
1a0: cf 91 pop r28
1a2: 1f 91 pop r17
1a4: 0c 94 af 00 jmp 0x15e ; 0x15e <_Z12EEPROM_Writejh>
1a8: df 91 pop r29
1aa: cf 91 pop r28
1ac: 1f 91 pop r17
1ae: 08 95 ret
*/
// =====================================
// ====== end of EEPROM routines =======
// =====================================