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
Bob S
Principal

You are not waiting long enough for the WRITE operations to complete before accessing the chip again (either read or write).  See the tWR (Internal Write cycle duration) parameter in the datasheet.  You can either increase your dumb HAL_Delay() delays to that amount, or use ACK polling to find out when the write operation is done (section 5.1.6).

Thanks, how would I set up the ACK polling using the HAL memory library?

I read that section, but I thought waiting for acknowledgement was part of the HAL Blocking I2C functions with the timeout. If the HAL_I2C_Mem_Write function wasn't getting an acknowledgement back within the timeout period wouldn't it return a HAL_ERROR of some kind? It always returns HAL_OKAY.

> It always returns HAL_OKAY.

Sure it does, when you're stepping through it with a debugger. But you don't see the errors in that case either.

Monitor the return status and actually do something with that info. Your code just silently ignores whatever return value occurs.

If you feel a post has answered your question, please click "Accept as Solution".
EPala.2
Associate III

@TDK So assuming that it is returning HAL_ERROR, is there a different function I should be calling to do the write timeout check? 

Based on my understanding that should be built into HAL_I2C_Mem_Read/Write because both under the hood are supposed to wait for acknowledgement from target device before performing their operation. The timeout of 100ms I have set is far beyond the internal write time of the EEPROM. So what is going on?

EPala.2
Associate III

Shouldn't this be waiting for an acknowledge bit and doing the write once the acknowledge bits are received? This is directly from the HAL_I2C_Mem_Write function:

    if (I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK)

    {

      /* Process Unlocked */

      __HAL_UNLOCK(hi2c);

      return HAL_ERROR;

    }

No, it doesn't work like that. If it gets a NACK, it stops.

If you feel a post has answered your question, please click "Accept as Solution".
EPala.2
Associate III

So then what is the timeout for if it isn't waiting for the device to be ready? I feel like I'm misunderstanding that.

EPala.2
Associate III

And are you please able to answer my above question:

If the timeout feature on the HAL_I2C_Mem_Write is not waiting for an acknowledge bit, what function in the I2C library would I use to wait for the acknowledge bit?

TDK
Guru

Clock stretching, maybe multi-master busy status as well.

If you feel a post has answered your question, please click "Accept as Solution".