STM32 I2C Bus Communication
The I2C bus is the “universal” interface in the microcontroller world, as almost all common sensors, display modules, and memory chips support I2C communication. This article will guide you through the working principles of I2C and how to implement I2C communication on STM32.
What is I2C?
I2C (Inter-Integrated Circuit) is a simple, bidirectional, two-wire synchronous serial bus. It only requires two wires – SCL (Serial Clock Line) and SDA (Serial Data Line) to transmit data between connected devices.
Imagine I2C as a two-lane highway:
- • SCL is the traffic light, controlling the pace of data transmission
- • SDA is the lane, where data travels like vehicles
Note: All devices on the I2C bus are connected in parallel, like toll booths on a highway. Each device has its own address, and the master device (usually the microcontroller) selects the slave device to communicate with by broadcasting the address.
Hardware Connection of I2C
I2C Hardware Connection Diagram
As shown in the figure above, the hardware connection of I2C is very simple:
- 1. Connect the SCL pins of all devices together
- 2. Connect the SDA pins of all devices together
- 3. Both SCL and SDA require pull-up resistors (usually 4.7kΩ) connected to VCC
Why Pull-Up Resistors are Needed? Because I2C uses an open-drain output method, devices can only pull the bus low actively, and it is pulled high by the pull-up resistors when released. This is like speed bumps on a highway, preventing data transmission from being too fast and causing “accidents.”
I2C Communication Protocol
I2C communication is always initiated by the master device, following these steps:
- 1. Start Condition : The master pulls SDA low while keeping SCL high
- 2. Address Frame : Sends a 7-bit slave address and a 1-bit read/write flag
- 3. Acknowledge Bit : The slave acknowledges
- 4. Data Frame : Sends or receives 8 bits of data
- 5. Acknowledge Bit : The receiver acknowledges
- 6. Repeat Steps 4-5 until transmission is complete
- 7. Stop Condition : The master pulls SDA high while keeping SCL high
This process is like a complete journey on a highway:
- • Start condition is getting on the highway
- • Address frame is choosing the correct exit
- • Data frame is the journey
- • Stop condition is getting off the highway
STM32 I2C Configuration
The I2C peripheral of STM32 is very powerful, and we can use it with simple configuration. Here are the steps for configuration:
- 1. Enable I2C clock and GPIO clock
- 2. Configure I2C pins as open-drain output
- 3. Configure I2C parameters (such as speed, address, etc.)
- 4. Enable I2C

void I2C_Config(void){// Enable clockRCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// Configure GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Configure I2C
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitStructure);
// Enable I2C
I2C_Cmd(I2C1, ENABLE);
}
Note: Before using I2C, you must first configure GPIO and clock! This is like ensuring your vehicle is in good condition and the fuel tank is full before getting on the highway.
I2C Data Transmission
Here is a simple function to write data via I2C:
void I2C_Write(uint8_t SlaveAddress, uint8_t RegAddress, uint8_t Data)
{
// Wait for I2C to be idle
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
// Send start signal
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// Send slave address
I2C_Send7bitAddress(I2C1, SlaveAddress, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// Send register address
I2C_SendData(I2C1, RegAddress);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Send data
I2C_SendData(I2C1, Data);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Send stop signal
I2C_GenerateSTOP(I2C1, ENABLE);
}
This process is like delivering a package:
- 1. Wait for good road conditions (I2C idle)
- 2. Depart (send start signal)
- 3. Find the destination (send slave address)
- 4. Confirm the recipient (send register address)
- 5. Deliver the package (send data)
- 6. Return (send stop signal)
Practical Application Example
Let’s take reading data from the MPU6050 gyroscope as an example:
#define MPU6050_ADDR 0xD0
#define ACCEL_XOUT_H 0x3B
void ReadAccelData(int16_t* AccelX, int16_t* AccelY, int16_t* AccelZ)
{
uint8_t buffer[6];
// Read acceleration data
I2C_Write(MPU6050_ADDR, ACCEL_XOUT_H, 0); // Set read start address
// Read 6 bytes of data
for(int i = 0; i < 6; i++)
{
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
buffer[i] = I2C_ReceiveData(I2C1);
}
// Combine high and low bytes
*AccelX = (buffer[0] << 8) | buffer[1];
*AccelY = (buffer[2] << 8) | buffer[3];
*AccelZ = (buffer[4] << 8) | buffer[5];
}
Note: When reading multiple bytes of data, pay attention to the byte order! The MPU6050 data has high byte first and low byte last.
Common Problems and Solutions
- 1. I2C Bus Stuck
- • Reason: The slave device may not have released the SDA line
- 2. Communication Failure
- • Solution: Reinitialize I2C or manually send 9 clock pulses to clear the bus
- 3. Data Error
- • Confirm if the slave device address is correct
- • Check if the clock frequency matches
- • Confirm if the data format (such as endianness) is correct
Conclusion
Although I2C seems simple, mastering it requires a lot of practice. It is recommended to start with simple devices (like EEPROM) and gradually transition to more complex sensors. When using new devices, carefully read the datasheet, paying special attention to timing requirements and special instructions.
Mastering I2C is like learning to drive on the highway, enabling you to navigate smoothly in the world of microcontrollers. Start your I2C journey, and soon you will become an experienced driver in I2C communication!