Skip to main content
Manu Abraham
Senior
February 22, 2017
Question

STM32F334 with 24C32 EEPROM I2C Read/Write

  • February 22, 2017
  • 7 replies
  • 7824 views
Posted on February 22, 2017 at 09:59

Hi,

Trying to get I2C communication between a F334 and a 24C32 EEPROM working,

The read and write functions do return correctly, but the reads do not match what

has been written to the EEPROM. Struggling to find the issue at hand and in the

thought that someone could possibly lend me a hand on this issue, which would

be very helpful. The EEPROM's address lines are all grounded, which effectively

puts the EEPROM at an address of 0xA0

The output I am reading in a terminal, which says:

-------------= I2C1 REG dump =-------------

I2C_CR1 : 0x01

I2C_CR2 : 0x20404a1

I2C_OAR1 : 0x8000

I2C_OAR2 : 0x00

I2C_TIMINGR : 0x10c08dcf

I2C_TIMEOUTR: 0x00

I2C_ISR : 0x01

I2C_ICR : 0x00

I2C_PECR : 0x00

I2C_RXDR : 0xff

I2C_TXDR : 0x00

-------------------------------------------

Data: ff ff ff ff

-------------= I2C1 REG dump =-------------

I2C_CR1 : 0x01

I2C_CR2 : 0x20404a1

I2C_OAR1 : 0x8000

I2C_OAR2 : 0x00

I2C_TIMINGR : 0x10c08dcf

I2C_TIMEOUTR: 0x00

I2C_ISR : 0x01

I2C_ICR : 0x00

I2C_PECR : 0x00

I2C_RXDR : 0xff

I2C_TXDR : 0x00

-------------------------------------------

Data: ff ff ff ff

which doesnt reflect what I have written. I was expecting 0x00, 0x01, 0x02, 0x03

as expected as in:

i2c_wr(0xa0, 0x00, 0x00);

i2c_wr(0xa0, 0x01, 0x01);

i2c_wr(0xa0, 0x02, 0x02);

i2c_wr(0xa0, 0x03, 0x03);

instead of 0xff, 0xff, 0xff, 0xff.

Any thoughts/suggestions ?

Thanks.

#stm32f334-i2c

Note: this post was migrated and contained many threaded conversations, some content may be missing.
This topic has been closed for replies.

7 replies

AvaTar
Senior III
February 22, 2017
Posted on February 22, 2017 at 10:06

Are you sure you addressing the slave correctly ?

You should see an Acknowledge at bit 9. You have a scope or logic analyzer ?

All read bytes 0xFF looks suspiciously like the slave(s) not responding at all.

I2C has pull-ups, so dead reads return 0xFF.

Manu Abraham
Senior
February 22, 2017
Posted on February 22, 2017 at 10:54

The address should be correct, I guess.

A0, A1, A2 pins connected to ground, which puts the EEPROM at 0xA0

The pins are pulled up 3k9 resistors. Yes, I agree that the FF's are bogus reads.

I am not really sure whether the slave is not responding at all. It appears to respond,

looking at the attached waveform ?

The bottom 2 traces are a zoomed version of the 2 upper traces.

________________

Attachments :

20170222_145436.jpg : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HytQ&d=%2Fa%2F0X0000000bDb%2FHl1.hGj58ibyhbPBJz31iKZuHdMNY1oVOMjEhKz1L0M&asPdf=false
AvaTar
Senior III
February 22, 2017
Posted on February 22, 2017 at 11:07

Looks o.k. to me. I would interpret that as ACK, too.

Coincidentally, erased Flash/EEPROM cells also contain 0xFF, so the read bytes might reflect reality.

Perhaps you need to concentrate on the validation of you programming process (as described in the datasheet).

Manu Abraham
Senior
February 22, 2017
Posted on February 22, 2017 at 14:04

The EEPROM datasheet.

http://www.atmel.com/images/doc0336.pdf

Looking at Page11 Fig 2, Byte Write. It says

Start

Slave Address+R/W -> ACK

Reg Address MSB -> ACK

Reg Address LSB ->ACK

Data ->ACK

Stop

The problem that I perceive, sending only the Reg MSB;

while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXIS) == RESET) {};

//Send the address of the register we wish to write to

I2C_SendData(I2C1, (uint8_t)reg); // msb

Modifying the code to send the LSB too as described in the datasheet..

but, when I try to do send in the LSB, checking for the next 

I2C_ISR_TXIS

to send the LSB, the TXIS flag is not raised and the loop goes on indefinitely.

Having lost state completely, Am I looking at things incorrectly ?

S.Ma
Principal
February 22, 2017
Posted on February 22, 2017 at 11:14

To me it looks like the eeprom datasheet was not read entirely. When a data is written in eeprom (any) you need to wait for the eeprom erase and write operation which would take up to 10msec. During this time, the eeprom is busy and will reject (NACK) your request. If Nack, noone set the read operation and the pull-up on the bus will tell 0xFF...

Manu Abraham
Senior
February 22, 2017
Posted on February 22, 2017 at 14:07

I tried modifying the code to have more than 10ms delay after the write for the read,

but that made no difference at all. changes look thus:

i2c1_init();

led_init();

led_toggle();

i2c_wr(0xa0, 0x00, 0xde);

i2c_wr(0xa0, 0x01, 0xad);

i2c_wr(0xa0, 0x02, 0xbe);

i2c_wr(0xa0, 0x03, 0xef);

delay(10);

/* Infinite loop */

while (1) {

debug_i2c1();

delay(10);

i2c_rd(0xa1, 0x00, dbuf, 4);

sprintf((char *)strbuf, 'Data: %02x %02x %02x %02x\r\n',

dbuf[0], dbuf[1], dbuf[2], dbuf[3]);

putstr(USART1, strbuf);

led_toggle();

}

-------------= I2C1 REG dump =-------------

I2C_CR1 : 0x01

I2C_CR2 : 0x20404a1

I2C_OAR1 : 0x8000

I2C_OAR2 : 0x00

I2C_TIMINGR : 0x10c08dcf

I2C_TIMEOUTR: 0x00

I2C_ISR : 0x01

I2C_ICR : 0x00

I2C_PECR : 0x00

I2C_RXDR : 0xff

I2C_TXDR : 0x00

-------------------------------------------

Data: ff ff ff ff

Maybe I am missing something completely.
Ronald Niederhagen
Associate II
February 22, 2017
Posted on February 22, 2017 at 11:53

I'm using a 24C08 which should be similar, just smaller.

Have you checked if pin 7 (which is WP, write_protect) is low? At least during the write.

I'm using mbed, so my code looks different, but I guess you can figure it out from there:

void byte_write(int dev_addr,int w_addr,uint8_t d)

{

    char cmd[2];

    cmd[0] = w_addr & 0xFF;

    dev_addr = ((w_addr & 0x300) >> 7) | (dev_addr & 0xF0);

    cmd[1] = d;

    i2c_bus.write(dev_addr,cmd,2);

    wait_ms(10); // wait until write cycle is complete

}

uint8_t byte_read(int dev_addr,int w_addr)

{

    char cmd[2];

    cmd[0] = w_addr & 0xFF;

    dev_addr = ((w_addr & 0x300) >> 7) | (dev_addr & 0xF0);

    i2c_bus.write(dev_addr,&cmd[0],1,true); // it is important to make this a 'repeated' access

    i2c_bus.read(dev_addr,&cmd[1],1);

    return(cmd[1]);

}

Not pretty, but it works for me.

Manu Abraham
Senior
February 22, 2017
Posted on February 22, 2017 at 14:11

Sigh, tried the delay with no perceivable difference in the result.

Maybe something is really odd in my setup.

S.Ma
Principal
February 22, 2017
Posted on February 22, 2017 at 15:50

Add 10msec delay between each write. Programming start after the stop bit.

Or try 

https://community.st.com/0D50X00009XkW1qSAF

 
Shashank TS_2
Visitor II
January 22, 2018
Posted on January 22, 2018 at 07:29

Hello, Am using STM32F0 uC for interfacing with a AT24C64. I am not able to write sequentially to the EEPROM after one page, i.e 32 Bytes. Can someone please if the logic is wrong.

This is the code:

data[0]=0x00; //First word address 8bit

data[1]=0x00; //Second word address 8bit

for(i=2;i<34;i++)

{

data[i]=0x11;

}

HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS<<1, data, 34, 50); //data is int type,34 is number bytes of data

data[0]=0x00; //First word address 8bit

data[1]=0x20; //Second word address 8bit// Next Page

for(i=2;i<34;i++)

{

data[i]=0x22;

}

HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS<<1, data, 34, 50); //data is int type,34 is number bytes of data

while (1)

{

/* USER CODE END WHILE */

data[0]=0x00;

data[1]=0x00;

HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS<<1, data, 2, 50); //data is int type pointing to first address here

for(i=0;i<32;i++)

{

HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDRESS<<1, &dataout[i], 1, 50);//maximum is 32 byte data locations

}

data[0]=0x00;

data[1]=0x20;

HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS<<1, data, 2, 50); //data is int type pointing to first address here

for(i=0;i<32;i++)

{

HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDRESS<<1, &dataout_1[i], 1, 50);//maximum is 32 byte data locations

}

}

Ronald Niederhagen
Associate II
February 22, 2018
Posted on February 22, 2018 at 10:14

Hi, I'm not sure there is a clean answer, yet.

Here is what works for me in mbed:

/* start code */

#define AT24C32_PAGE_SIZE       32

int imin(int a, int b) { return a < b ? a : b; }

bool read_eeprom(int i2c_addr, int address, char *buffer, int len)

{

  int lx;

  char cmd[2];

  char mem_addr = (i2c_addr & 0xFE);

  while ((lx = imin(AT24C32_PAGE_SIZE - (address % AT24C32_PAGE_SIZE),len)) > 0)

    {

    cmd[0] = ((address & 0x1F00) >> 8);

    cmd[1] = (address & 0xFF);

    i2c_bus.write(mem_addr,cmd,2);

    i2c_bus.read(mem_addr,buffer,lx);

    address += lx;

    buffer += lx;

    len -= lx;

    }

  return true;

}

bool write_eeprom(int i2c_addr, int address, char *source, int len)

{

  int lx, i;

  char cmd[AT24C32_PAGE_SIZE+2];

  char mem_addr = (i2c_addr & 0xFE);

  while ((lx = imin(AT24C32_PAGE_SIZE - (address % AT24C32_PAGE_SIZE),len)) > 0)

    {

    cmd[0] = ((address & 0x1F00) >> 8);

    cmd[1] = (address & 0xFF);

    address += lx;

    len -= lx;

    lx += 2;

    for (i=2;i < lx;i++) {cmd[i] = *source++;}

    i2c_bus.write(mem_addr,cmd,lx);

    wait_ms(10); // wait until write cycle is complete

    }

  return true;

}

/* end code*/

And here is how you use these functions:

#define AT24C32_ADR     0xa0

read_eeprom(AT24C32_ADR,20,rtc_buf,sizeof(rtc_buf));

write_eeprom(AT24C32_ADR,40,txt,sizeof(txt));

The functions take care of sequential reads/writes across page boundaries.

Please note: larger EEPROMs like the AT24C32 or the AT24C64 require 2 byte addresses. Smaller ones like the AT24C08 uses 1 byte address. That's why these access functions are not (easily) compatible. See the data sheets for more detail.