EEPROM **Hardware Level** programming ( 2560 Mega)

Hello all!

Brief history: been using the arduino for college. Been only using hard ware level programming. AKA accessing everything from scratch. Such as creating my own functions for serial capabilities.

Here's the question. And I have read through the manual on this, but my code for the write function, just is not working. I am really sure I got the sequence correct. However, the darn thing just will not write.

Any ideas?

void EepromWrite(unsigned short address, unsigned char data)
{
while( *myEECR & 0x02){}//wait for completion of previous write//

// defining which addres to be written to
*myEEARhigh= 0x00;
*myEEARlow = 0x01;

*myEEDR = data;// putting data in temp reg

*myEECR |= 0x04;// writing 1 to EEMPE bit

*myEECR |= 0x02;// now writing to EEPE bit which starts write

}
Here are the declarations of registers:
/////////////////////////////////////////////////////////////////
//EEPROM REG
////////////////////////////////////////////////////////////////
//Where the adresses live to store data
volatile unsigned char myEEARlow = (unsigned char) 0x41;
volatile unsigned char myEEARhigh = (unsigned char) 0x42;
//EEPROM control register
volatile unsigned char myEECR = (unsigned char) 0x3F;
//where the value is stored before it goes into the EEPROM storage address
volatile unsigned char myEEDR = (unsigned char) 0x40;

Anyone who can help will help my understanding I thank in advance. BTW the assignment is over. So take your time... :grin:

Writing to EEPROM involves a timed sequence. Does your code execute within the time limit?

It looks like an examle from datasheet. Try EEARH 0x22; EEARL 0x21; EEDR 0x20; EECR 0x1F instead.

Yes the sequence should be within 4 cycles. I imagine these executions happen within a mater of a fraction of micro seconds.

As for those Hex values Budvar10; are you suggestion I try the other addresses given in the data sheet, instead of where I declared their homes already? Because there are generally two addressees given for each register within the manual.

I imagine these executions happen within a mater of a fraction of micro seconds.

The time the processor takes to execute those instructions is irrelevant. For example, if the processor is running from a 1 Hz clock it will take more than four seconds to write to the EEPROM.

The number of cycles is what is important.

Capt_Rhizz:
Yes the sequence should be within 4 cycles.

In other words, you took no action, exerted no effort, to verify your assumption is correct. If you had, you would know the answer to the question is "no".

...are you suggestion I try the other addresses given in the data sheet, instead of where I declared their homes already?

The compiler has enough intelligence to use the lower addresses when appropriate.

• Bit 2 – EEMPE: EEPROM Master Programming Enable
The EEMPE bit determines whether setting EEPE to one causes the EEPROM to be written.
When EEMPE is set, setting EEPE within four clock cycles will write data to the EEPROM at the
selected address If EEMPE is zero, setting EEPE will have no effect. When EEMPE has been
written to one by software, hardware clears the bit to zero after four clock cycles. See the
description of the EEPE bit for an EEPROM write procedure.

Ok, so what "point" are you trying to drive? I don't think I am following.... :~

This is the code that has to execute within four clock cycles...

  *myEECR |= 0x04;// writing 1 to EEMPE bit
  *myEECR |= 0x02;// now writing to EEPE bit which starts write

This is the resulting assembly...

  ec:	e0 91 04 01 	lds	r30, 0x0104
  f0:	f0 91 05 01 	lds	r31, 0x0105
  f4:	80 81       	ld	r24, Z
  f6:	84 60       	ori	r24, 0x04	; 4
  f8:	80 83       	st	Z, r24

  fa:	e0 91 04 01 	lds	r30, 0x0104
  fe:	f0 91 05 01 	lds	r31, 0x0105
 102:	80 81       	ld	r24, Z
 104:	82 60       	ori	r24, 0x02	; 2
 106:	80 83       	st	Z, r24

Between the two st(ore) instructions and including one st(ore) is the important part. The first st(ore) sets the EEMPE bit. The second st(ore) sets the EEPE bit. Instruction timing, in cycles, is available in the datasheet. What are the total cycles?

This is me going out on a limb here... 10 cycles? I am just guessing that each line is an instruction and an instruction is a cycle? And if this is so, it took 5 cycles between the bit operations.

My teacher made us produce this assembly, but never went over its significance nor how to read it. So I guess I am lost again on this one. Not very familiar with assembly. More the C language level. You sure are making me work for this one Baldly. Which I do appreciate, yet I am still unfortunately not understanding. :%

Capt_Rhizz:
I am just guessing...

Guessing leads to a crashed Mars rover.

I told you the important instruction: "st". There are two "st" instructions in the listing. What instructions are between the two "st" instructions?

Ahh yes, but guessing also leads to more thought provoking answers in the form of questions. :zipper_mouth_face:

It seems to me there are 4 instructions between the two (st)ore instuctions: ldr, ldr, ld, ori... I myself do not know how to interpret assembly language. So if you don't mind me asking? What is the significance of these in-between instructions? And how do we know how long these instructions are taking in cycles. I tried looking for it on the 2560 ATmel manual but no look so far. I digress and will continue to search though..

Also if we are outside the given parameters (in this case 4 clock cycles), how can we correct for this error? Do we have to do something with the produced assembly language?? Thank you in advance for any help.

TheArchitect22:
It seems to me there are 4 instructions between the two (st)ore instuctions: ldr, ldr, ld, ori... I myself do not know how to interpret assembly language. So if you don't mind me asking? What is the significance of these in-between instructions? And how do we know how long these instructions are taking in cycles. I tried looking for it on the 2560 ATmel manual but no look so far. I digress and will continue to search though..

Instruction set summary, page 404

From some searching around on the internets. I saw that each instruction should be added together, then multiplied by 2.5. So if what I am thinking is correct and that is for each St or store instruction; it is taking up 2.5 clock cylcles. So if those are the only instructions then the total would be 5 cycles and we would thus be over the given time.

So how is this corrected. Can I just do this:

FROM:
*myEECR |= 0x04;// writing 1 to EEMPE bit

*myEECR |= 0x02;// now writing to EEPE bit which starts write

TO:
*myEECR |=06;

Then it would be done it one instruction? But not in a sequence...

I feel a bronze star for effort coming.. :cold_sweat:

It looks like an examle from datasheet. Try EEARH 0x22; EEARL 0x21; EEDR 0x20; EECR 0x1F instead.

...are you suggestion I try the other addresses given in the data sheet, instead of where I declared their homes already?

The compiler has enough intelligence to use the lower addresses when appropriate.

Yes, that is exactly true. It does'n matter which addresses are used.

I 've tried to compile the code from datasheet and Capt_Rhizz code also in AtmelStudio and both worked.

	while(EECR & (1 << EEPE));
000001AF  SBIC 0x1F,1		Skip if bit in I/O register cleared 
000001B0  RJMP PC-0x0001		Relative jump 
	EEAR = 1;
000001B1  LDI R24,0x01		Load immediate 
000001B2  LDI R25,0x00		Load immediate 
000001B3  OUT 0x22,R25		Out to I/O location 
000001B4  OUT 0x21,R24		Out to I/O location 
	EEDR = 0x55;
000001B5  LDI R24,0x55		Load immediate 
000001B6  OUT 0x20,R24		Out to I/O location 
	EECR |= (1 << EEMPE);
000001B7  SBI 0x1F,2		Set bit in I/O register 
	EECR |= (1 << EEPE);
000001B8  SBI 0x1F,1		Set bit in I/O register 


	while(*myEECR & 0x02) {}
000001B9  SBIC 0x1F,1		Skip if bit in I/O register cleared 
000001BA  RJMP PC-0x0001		Relative jump 
	*myEEARhigh = 0;
000001BB  OUT 0x22,R1		Out to I/O location 
	*myEEARlow  = 1;
000001BC  LDI R24,0x01		Load immediate 
000001BD  OUT 0x21,R24		Out to I/O location 
	*myEEDR     = 0xAA;
000001BE  LDI R24,0xAA		Load immediate 
000001BF  OUT 0x20,R24		Out to I/O location 
	*myEECR    |= 0x04;
000001C0  SBI 0x1F,2		Set bit in I/O register 
	*myEECR    |= 0x02;
000001C1  SBI 0x1F,1		Set bit in I/O register

AWOL:

TheArchitect22:
It seems to me there are 4 instructions between the two (st)ore instuctions: ldr, ldr, ld, ori... I myself do not know how to interpret assembly language. So if you don't mind me asking? What is the significance of these in-between instructions? And how do we know how long these instructions are taking in cycles. I tried looking for it on the 2560 ATmel manual but no look so far. I digress and will continue to search though..

http://www.atmel.com/Images/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf
Instruction set summary, page 404

Thanks for the help AWOL. If I was understanding the datasheet correctly it seems we are taking 7 clock cycles to complete the instructions in between the two "st(ore)" instructions, which is over the required limit of within 4 clock cycles. But then how can we correct for this? What do we need to do to get it to within the specified limit of 4 clock cycles. Any help would be appreciated, thank you all. By the way my background is not in CS or computer engineering, i'm just trying to learn. Thank you all for helping.

Budvar10:

It looks like an examle from datasheet. Try EEARH 0x22; EEARL 0x21; EEDR 0x20; EECR 0x1F instead.

...are you suggestion I try the other addresses given in the data sheet, instead of where I declared their homes already?

The compiler has enough intelligence to use the lower addresses when appropriate.

Yes, that is exactly true. It does'n matter which addresses are used.

I 've tried to compile the code from datasheet and Capt_Rhizz code also in AtmelStudio and both worked.

	while(EECR & (1 << EEPE));

000001AF  SBIC 0x1F,1 Skip if bit in I/O register cleared
000001B0  RJMP PC-0x0001 Relative jump
EEAR = 1;
000001B1  LDI R24,0x01 Load immediate
000001B2  LDI R25,0x00 Load immediate
000001B3  OUT 0x22,R25 Out to I/O location
000001B4  OUT 0x21,R24 Out to I/O location
EEDR = 0x55;
000001B5  LDI R24,0x55 Load immediate
000001B6  OUT 0x20,R24 Out to I/O location
EECR |= (1 << EEMPE);
000001B7  SBI 0x1F,2 Set bit in I/O register
EECR |= (1 << EEPE);
000001B8  SBI 0x1F,1 Set bit in I/O register

while(*myEECR & 0x02) {}

000001B9  SBIC 0x1F,1 Skip if bit in I/O register cleared
000001BA  RJMP PC-0x0001 Relative jump
*myEEARhigh = 0;
000001BB  OUT 0x22,R1 Out to I/O location
*myEEARlow  = 1;
000001BC  LDI R24,0x01 Load immediate
000001BD  OUT 0x21,R24 Out to I/O location
*myEEDR     = 0xAA;
000001BE  LDI R24,0xAA Load immediate
000001BF  OUT 0x20,R24 Out to I/O location
*myEECR    |= 0x04;
000001C0  SBI 0x1F,2 Set bit in I/O register
*myEECR    |= 0x02;
000001C1  SBI 0x1F,1 Set bit in I/O register

Yes, the code compiles for me as well (using Arduino Compiler) but EEPROM_write function does not write to an EEPROM address like it is suppose to. And I believe it is because of the reason AWOL and CodingBadly are pointing out: that the logic 1 flipping of the EEMPE bit and EEPE bit are not occuring within the specified time limit (4 clock cycles). If i read the datasheet correctly, it is taking 7 clock cycles. By the way, my custom EEPROM_read function works, tested it using the built-in EEPROM.write() function from the EEPROM.h, it is just that my custom EEPORM_write() function is not working properly.

By the way here is my code: The Read function works just not the Write function..

void EEPROM_write(unsigned char eeData)
{

while (*myEECR & EPE); //Wait for completion of previous write

//while (*mySPMCSR & SPM){};

*myEEARH = 0x00;
*myEEARL = 0x01; //set up address and data registers

*myEEDR = eeData;

*myEECR |= MPE; //write logical one to EEMPE
*myEECR |= EPE; //Start eeprom by writing logic one to EEPE

}

unsigned char EEPROM_read()
{

while (*myEECR & EPE){}; //wait for completion of previous write

*myEEARH = 0x00;
*myEEARL = 0x01; //set up address register

*myEECR |= ERE; //Start EEPROM Read by writing logic one to EERE

return *myEEDR;

}

My # defines are as follows:

#define EPE 0x02
#define MPE 0x04
#define ERE 0x01

I narrowed down my problem to my EEPROM_write() function..

Capt_Rhizz:
From some searching around on the internets. I saw that each instruction should be added together...

The number of clock cycles for each instruction should be added together for a total number of clock cycles. Correct.

...then multiplied by 2.5.

Why on Earth would you do that?

Can I just do this:
FROM:
*myEECR |= 0x04;// writing 1 to EEMPE bit
*myEECR |= 0x02;// now writing to EEPE bit which starts write
TO:
*myEECR |=06;

No. The datasheet is very clear. The bits must be set separately, in sequence, within four clock cycles.

Then it would be done it one instruction?

Correct. Which is why it will not work.

I feel a bronze star for effort coming.. :cold_sweat:

Sounds good to me.

TheArchitect22:
If I was understanding the datasheet correctly it seems we are taking 7 clock cycles to complete the instructions in between the two "st(ore)" instructions...

lds --> 2
lds --> 2
ld  --> 2
ori --> 1

You did not include one of the st(ore) instructions in the total. I did mention twice that is necessary.

...which is over the required limit of within 4 clock cycles.

In any case that is correct. The code takes too long to set the second bit.