cancel
Showing results for 
Search instead for 
Did you mean: 

I2C EEPROM 24LC16b, 24LC65 problem ...

AGoog
Associate II

Hello,

I have a problem with I2C eeprom 24LC16b and also with 24LC65. Altough the internal buffer is 16 bytes I can sent at once only 15 bytes (14 characters + 1 null char) and the same is aslo for 24LC65 (Instead of 64 I can store only 63 chars at once = 62 chars + 1 null char).

I use HAL drivers. All the initialization code is created by CubeMX. I tried with internall pull ups and also with external 4.7K pul-ups.

Bellow is a snippet from my code inside main function.

Bellow is also a screenshot from my serial (UART) program, where you can see results readed from my EEPROM 24LC16b when I store "12345678901234", "123456789012345", "1234567890123456". "12345678901234567", "123456789012345678", "1234567890123456789" respectively.

We can see that when the length of the string is greater than 16 chars remaining characters go to the begining of the EEPROM buffer. That seems OK but where does go character 16 (second output bellow) - buffer is 16 bytes long)!? When I used 24LC65 the same occours after 64 character but character 64 is missing as it was for output 2 bellow).

Look at the last picture bellow (outputs). The first output is OK (we can also see the last null character). In the 3rd output (I store 17 chars into eeprom) null character rotate to the first location and owerwrite 1 (that's OK), but where did null go in the 2nd output. When I store 16 characters the last character e (and other last characters from later outputs where I store more than 16 characters) wasn't written by our program => so it is something old data from the memory; that's also OK).

Thanks for help!

char writeStr[] = "12345678901234"; //14 bytes + 1 for "null" = 15 chars
 
char readStr[200]; //Here I want to read a string from I2C eeprom
 
//memory location address
uint16_t MemAddress = 0x0;  
 
//I2c device address =(0x50<<1) = A0 
uint16_t i2cAddress = (uint16_t)(0x50<<1);  
 
//write into I2C eeprom
HAL_I2C_Mem_Write(&hi2c2, i2cAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, (uint8_t*)writeStr,strlen(writeStr)+1, HAL_MAX_DELAY); 
 
//wait until internal write is finished ...
while(HAL_I2C_IsDeviceReady(&hi2c2, i2cAddress, 1, HAL_MAX_DELAY) != HAL_OK); 
 
HAL_I2C_Mem_Read(&hi2c2, i2cAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, (uint8_t*)readStr,strlen(writeStr)+1, HAL_MAX_DELAY); 
 
//test 1: string from EEPROM send to PC through UART 
HAL_UART_Transmit(&huart1, (uint8_t*)readStr, strlen(writeStr)+1, HAL_MAX_DELAY); 
 
//test 2: if string from EEPROM equals writeStr => turn on LED 
if(strcmp(writeStr, readStr) == 0) {
     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
 }
 

Results:

 0690X000006D7ZPQA0.jpg

1 ACCEPTED SOLUTION

Accepted Solutions
AGoog
Associate II

The problem is solved!

24LC16b needs only 1 byte length of EEPROM memory location address (some eeproms has 2 bytes or WORD memory addresses) that is combined with 3 less significant bits of a device address B0, B1, B2. These bits are used to address eight 256 bytes memory block. And inside this memory block address byte is used to address individual byte location inside.

So I just replaced this line of code:

HAL_I2C_Mem_Write(&hi2c2, i2cAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, (uint8_t*)writeStr,strlen(writeStr)+1, HAL_MAX_DELAY); 

with this (sent only 1 byte of memory address):

HAL_I2C_Mem_Write(&hi2c2, i2cAddress, MemAddress, I2C_MEMADD_SIZE_8BIT, (uint8_t*)writeStr,strlen(writeStr)+1, HAL_MAX_DELAY); 

The same change I made also for receiving data from EEPROM and it works as it should.

View solution in original post

6 REPLIES 6
Mon2
Senior III

Just a quick thought - the standard UART inside of a PC is often with a 16 byte FIFO (buffer) depth. Review the UART configuration of the serial port being used with the Hercules application to see if that impacts your results.

S.Ma
Principal

EEPROM have a page size for a single erase/write cycle and you shouldn't assume what happens if in a single write you happen to cause out of page write.

If the page is 64 bytes, you can write for example at 0x20-0x3F (16 bytes in the same page), and you cannot write in single transaction in 0x30-0x4F. You'll have to split that up.

Bury these delicate specific code in a generic function with any block of data of any size to hide these issues to the higher level code. You don't need to use a serial port, use the debugger. If need more guidance, let me know.

AGoog
Associate II

Thanks for your answer! If I send a string "writeStr" of arbitrary length to a PC through UART it shows it correctly - without mistakes. So I think there's no problem with UART settings.

AGoog
Associate II

Thanks for your answer!

The page size for 24LC16b is 16 bytes (the same as the size of its buffer in this case). Because I write 16 bytes starting from memory address 0 I don't cross the page.

You metnioned: "Bury these delicate specific code in a generic function with ...". The problem is that my code doesn't work corectly for trivial "school" cases. It doesn't store 16th byte. Why? But if I sent 17 bytes, you can see that the first byte (number 1) is overwritten with a null character as it should be and the 16th bytes also is missing.

If the entered and read strings matches the test LED turns ON (it works for strings shorter than 16 bytes), but it doesn't for string of 16 bytes and of course (that's normal) for longer (this mismatch also shows the UART).

I read the datashett for 24lc16b many times and I can't see the problem. It might be the problem with HAL functions for I2C or I missed something, I don't know?

Any additional suggestion?

S.Ma
Principal

The right answer requires an oscilloscope probe of the transaction to find out where is the issue.

If you don't have an oscillosope, try to use the I2C by GPIO which is shared in this forum and compare the behaviour.

Maybe the ideal case would be for ST to have a special board with various type of I2C/SPI EEPROM and a generic driver to read/write all of them at higher abstraction layer? Seems that it would save a lot of bringup time and forum threads?

AGoog
Associate II

The problem is solved!

24LC16b needs only 1 byte length of EEPROM memory location address (some eeproms has 2 bytes or WORD memory addresses) that is combined with 3 less significant bits of a device address B0, B1, B2. These bits are used to address eight 256 bytes memory block. And inside this memory block address byte is used to address individual byte location inside.

So I just replaced this line of code:

HAL_I2C_Mem_Write(&hi2c2, i2cAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, (uint8_t*)writeStr,strlen(writeStr)+1, HAL_MAX_DELAY); 

with this (sent only 1 byte of memory address):

HAL_I2C_Mem_Write(&hi2c2, i2cAddress, MemAddress, I2C_MEMADD_SIZE_8BIT, (uint8_t*)writeStr,strlen(writeStr)+1, HAL_MAX_DELAY); 

The same change I made also for receiving data from EEPROM and it works as it should.