writing and reading data to eeprom 24aa01

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

Hi all,

 

Stuck in the implmentation of the TWI in the avr im posting the code please go through and guide me.

 

 

 

#include <avr/io.h>
#include <util/delay.h>
void i2c_int()
{
	TWSR=0x00;
	TWBR=0x0C;                                  // set the 400K
	TWCR|=(1<<TWEN);                            // set enable only
	
}
void wait(void)
{
	while(!(TWCR& (1<<TWINT)));                 // wait condition to check the twint flag
}
void Str(void)
{
	TWCR|= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN));   // start condition setting bits twint, start, enable
	wait();
}
void sto(void)
{
	TWCR|= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);;	// stop condition
	wait();
}

void write(unsigned int x)
{
	
	TWDR=x;	
	TWCR|=((1<<TWINT)|(1<<TWEN));
	wait();
	TWDR=0x00;
}

void read()
{
	TWCR|=((1<<TWINT)|(1<<TWEN)|(0<<TWEA));
	wait();
	PORTB=TWDR;
	TWDR=0x00;	
}
int main(void)
{
	DDRB=0xff;	// setting port b as output
        i2c_int(); 
 	Str();		// start condition
 	write(0xAE);	// 10101110 [1010 address of slave, XXX dont care 0 write] -frame format
  	write(0x00);	// address pointer
  	write(0xff);	// data
    sto();
//  _delay_ms(1000);
  	Str();		// start
 	write(0xAE);	// 10101110 write condition
 	write(0x00);	// read data
        sto();
	Str();	        //  start
 	write(0xAF);	// 10101111 READ MODE
 	read();
	sto();		// stop

}
Last Edited: Tue. Jul 18, 2017 - 12:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please replace all your magic values with the official BIT_NAMES from the Atmel datasheet.
And post neatly formatted code in a CODE window. i.e. click the < /> icon
.
Then readers might give you some advice.
.
David.
.

Last Edited: Sat. Jul 15, 2017 - 06:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A quick clean-up of your post using the code ("<>") formatter:

 

#include <avr/io.h>
#include <util/delay.h>
#define Start 0xA4
#define stop 0x94

void i2c_int()
{
  TWSR=0x00;
  TWBR=0x0C;  // set the 400K
  TWCR=0x04;  // set enable only
}

void wait(void)
{
  while(!(TWCR& (1<<TWINT))); // wait condition to check the twint flag
}

void Str(void)
{
  TWCR=0b10100100;   // start condition setting bits twint, start, enable
  wait();
}

void sto(void)
{
  TWCR=stop; // stop condition
  wait();
}

void write(unsigned int x)
{
  TWDR=x;
  TWCR=0x84;
  wait();
  TWDR=0x00;
}

void read(unsigned char y)
{
  TWCR&=0xC4;
  PORTB=TWDR;
  TWDR=0x00;
}

int main(void)
{
  DDRB=0xff;      // setting port b as output
  i2c_int();
  Str();          // start condition
  write(0xAE);    // 10101110 [1010 address of slave, XXX dont, mind 0 write] -frame format
  write(0x01);    // address pointer
  write(0xff);    // data
  Str();          // repeated start
  write(0xAF);    // 10101111 read condition
  read(0x01);     // read data
  sto();          // stop
}

 

Except the use of magic numbers, there is a big issue with this code: it returns from main. I suggest you change the code to do a single access and then just hang in a while-loop.

 

EDIT: also note that Atmel provides example code for TWI usage (AVR311, AVR315, etc) and AVR Libc also contains an example implementation ("twitest") for write/read to 24Cxx devices.

 

EDIT 2: you should also provide a better explanation other than "stuck in implementation". Did you test the code? What is the result? What did you expect? Looks like you use PORTB for showing the data read from the I2C device. 

/Jakob Selbing

Last Edited: Sat. Jul 15, 2017 - 07:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I regret the inconvenience caused Sir.

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

Yes im trying to write the data 0xff at the 0x01 location of the eeprom and want to read the data from same location and display that on port b, there arent any errors in the code.

 

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

hshubh wrote:

Yes im trying to write the data 0xff at the 0x01 location of the eeprom and want to read the data from same location and display that on port b, there arent any errors in the code.

So what DO you get on PORTB?

/Jakob Selbing

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

It would take you 5 minutes to tidy your code as I suggested in #2.
.
You would then make progress.
.
David.

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

Why do folks feel the need to reinvent TWI code when they could just use the Fleury library code?

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

No it's displaying nothing on portB. The output ion port B is 0x00.

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

Have elaborated the bits that are been set respective register. Anything else were I tidy the code?

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

I presume that there is a school out there that sets this as a standard assignment.

 

I would guess that the easiest way for a student to do this would be by reading Fleury.

 

If I was "marking" the assignment,   I would be perfectly happy with a direct copy of Fleury with "added explanatory comments" in the student's native language.

There is no such thing as plagiarism in "engineering".   But you do need to show your teacher that you understand the code.

 

David.

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

So, if the assignment is to do this from "first principles", this is the approach to take:

 

How To Interface Anything to Anything Else

 

But you should certainly be making use of available supporting resources - such as the Application Notes & Examples mentioned in #3

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

hshubh wrote:
TWCR&=0xC4; // making high bits TWINT,TWEA,TWEN
That line will effectively clear all bits but TWINT, TWEA and TWEN so that may not work as intended.

 

hshubh wrote:
No it's displaying nothing on portB. The output ion port B is 0x00.
So value 0x00 is "nothing"? How do you physically "read" that value on the port? Do you use LEDs? Are they wired active-low or active-high?

 

Also, a piece of advice. Your code does not check the ACK status after first SLA+W. That should really be the FIRST thing to debug. If the slave does not ACK the SLA+W then it does not matter what the rest of the code does.

/Jakob Selbing

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

jaksel wrote:

hshubh wrote:

TWCR&=0xC4; // making high bits TWINT,TWEA,TWEN

 

 

@jaksel,

 

hshubhh has made no effort to use the BIT_NAMEs e.g. TWINT,TWEA,TWEN

 

I suggest that you wait until he shows some attempt to write the code properly.

 

There is no point in offering help until he actually reads the advice.   

 

David.

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

clawson wrote:
Why do folks feel the need to reinvent TWI code when they could just use the Fleury library code?
david.prentice wrote:
I presume that there is a school out there that sets this as a standard assignment.

I guess that would negate my question -- why bother to hook a 128 byte part of external storage with a slow interface to a device that has at least that much EEPROM built in?

 

So retro. ;)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Yes,  it is extremely unlikely that anyone would use a 24AA01 nowadays.

 

However it is considerably faster than the AVR EEPROM.    The 8-byte EEPROM page is written in less time than the AVR takes to write one single byte.    Yes,  it is faster to read the AVR EEPROM.

 

I always find it a mystery that a student will take days to try to get her assignment work done for her.

When with 5 minutes effort,  she could actually learn how to do it herself (with help from the forum).

 

David.

Last Edited: Sat. Jul 15, 2017 - 02:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What exactly you need I'm not getting please take a look at the code I have done changes that you have suggested please let me know what else you expect so I can add on those too.

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

It's not an assignment I'm just trying to learn the concept in my free time n doing it by myself.. I'm aware it's of no use willing to learn.

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

hshubh wrote:
I have done changes that you have suggested
Where can we see these changes?

David (aka frog_jr)

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

It's not an assignment I'm just trying to learn the concept in my free time n doing it by myself.. I'm aware it's of no use willing to learn.

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

He had asked to change the numbers by bits I did the same in comments of the code n wrote the code in<>. As suggested

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

I was suggesting that you use the official BIT_NAMEs e.g.

// instead of :
  TWCR=0b10100100;   // start condition setting bits twint, start, enable
// you write
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);   //use BIT_NAMEs

Yes,  it would take you 5 minutes to do all the edits.

 

David.

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

Got it sir..now it's more clear. Moment will edit all.

Thank you

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

1)Yes i have used the leds and those are active-high, as per the advice i have checked the ack of the signals by using the function below, for different conditions

 

if(TWSR==0x08)

{

 PORTB=0x01;

}

 

checked each ACK signal with their various values mentioned in datasheet for the master transmitter, i checked its giving the expected values till the start condition which is at the 4th line from bottom after that it is not giving the ack for the ADD+R condition which is write(0xAF). 

 

2)Sir you mentioned in second that it returns from mains i didnt understood what you ment there.

 

 

thank you. 

 

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

I have added comments to your tidied #1.

#include <avr/io.h>
#include <util/delay.h>
void i2c_int()
{
	TWSR = 0x00;
	TWBR = 0x0C;                                  // set the 400K
	TWCR = (1<<TWEN);                            // .kbv use =
}
uint8_t wait(void)                                  // .kbv make non-void
{
	while(!(TWCR& (1<<TWINT)));                 //  wait for next interrupt
        return (TWSR & 0xF8);                       // return status
}
uint8_t Str(void)
{
	TWCR = ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN));   // .kbv use = . clear IRQ, start
	uint8_t status = wait();
        return (status == 0x08 || status == 0x18);  //START or REP_START
}
void sto(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);;	// clear IRQ, stop condition
        while (TWCR & (1<<TWSTO)) ;                     // wait for completion
}

uint8_t write(unsigned int x)
{

	TWDR = x;
	TWCR = ((1<<TWINT)|(1<<TWEN));                  //clear IRQ, xmit data
	uint8_t status = wait();
	return status == 0x18 || status == 0x28 || status == 0x40 || status == 0x50; //ACK is true
}

uint8_t read()
{
	TWCR = ((1<<TWINT)|(1<<TWEN)|(0<<TWEA));         //NAK i.e. only one read
	uint8_t status = wait();                        //discard status
	return PORTB = TWDR;                             // return received data
}
int main(void)
{
	DDRB=0xff;	// setting port b as output
        i2c_int();
 	Str();		// start condition
 	write(0xAE);	// 10101110 [1010 address of slave, XXX dont care 0 write] -frame format
  	write(0x00);	// address pointer
  	write(0xff);	// data
    sto();
        _delay_ms(5);   // .kbv page-write takes at least 5ms
  	Str();		// start
 	write(0xAE);	// 10101110 write condition
 	write(0x00);	// read data
        sto();
	Str();	        //  start
 	write(0xAF);	// 10101111 READ MODE
 	read();
	sto();		// stop

        while (1) ;     // not necessary but is logical for forever
}

I have made most of your functions non-void.   You should USE the return values

Untested.  I just typed into Browser.

 

Note that every time you write to the TWCR register,  you normally write 1 to TWINT to clear the IRQ.

 

David.

Last Edited: Sat. Jul 15, 2017 - 05:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hshubh wrote:
i checked its giving the expected values till the start condition which is at the 4th line from bottom after that it is not giving the ack for the ADD+R condition which is write(0xAF).
Maybe it is because the 24AA01 is busy writing the data into EEPROM? As David indicates in his last post, the device has a 5 ms write cycle time.

 

In general, if a device does not ACK then you need to handle that somehow. In this case, you could just repeat the read attempt until ACK received (but no more than 100 times or so).

 

hshubh wrote:
2)Sir you mentioned in second that it returns from mains i didnt understood what you ment there.

If you do not understand that, then I think you need to take a step back and learn the basics.

/Jakob Selbing

Last Edited: Sun. Jul 16, 2017 - 06:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok,  from a logical point of view,  an embedded program never returns from main.

 

In fact,  the GCC program model can return from main.   It simply disables interrupts and enters an endless loop. i.e. CLI, here: RJMP here

 

A non-interrupt program does not matter.   It sits in the endless loop.   Nothing happens.

A program that relies on interrupts will stop working.   Same thing.  Endless loop with nothing happening.

 

Regarding the I2C.   Yes, the very first thing that any I2C program should do is test the Slave for ACK.

Apparently the OP's 24AA01 chip has got an 8-bit address of 0xAE / 0xAF.    i.e. hardware pins A0, A1, A2 are all hardwired to VCC.

 

I would use an LED to indicate the result of any I2C operation.    Or better still,   descriptive messages to a Serial Terminal.

 

David.

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

The default value of the memory in the EEPROM is 0xff so I suggest using a different test value, such as 0xbb.

 

What are you seeing on your (or your school's electronics lab) oscilloscope?  Is there asserting (making logic LOW) and releasing (making logic HIGH) of the SDA and SCL pins?

No scope? Set the program to read/write to the Serial EEPROM about 15 times a second continuously.  Put LEDs (with 150 ohm resistors) on the SDA and SCL lines.  They will flicker if you

have I2C TWI activity. 

 

Do you have 3000 ohm pull-up resistors to Vcc on the SDA/SCL lines? 

Are the chip-select address pins on the Serial EEPROM IC pulled to ground?

 

I assume that your AVR system clock speed is 16MHz if you are using a value of 0x0c for TWBR to get a 400 KHz I2C clock signal. 

 

Here is the quick, easy, and reliable way to read a serial EEPROM:

1:  Get an Arduino Nano or UNO clone from eBay for about $3.00 US.

2:  Download the standard library for reading Serial EEPROM (which uses the standard Wire.h library for interfacing with I2C).  Here is the read buffer section below:

3:  Incorporate the code from the example programs into your Arduino application's .INO file.  (the "main()" ) part of the Arduino program).

4:  Experiment until working. (which won't take long because hundreds of thousands of running Arduino programs are using the same code).


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void I2C_EEPROM_read_buffer( int deviceAddress, unsigned int myEEaddress, byte *buffer, int numBytes) {
    Wire.beginTransmission(deviceAddress);
    Wire.write((int)(myEEaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceAddress, numBytes);  // repeat START, then send SLA+R
    for ( int c = 0; c < numBytes; c++ )
      if (Wire.available()) buffer[c] = Wire.read();
Last Edited: Sat. Jul 15, 2017 - 11:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Sir I will really try working on this.

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

David Sir the changes you added were really helpful....

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

As jacksel Sir mentioned, after observations it was noticed that the controller was busy writing the data.
N after that stop condition was the main were the code went wrong.

As their is the wait condition in that due to which the code wasnt working

Thank you to each and every person for investing yours precious time and giving a helping hand.

It was possible only because of you people.

Thank you soo much.