cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 HAL_I2C_Mem_Write/Read Errors In Quick Sequential Operations

EPala.2
Associate III

Hi, I am working on a project using the STM32H730 with the M24C64 I2C EEPROM chip. 

In my project I am using the HAL_I2C_Mem_Write functions to load and save values from the EEPROM. I'm running into an issue where the wrong value gets read if there are sequential calls to HAL_I2C_Mem_Write or HAL_I2C_Mem_Read functions. I already have a short delay of 1ms after the reads and writes, but it seems longer is necessary, more in the realm of 10ms, which is a major drag on performance. I discovered this when debugging because I do not get read/write errors when stepping through slowly with a debugger, as this adds a time delay between the I2C functions being called. 

Here are my I2C read / write functions:

/**

* @brief Erases the entire i2c_eeprom memory

*/

void persistent_memory_i2c_eeprom::erase_all(void) {

clear_block(0, mem_size);

}

 

/**

* @brief Writes a byte to i2c_eeprom memory

*/

void persistent_memory_i2c_eeprom::write_val(uint32_t offset, uint8_t val) {

HAL_StatusTypeDef res = HAL_I2C_Mem_Write(hi2c, DevAddress, mem_base_address + offset, I2C_MEMADD_SIZE_16BIT, &val, 1, 100);

HAL_Delay(1);

}

 

/**

* @brief Reads a byte from i2c_eeprom memory

*/

uint8_t persistent_memory_i2c_eeprom::read_val(uint32_t offset) {

uint8_t data;

HAL_StatusTypeDef res = HAL_I2C_Mem_Read(hi2c, DevAddress, mem_base_address + offset, I2C_MEMADD_SIZE_16BIT, &data, 1, 100);

HAL_Delay(1);

return data;

}

 

 

/**

* @brief Writes a block of data to i2c_eeprom memory

*/

void persistent_memory_i2c_eeprom::write_block(uint32_t offset, uint8_t * vals, uint32_t size) {

 

uint32_t write_remaining = size;

uint32_t mem_addr = mem_base_address + offset;

uint32_t incr = 0;

while(write_remaining > 0){

uint16_t block_portion = 32 - (mem_addr % 32);

if(block_portion > write_remaining){

block_portion = write_remaining;

}

HAL_StatusTypeDef res = HAL_I2C_Mem_Write(hi2c, DevAddress, mem_addr, I2C_MEMADD_SIZE_16BIT, &vals[incr], block_portion, 100);

mem_addr += block_portion;

write_remaining -= block_portion;

incr += block_portion;

HAL_Delay(1);

}

}

 

/**

* @brief Reads a block of data from i2c_eeprom memory

*/

void persistent_memory_i2c_eeprom::read_block(uint32_t offset, uint8_t * vals, uint32_t size) {

 

HAL_StatusTypeDef res = HAL_I2C_Mem_Read(hi2c, DevAddress, mem_base_address + offset, I2C_MEMADD_SIZE_16BIT, vals, size, 100);

HAL_Delay(1);

}

 

void persistent_memory_i2c_eeprom::clear_block( uint32_t offset, uint32_t size ) {

uint8_t vals[32] = {};

uint32_t write_remaining = size;

uint32_t mem_addr = mem_base_address + offset;

uint32_t incr = 0;

while(write_remaining > 0){

uint16_t block_portion = 32 - (mem_addr % 32);

if(block_portion > write_remaining){

block_portion = write_remaining;

}

HAL_StatusTypeDef res = HAL_I2C_Mem_Write(hi2c, DevAddress, mem_addr, I2C_MEMADD_SIZE_16BIT, &vals[incr], block_portion, 100);

mem_addr += block_portion;

write_remaining -= block_portion;

incr += block_portion;

HAL_Delay(1);

}

}

 

Here is an example of a call that leads to an error unless I insert an artificial delay:

/* Write each preset to memory */

clear_block(mem_offset, 1);

write_block(mem_offset, &temp[i], 1);

 

Is there a reason this is happening? Currently the weird thing is that all the read / write functions are returning HAL_OK, even when they're reading / writing the incorrect values. Is there a different function I can call to wait until the EEPROM is actually ready to accept new messages?

21 REPLIES 21
Piranha
Chief II

If on NACK situation the HAL_I2C_Mem_Write() stops and returns HAL_ERROR, then why don't you just wait and retry in that case? Introducing another function, which does an additional I2C transaction just for checking the device status, just wastes the total transfer time and increases the code size.

You're right of course.

 

Btw, I've tested an i2c eeprom on some custom STM32F7 board, and couple of times managed to drive it to a weird state: HAL_I2C_IsDeviceReady returned with error=timeout  almost immediately, without waiting the specified time (measured with HAL_GetTick around the call gives delta <= 1). After a power cycle all returned to normal working state and this does not reproduce again. Looked in the source of HAL_I2C_IsDeviceReady, couldn't find apparent cause of that.