I2C Implementation in Python - cu-ecen-aeld/buildroot-assignments-base GitHub Wiki
I2C Implementation in Python
What is I²C?
- I²C, pronounced I-squared-C or I-2-C, is a popular serial communication protocol initially developed by Phillips Semiconductor (now NXP Semiconductor).
- It is widely used by major IC manufacturers for a variety of devices like microcontrollers, ADCs, DACs, EEPROMs, I/O devices, and real-time clocks.
- I²C is a multi-slave, half-duplex bus, meaning a master device communicates with multiple slave devices on the same bus, but communication occurs in only one direction at a time.
- On the Raspberry Pi, the Pi acts as the master while connected devices act as slaves.
Key Features:
- Two Wires:
- SDA (Serial Data): Carries data packets between the master and slave devices.
- SCL (Serial Clock): Synchronizes the data packets via a clock signal generated by the master.
- Pull-Up Resistors:
- SDA and SCL are connected to the +Vdd power wire via pull-up resistors, defaulting the bus to a high state.
- Typical voltages are 3.3V or 5V.
I²C in Python
There are multiple ways to implement I²C in Python. This documentation focuses on using low-level system calls.
Linux I2C Interface:
- I²C buses are represented as device files (e.g.,
/dev/i2c-1
) in Linux. - Tools like
i2cdetect
can identify the unique address of connected I²C devices.
Python Modules for I²C:
fcntl
: For file descriptor I/O control operations.struct
: For packing and unpacking data in binary formats.ctypes
: For low-level memory and data type operations.
Configuring I²C on Raspberry Pi
If you are using a Raspberry Pi, you must configure its I²C hardware to enable communication. Follow the steps in the Raspberry Pi Hardware Hints - I²C section for detailed instructions.
Note: This guide for enabling I²C is tailored for Raspberry Pi. If you're using a different platform, you may need to adapt the configuration to match your hardware's requirements.
Implementation Steps
Step 1: Initialize I²C Device
Open the I²C device file and set the slave address:
import fcntl
# I²C Settings
DEVICE = 0x27 # Replace with your device's I²C address
I2C_SLAVE = 0x0703 # I²C_SLAVE operation code
# Open the I²C bus
i2c_file = open('/dev/i2c-1', 'rb+', buffering=0)
fcntl.ioctl(i2c_file, I2C_SLAVE, DEVICE) # Set the I²C device address
Step 2: Create Utility Functions
Writing Data:
Write a single byte to the I²C device:
def write_byte(data):
"""Write a single byte to the I²C device."""
i2c_file.write(bytearray([data]))
Reading Data:
Read a sequence of bytes starting from a specific register:
def read_bytes(register, length):
"""
Read a sequence of bytes from the I²C device.
:param register: Starting register address.
:param length: Number of bytes to read.
:return: List of bytes read.
"""
i2c_file.write(bytearray([register])) # Set the register pointer
return list(i2c_file.read(length)) # Read the data
Step 3: Example Applications
Example 1: BMP180 Sensor Communication
The BMP180 sensor is used to read temperature , altitude and pressure data over I²C.
Refer to the BMP180 I2C interface for full implementation details.
Example 2: I²C LCD Communication
The I²C-enabled LCD is controlled to display strings using specific commands.
Refer to the I2C LCD Interface for complete code.