interfacing 24lc1025 with atmega32

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

Hello,

 

I want to interface 24LC1025 with atmega32. 24LC1025 is divided in two block of 512kb and in control frame there is a bit block select bit to select the block. I can read and write first block without any problem(random read and write).

But when I try to read second block I getting 255. I am sure my I2C rutains are correct because as I say, I can read and write on first block. This is my code. Please help to solve the problem.

 

//Microcontroller- atmega32

//Compiler-WINAVR 20100110 ,AVR STDIO 7

//CRESTAL- FREQ-11.0592Mhz

void main(void)

{

 unsigned char log_data[5];

        EEPROM_WriteByte_1Mb(100,10,0);    //work fine
        EEPROM_WriteByte_1Mb(200,20,0);    //work fine
        EEPROM_WriteByte_1Mb(300,30,1);    //not working
        EEPROM_WriteByte_1Mb(400,40,1);    //not working

while(1){

             log_data[0]= EEPROM_ReadByte_1Mb(100,0);     //Read block 0, this by setting block select bit =0,this is working fine
             log_data[1]= EEPROM_ReadByte_1Mb(200,0);
             log_data[2]= EEPROM_ReadByte_1Mb(300,1);     //Read block  1, this by setting block select bit =1,this not work
             log_data[3]= EEPROM_ReadByte_1Mb(400,1);

ms(100);

}

}

unsigned char check_frame;     //This is for checking value of control frame, When I select block 0, here value is A0, this working fine

                                              //when I select block 1, here value is A8, this not working.

/****************

Input- address,data,block bit

output- non

****************/

void EEPROM_WriteByte_1Mb(unsigned int eeprom_Address, unsigned char eeprom_Data, unsigned char block)
{
    unsigned char address_wh,address_wl;
    unsigned char Page_Number=0x00;

       if(block==0){
       Page_Number=0x00;                             //select first block ,first 512Kb
       }
       else if(block==1){
       Page_Number=0x04;                             //select second block ,second 512Kb
       }
       else{
       Page_Number=0x00;                           //Default select block 1
       }

    address_wh= ((eeprom_Address>>8) & 0x00FF);                     //break int to char
    address_wl= (eeprom_Address & 0X00FF);

    I2C_Start();                                                                           // Start i2c communication

    I2C_Write(EEPROM_ID|(Page_Number<<1));                          // connect to 24LC1025 and above by sending its ID on I2c Bus
    check_frame=(EEPROM_ID|(Page_Number<<1));
    I2C_Ack();

    I2C_Write(address_wh);                      //Send address high
    I2C_Ack();

    I2C_Write(address_wl);                       //Send address low
    I2C_Ack();

    I2C_Write(eeprom_Data);                  // Write the data at specified address
    I2C_Ack();
    I2C_Stop();                                     // Stop i2c communication after Writing the data

    ms(5);                                            //Should be 5 ms delay in every random write

    return;

}

/****************

Input- address and block bit

output- unsigned char data

****************/

unsigned char EEPROM_ReadByte_1Mb(unsigned int eeprom_Address,unsigned char block)
{
    unsigned char eeprom_Data;  //,address_h,address_l;
    unsigned char address_rh,address_rl;
    unsigned char Page_Number=0x00;

    if(block==0){
    Page_Number=0x00;                             //select first block ,first 512Kb
    }
    else if(block==1){
    Page_Number=0x04;                             //select second block ,second 512Kb
    }
    else{
    Page_Number=0x00;                           //Default select block 1
    }

    address_rh= ((eeprom_Address>>8) & 0x00FF); //break int to char
    address_rl= (eeprom_Address & 0X00FF);

    I2C_Start();                                                      // Start i2c communication
    I2C_Write(EEPROM_ID|(Page_Number<<1));      // connect to AT24LC1025 and above(write) by sending its ID on I2c Bus
    I2C_Ack();

    I2C_Write(address_rh);                       // address high
    I2C_Ack();
    I2C_Write(address_rl);                       // address low
    I2C_Ack();

    I2C_Start();                                                  // Start i2c communication
    I2C_Write(0xA1|(Page_Number<<1));           // connect to 24lc1025(read) by sending its ID on I2c Bus
    I2C_Ack();

    eeprom_Data = I2C_Read();                   // Read the data from specified address
    I2C_NoAck();
    I2C_Stop();                                           // Stop i2c communication after Reading the data

      us(10);
    return (eeprom_Data);                        // Return the Read data
}

 

Last Edited: Fri. Mar 1, 2019 - 09:56 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

0xA8 is exactly what I would expect.

 

 

Your code shares a featue which is common in much I2C code we here on AVRfreaks. You are not checking any return codes for errors. Once you add this in, debugging becomes almost trivial.

 

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

There is a WORKING example of an I2C reading/writing to eeprom here, with WORKING I2C master code.   http://homepage.hispeed.ch/peter...

 

As stated above, you write blindly to your device with out checking to see if it is even listening to you because you do not check for the ACK/NAK sent by the eeprom.

I2C will tell you when something goes wrong, but you must be listening...

Avoid any I2C code that returns VOID from their functions!

 

Try again using the known good lib's above and test for and respond correctly to the returned status.

Also, be sure you have pull up resistors on your SDA/SCL lines, for 5v systems, 4.7k work well.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

ki0bk wrote:
Also, be sure you have pull up resistors on your SDA/SCL lines, for 5v systems, 4.7k work well.

 

This is just a general FYI and may not have any connection to the issue you are having.  We get a lot of I2C questions about code not working and after a lot of back and forth we find out that the pull up resistors are either the wrong value, not in teh right place, or not there at all.  4k7 resistors should be l=placed at the very end of the I2C bus.

 

samic45mit1 wrote:
else if(block==1){ Page_Number=0x04; //select second block ,second 512Kb

 

I think you have this wrong.  I am assuming BLOCK and PAGE are the same thing.  Look at the control byte, I think you are not setting the bit properly

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Thu. Feb 28, 2019 - 03:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah,  use two slave addresses.   Use 0xA0 for the lower 64K bytes and 0xA8 for the upper 64K bytes (assuming A0 and A1 are zero).   Don't do any shifting of this slave address.  However, include an OR operation with 0x01 (to set bit 0)  if you are doing a READ operation from the EEPROM.

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

Yeah,  use two slave addresses.   Use 0xA0 for the lower 64K bytes and 0xA8 for the upper 64K bytes (assuming A0 and A1 are zero).   Don't do any shifting of this slave address.  However, include an OR operation with 0x01 (to set bit 0)  if you are doing a READ operation from the EEPROM.

 

Are you suggesting like this "I2C_Write(EEPROM_ID|(Page_Number<<1))" ? I test this but it not work.

 

And this is not the hardware issue because this routine is working properly with block zero. and I test this many time.

 

  

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

samic45mit1 wrote:
And this is not the hardware issue because this routine is working properly with block zero. and I test this many time.

 

And we are not arguing with you.  It is a software issue.  Look at what I asked regarding the page/block in #4 and read what Simonetta posted in #5.

 

What are the logic levels of A0 and A1?  We assume 0, and 0.

 

Heres a possible way to check that things are communicating....

 

  I2C_Write(EEPROM_ID|(Page_Number<<1));      // connect to AT24LC1025 and above(write) by sending its ID on I2c Bus

In your code, where ever you have the 

  EEPROM_ID|(Page_Number<<1

change it to what the hard code would be.  In this case assuming A0 and A1 are both '0' the address would be 0xA8 for write and 0xA9 for a read.  Then run your code and see if you can write and read to teh upper block.  If you can then your code has the issue in how you are setting up the bits.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

YOu could also try changing this:

  I2C_Write(EEPROM_ID|(Page_Number<<1));      // connect to AT24LC1025 and above(write) by sending its ID on I2c Bus

 

to this:

 

  I2C_Write(EEPROM_ID|(1<<Page_Number));      // connect to AT24LC1025 and above(write) by sending its ID on I2c Bus

 

One last thing.  you might need to change this:

else if(block==1){
       Page_Number=0x04;                             //select second block ,second 512Kb

to this:

else if(block==1){
       Page_Number=0x03;                             //select second block ,second 512Kb

 

I think you are shifting one too many times

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

samic45mit1 wrote:
And this is not the hardware issue because this routine is working properly with block zero. and I test this many time.

Not necessarily !

My experience of this wierdo (2 chips in one) family of EEPROM is that an engineer previous to me had failed to connect A2 as logic high as the datasheet mandates and I could not get reliable reads/writes.

Have you conneced A2 correctly ?

 

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

Yes you are right I connect A2 with gnd. I think that's why I am not able to read or write the IC. and as per data sheet it should connected to vcc.

But when I connect A2 with vcc then read/write from block 0 is also stop. 

 

Thankyou

Last Edited: Fri. Mar 1, 2019 - 09:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can read any 24Cxx EEPROM continuously.

You can only write to a page.

 

It is very inefficient to write a single byte.   It is wise to use a generic function that writes an arbitrary block of N bytes to a specific location.    A single byte would just be a block with N = 1.

 

The function sets location and sends bytes to the EEPROM until it gets to a page boundary.

Issue an I2C_STOP.   This starts the Page write.    Either wait for 5ms or poll for completion.

Continue until you have sent all N bytes.

 

You can extend the algorithm by setting the correct Slave address when you have multiple 24Cxx chips.

The small 24C01 - 24C16 chips have 8-bit location counters

The current 24C32 - 24C512 chips have 16-bit location counters

24C1025 / 24C1026  have two Slave addresses in one physical chip.

 

Note that page sizes vary from 24C01 to 24C1025.    It takes the same time to write an 8-byte page in 24C01 as a 256- 128-byte page in a 24C1025

 

David.

Last Edited: Fri. Mar 1, 2019 - 10:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes your all point are correct but my problem is that I am not able to read/write to block 2 of memory. Even when I connect A2 to vcc as given in datasheet. So can you suggest what is possible problem. 

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

24LC1025 appears as two different Slave devices:
 

24LC1025:  A2 must be 1
Address pins:100   L = 0x50,  H = 0x54
Address pins:101   L = 0x51,  H = 0x55
Address pins:110   L = 0x52,  H = 0x56
Address pins:111   L = 0x53,  H = 0x57

24LC1026:  A0 is nc
Address pins:00x   L = 0x50,  H = 0x51
Address pins:01x   L = 0x52,  H = 0x53
Address pins:10x   L = 0x54,  H = 0x55
Address pins:11x   L = 0x56,  H = 0x57

I will post you some code later.   It is painful with an Arduino.    Straightforward with Fleury.

 

Yes,  the 24C1026 approach seems more intuitive.

 

David.

Last Edited: Fri. Mar 1, 2019 - 04:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

#define LOWBLOCK 0xA0    // used when accessing bytes 0x00000 to 0x0ffff of the serial EE

#define HIGHBLOCK 0xA8    // used when accessing bytes 0x10000 to 0x1ffff of the serial EE

 

If you are doing a read operation on the lower block,  use:

   if (EEaddress < 0x10000)  SLA =  LOWBLOCK | 0x01;  else SLA = HIGHBLOCK | 0x01;

 

To read this I2C device:   do a START, then write Slave address 0xA0 or 0xA8 depending on the block, then write the two bytes for the EEPROM address.

   Next do a Restart, which is a STOP followed by a START.   Then send Slave Address 0xA1 or 0xA9 and read your EEPROM data.   So yes, with I2C EEPROMs, you have to send four bytes and a few START/STOPs just to read one byte from the device.  You can do more reads to get more data up to the page limit.

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

A Restart is not a Stop followed by a Start.

 

But yes,  Simonetta shows the procedure.

Incidentally,  a 24Cxx is quite happy to do either Restart or Stop/Start.    Some Slave devices require you to not Release the bus.   Other devices require a Stop to release the bus.

 

David.

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

samic45mit1 wrote:
So can you suggest what is possible problem.

In all truthfulness;!  No! The code you've presented should work. I cannot see any problem there.

 

BUT:

 

  1. We cannot review your schematic.
  2. We cannot review your soldering / wiring
  3. We cannot review your EEPROM_ID definition (but let's assume it is 0xA0 because you told us {check_frame} becomes 0xA8)
  4. We cannot review your I2C primitives
  5. We cannot review the return codes from those I2C primitives (if any)

 

The ball is really in your court now.

 

Last Edited: Fri. Mar 1, 2019 - 09:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here are some generic functions:

They allow write of a block that straddles a page boundary or Slave boundary.

They allow read of a block that straddles a Slave boundary.

 

They require some better error checking.

And a better way to determine the HI_address for a Slave.

I can post an Arduino version if you want.

#include "i2cmaster.h"
#include <stdbool.h>
#define HI_SLAVE 4     //24C1025 uses L=0x50 / H=0x54 (7-bit addresses)

extern void delay(long ms);

void write_24xx_fleury(uint32_t loc, uint8_t *buf, int n, uint8_t slave, int pagesize)
{
    uint8_t ret, slaveads;
    uint8_t attempts;
    uint32_t pagemask = pagesize - 1;
    i2c_init();
    while (n > 0) {
        slaveads = slave;
        if (loc >= 0x10000) slaveads += HI_SLAVE;
        attempts = 0;
        while (1) {
            ret = i2c_start(slaveads << 1); //poll for ACK
            if (ret == 0) break;
            if (++attempts > 5) return;
            delay(1);
        }
        i2c_write(loc >> 8); // hi-byte of address
        i2c_write(loc);
        while (n) {
            i2c_write(*buf++);
            n--;
            if ((++loc & (pagemask)) == 0) // page boundary
                break;
        }
        i2c_stop(); // starts I2C sequence with STOP
    }
}

bool read_i2c_fleury(uint32_t loc, uint8_t *buf, int n, int slave)
{
    uint8_t ret, attempts;
    uint8_t slaveads;
    i2c_init();
    while (n) {
        slaveads = slave;
        if (loc >= 0x10000) slaveads += HI_SLAVE;
        attempts = 0;
        while (1) {
            ret = i2c_start(slaveads << 1); //poll for ACK
            if (ret == 0) break;
            if (++attempts > 5) return false;
            delay(1);
        }
        i2c_write(loc >> 8); // hi-byte of address
        i2c_write(loc);
        ret = i2c_start((slaveads << 1) | I2C_READ); //
        while (n > 0) {
            n--;
            *buf++ = i2c_read(n != 0);
            loc++;
            if (loc == 0x10000) break;
        }
        i2c_stop(); // starts I2C sequence with STOP
    }
    return true;
}

David.

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

OK Thanks all, I try the above code and double check my hardware.