Overview of I2C Bus
The Inter-Integrated Circuit (I2C) protocol enables half-duplex serial communication common used with devices like OLED displays and gyroscopes. The bus consists of three lines: SCL (clock), SDA (data), and ground.
OLED Display Control Architecture
Hardware Layer
OLED screens utilize the SSD1306 controller chip for operation. To display content, applications write data to the controller's GDDRAM (Graphics Display Data RAM). The controller continuously refreshes the screen by reading from this memory.
Software Stack
- Application layer determines display content and position
- Graphics library converts characters to pixel patterns and invokes driver functions
- SSD1306 driver manages I2C communication protocols for writing data to display memory
- HAL driver handles low-level I2C data transmission
I2C Communication Protocol
Supports one master with multiple slave devices configuration.
Signal Timing
- Start condition: SDA transitions from high to low while SCL remains high
- Data transfer: SDA sampled when SCL is high, changed when SCL is low
- Acknowledge: Receiver pulls SDA low during the ninth clock cycle after byte transmission
- Stop condition: SDA transitions from low to high while SCL remains high
Open-Drain Design Principle
Both SCL and SDA lines use open-drain outputs with external pull-up resistors. This prevents bus conflicts where one device drives high while another drives low, avoiding potential damage.
Hardware Architecture
STM32 I2C Controller Registers
- Data register (DR): Handles SDA data through shift register interface
- Clock control register (CCR): Configures SCL timing parameters
- Control registers (CR1/CR2): Manage operation modes and interrupt/DMA enablement
- Status registers (SR1/SR2): Monitor transmission state and error conditions
Transmission Control
Generate start condition by setting CR1 bit 8. Monitor SR1 bit 0 to confirm generation. Data transmission proceeds by polling status flags or using interrupt-driven approaches.
HAL Library Implementation
Master Mode Operations
// Transmit data to slave device
HAL_StatusTypeDef transmit_result = HAL_I2C_Master_Transmit(
&hi2c1, // I2C handle
0xD0, // Device address (7-bit left-shifted)
tx_buffer, // Data pointer
buffer_size, // Number of bytes
1000 // Timeout in milliseconds
);
// Receive data from slave device
HAL_StatusTypeDef receive_result = HAL_I2C_Master_Receive(
&hi2c1, // I2C handle
0xD0, // Device address
rx_buffer, // Data buffer
buffer_size, // Number of bytes
1000 // Timeout period
);
Memory Access Mode
For register-based devices requiring two-phase operations:
// Read from specific register
HAL_StatusTypeDef read_status = HAL_I2C_Mem_Read(
&hi2c1, // I2C handle
0xD0, // Device address
0x75, // Register address
I2C_MEMADD_SIZE_8BIT, // Address size
data_buffer, // Output buffer
1, // Bytes to read
1000 // Timeout
);
// Write to specific register
HAL_StatusTypeDef write_status = HAL_I2C_Mem_Write(
&hi2c1, // I2C handle
0xD0, // Device address
0x6B, // Register address
I2C_MEMADD_SIZE_8BIT, // Address size
&config_value, // Data to write
1, // Bytes to write
1000 // Timeout
);
MPU6050 Sensor Example
Write Operation Sequence
- Send device address with write flag
- Specify target register address
- Transmit data value
Read Operation Sequence
- Send device address with write flag
- Specify register address to read
- Send device address with read flag
- Receive data from sensor
Sample Configuration
Device address: 0x68 (binary 1101000) Target register: 0x75 Expected read value: 0x68 (default WHO_AM_I response)
Interrupt-Driven Approach
Unlike polling methods, interrupt-based implementations eliminate timeout parameters. After initialization and interrupt enabling, functions return immediately. Completion events trigger callback functions for further processing.