0
0
Power-electronicsHow-ToBeginner · 4 min read

How to Configure I2C in Embedded C: Simple Guide

To configure I2C in embedded C, you need to set up the I2C control registers for speed, enable the I2C module, and configure the pins for SDA and SCL. Then, write code to start communication, send addresses, read/write data, and stop communication using the microcontroller's I2C registers.
📐

Syntax

The basic steps to configure I2C in embedded C involve setting control registers, enabling the I2C peripheral, and configuring pins. Typical registers include:

  • I2C Control Register (I2C_CR): Enables I2C and sets master/slave mode.
  • I2C Clock Register (I2C_CLK): Sets the clock speed for communication.
  • I2C Data Register (I2C_DR): Holds data to send or receive.
  • I2C Status Register (I2C_SR): Shows status flags like start, stop, and acknowledge.

These registers vary by microcontroller but the pattern is similar.

c
void I2C_Init(void) {
    I2C_CR = 0x01;       // Enable I2C module
    I2C_CLK = 0x50;      // Set clock speed (example value)
    // Configure SDA and SCL pins as needed
}

void I2C_Start(void) {
    I2C_CR |= 0x02;      // Send start condition
    while (!(I2C_SR & 0x01)); // Wait for start flag
}

void I2C_Stop(void) {
    I2C_CR |= 0x04;      // Send stop condition
}

void I2C_Write(uint8_t data) {
    I2C_DR = data;       // Load data
    while (!(I2C_SR & 0x02)); // Wait for transmit complete
}

uint8_t I2C_Read(void) {
    while (!(I2C_SR & 0x04)); // Wait for data received
    return I2C_DR;       // Read data
}
💻

Example

This example shows how to initialize I2C, send a start condition, write a device address, send data, and stop communication.

c
#include <stdint.h>
#include <stdio.h>

// Simulated registers for demonstration
volatile uint8_t I2C_CR = 0;
volatile uint8_t I2C_CLK = 0;
volatile uint8_t I2C_DR = 0;
volatile uint8_t I2C_SR = 0;

void I2C_Init(void) {
    I2C_CR = 0x01;       // Enable I2C
    I2C_CLK = 0x50;      // Set clock speed
}

void I2C_Start(void) {
    I2C_CR |= 0x02;      // Start condition
    I2C_SR |= 0x01;      // Start flag set
}

void I2C_Stop(void) {
    I2C_CR |= 0x04;      // Stop condition
    I2C_SR &= ~0x01;     // Clear start flag
}

void I2C_Write(uint8_t data) {
    I2C_DR = data;
    I2C_SR |= 0x02;      // Transmit complete flag
}

int main(void) {
    I2C_Init();
    I2C_Start();
    I2C_Write(0xA0);    // Device address + write bit
    I2C_Write(0x55);    // Data byte
    I2C_Stop();
    printf("I2C communication done.\n");
    return 0;
}
Output
I2C communication done.
⚠️

Common Pitfalls

  • Not enabling the I2C peripheral: Forgetting to set the enable bit in the control register stops communication.
  • Incorrect clock speed: Setting wrong clock values causes timing errors and failed communication.
  • Not waiting for flags: Skipping status flag checks can cause data loss or bus errors.
  • Pin configuration errors: SDA and SCL pins must be set as open-drain or alternate function as required.
c
/* Wrong: Not enabling I2C before start */
void I2C_WrongInit(void) {
    I2C_CLK = 0x50;      // Clock set but I2C_CR enable bit missing
}

/* Right: Enable I2C before use */
void I2C_CorrectInit(void) {
    I2C_CR = 0x01;       // Enable I2C
    I2C_CLK = 0x50;      // Set clock
}
📊

Quick Reference

Remember these key points when configuring I2C:

  • Enable the I2C module before starting communication.
  • Set the clock speed to match your device's requirements.
  • Configure SDA and SCL pins correctly for I2C function.
  • Always check status flags before sending or receiving data.
  • Send start and stop conditions properly to frame communication.

Key Takeaways

Always enable the I2C peripheral by setting the control register before use.
Set the correct clock speed to ensure proper timing for I2C communication.
Configure SDA and SCL pins as open-drain or alternate function as required by your MCU.
Check status flags after each operation to avoid data loss or bus errors.
Use start and stop conditions to frame each I2C transaction correctly.