Does STM32’s Hardware I2C Have Bugs?

A legend has been circulating: the hardware I2C design of STM32 has bugs, and it is better not to use it; using software I2C is more reliable.
For a long time, to avoid unnecessary trouble, I have never used hardware I2C, mainly because software I2C is also quite convenient, and it can be used on almost any port.
Recently, I designed a board that just happened to use I2C, so I decided to test whether the hardware I2C is really as bad as some people say.
Test Hardware:STM32F407VET6+AT24C64
Test Software:STM32CubeMX v6.1.1
HAL Library:STM32CubeF4 Firmware Package V1.25.2
STM32CubeMX Configuration
Using STM32CubeMX for configuration is very convenient; basic configurations such as clock settings will not be detailed here. Just look at the I2C configuration below:
Does STM32's Hardware I2C Have Bugs?
The speed mode here is set to standard mode, with a clock speed of 100K. If higher performance is required, Fast mode with a 400K clock can be selected.
Once the configuration is complete, generate the code.
Writing Code
After the code is generated, you can directly call the functions to read and write data:
HAL_I2C_Mem_Read

HAL_I2C_Mem_Write

The function parameters can be referenced in the code comments.

When performing write operations with the 24CXX series EEPROM, it is important to note that when writing across pages, a certain delay is required; otherwise, the write may fail. The page sizes vary for different capacities.
Additionally, addresses for capacities below 24C16 are 8 bits, while addresses for capacities above 24C32 are 16 bits. When calling the read and write functions, it is important to choose I2C_MEMADD_SIZE_8BIT or I2C_MEMADD_SIZE_16BIT. For this test, a 24C64 is used, so I choseI2C_MEMADD_SIZE_16BIT.
To facilitate operations, I wrapped the read and write functions to account for various scenarios of cross-page writing, enabling continuous writing at any address. The code is as follows:
#include "at24c64.h"
#include "i2c.h"
#define AT24CXX_ADDR_READ   0xA1
#define AT24CXX_ADDR_WRITE   0xA0
#define PAGE_SIZE   32
/** * @brief        Read multiple bytes of data from any address of AT24C64 * @param        addr —— Address to read data (0-65535) * @param        dat  —— Address to store read data * @retval        Success —— HAL_OK*/
uint8_t At24cxx_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size){
    return HAL_I2C_Mem_Read(&hi2c2, AT24CXX_ADDR_READ, addr, I2C_MEMADD_SIZE_16BIT, recv_buf, size, 0xFFFFFFFF);
}
/** * @brief        Write multiple bytes of data to any address of AT24C64 * @param        addr —— Address to write data (0-65535) * @param        dat  —— Address to store written data * @retval        Success —— HAL_OK*/
uint8_t At24cxx_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size){
    uint8_t i = 0;
    uint16_t cnt = 0;
    // Count of bytes written
    /* For the starting address, there are two cases to consider */
    if(0 == addr % PAGE_SIZE )    {
        /* Starting address is exactly the page start address */
        /* For the number of bytes to write, there are two cases to consider */
        if(size <= PAGE_SIZE)        {
            // Number of bytes to write is not greater than one page, write directly
            return HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, dat, size, 0xFFFFFFFF);
        }
        else        {
            // Number of bytes to write is greater than one page, write the whole page in a loop
            for(i = 0;i < size/PAGE_SIZE; i++)            {
                HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, &dat[cnt], PAGE_SIZE, 0xFFFFFFFF);
                HAL_Delay(3);
                addr += PAGE_SIZE;
                cnt += PAGE_SIZE;
            }
            // Write the remaining bytes
            return HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, &dat[cnt], size - cnt, 0xFFFFFFFF);
        }
    }
    else    {
        /* Starting address deviates from the page start address */
        /* For the number of bytes to write, there are two cases to consider */
        if(size <= (PAGE_SIZE - addr%PAGE_SIZE))        {
            /* Can write all in this page */
            return HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, dat, size, 0xFFFFFFFF);
        }
        else        {
            /* This page cannot be fully written */
            // First finish writing this page
            cnt += PAGE_SIZE - addr%PAGE_SIZE;
            HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, dat, cnt, 0xFFFFFFFF);
            addr += cnt;
            HAL_Delay(3);
            // Loop to write whole page data
            for(i = 0;i < (size - cnt)/PAGE_SIZE; i++)            {
                HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, &dat[cnt], PAGE_SIZE, 0xFFFFFFFF);
                HAL_Delay(3);
                addr += PAGE_SIZE;
                cnt += PAGE_SIZE;
            }
            // Write the remaining bytes
            return HAL_I2C_Mem_Write(&hi2c2, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE_16BIT, &dat[cnt], size - cnt, 0xFFFFFFFF);
        }                }
}
Test Results
After testing, the hardware I2C read and write operations with EEPROM function normally. No so-called bugs were found; of course, this is only a test of one device for EEPROM with the M4 core. Other cores (like M3) and other I2C devices still need verification.
Conclusion
Using hardware I2C is quite simple; there is no need to adjust the timing manually, but it can only use a fixed number of pins.
Software-simulated I2C can use any pins and is relatively easy to port for different MCUs, but timing adjustment can be tricky for MCUs with different frequencies.
Both have their advantages and disadvantages, and the choice should depend on actual needs.
END
Author: Mr. Zhang
Source: Embedded Technology Development
Copyright belongs to the original author. If there is any infringement, please contact for deletion.
Recommended Reading
Embedded hardware to software, please be cautious!
Will programmers be assigned to write code if they go to jail?
Crash! The intern messed up the group’s code repository…
→ Follow to avoid getting lost ←

Leave a Comment

Your email address will not be published. Required fields are marked *