How to Use the I2C Pins on LattePanda Mu in Ubuntu OS
Background
LattePanda Mu has multiple I2C Ports, allowing direct communication with I2C devices after coding in the OS. This approach eliminates the need for a USB to I2C adapter or an MCU.
This article demonstrates how to identify BusNumber, program and use LattePanda Mu's I2C pins to read and write the AT24C256 EEPROM Module in an Ubuntu OS.
Preparation
Hardware
- AT24C256 I2C EEPROM Module
Wiring
The Lite Carrier of LattePanda Mu provides four I2C Ports as shown in the diagram below.
Connect the AT24C256 EEPROM Module to any one of the I2C Ports. The pin connections are listed in the table below.
Lite Carrier I2C Port Pins | AT24C256 Module Pins |
3V3 | VCC |
GND | GND |
SCL | SCL |
SDA | SDA |
Software
- python3
- i2c-tools
- smbus2
Installation and Initialization
- It is recommended to use the OS versions from the LattePanda Mu OS Compatibility List, as older versions may not function correctly.
- This article will use the i2cdetect command to identify the BusNumber of the I2C Port. This command is part of the i2c-tools package, which may not be installed by default on Ubuntu or other Linux distributions, so first, install the i2c-tools package.
sudo apt install i2c-tools
- This article will also use the smbus2 library and Python3 to program the I2C device, so they need to be installed.
sudo apt install python3 python3-pip
pip3 install smbus2
Detailed Steps
Expected Functionality: Write a code to store the value 0x42 at address 0x0000 on an AT24C256 EEPROM chip. Then, read back the value from address 0x0000 and compare it with the stored value to check if they are identical.
- Follow the steps outlined in the previous section to complete the wiring, and install the ubuntu OS and software libraries.
- Verify the BusNumber of the I2C Port
The index number marked on the Lite Carrier I2C Port may not match the BusNumber in the OS, so manual verification is needed. We can use the following command for this purpose.
sudo i2cdetect -y -r BusNum
Start testing the BusNum from 0 and increment until you find the 7-bit I2C address 0x50 of the AT24C256.
As shown in the following picture, the BusNumber is 3.
- Use the smbus2 library to write the code.
You can seek assistance from GPT-4o or Claude 3.5 while writing the code, which usually works after a few adjustments. The complete sample code is as follows:
from smbus2 import SMBus
import time
DEVICE_ADDRESS = 0x50 # AT24C256 I2C address
MEMORY_ADDRESS = 0x0000 # 16-bit memory address
VALUE_TO_WRITE = 0x42 # Value to write to EEPROM
def write_byte(bus, device_address, memory_address, data):
# Split 16-bit memory address into two bytes
addr_msb = (memory_address >> 8) & 0xFF # Most significant byte
addr_lsb = memory_address & 0xFF # Least significant byte
bus.write_i2c_block_data(device_address, addr_msb, [addr_lsb, data])
time.sleep(0.01) # Allow time for EEPROM to complete the write operation
def read_byte(bus, device_address, memory_address):
# Split 16-bit memory address into two bytes
addr_msb = (memory_address >> 8) & 0xFF # Most significant byte
addr_lsb = memory_address & 0xFF # Least significant byte
bus.write_i2c_block_data(device_address, addr_msb, [addr_lsb])
return bus.read_byte(device_address)
def main():
with SMBus(3) as bus: # Ensure correct bus number
print(f"Writing value 0x{VALUE_TO_WRITE:02X} to address 0x{MEMORY_ADDRESS:04X}")
write_byte(bus, DEVICE_ADDRESS, MEMORY_ADDRESS, VALUE_TO_WRITE)
time.sleep(0.1) # Short delay
print("Reading value back...")
read_value = read_byte(bus, DEVICE_ADDRESS, MEMORY_ADDRESS)
print(f"Read value: 0x{read_value:02X}")
if read_value == VALUE_TO_WRITE:
print("Success! Read value matches written value.")
else:
print("Error: Read value does not match written value.")
if __name__ == "__main__":
main()
- Save the above code as a .py script in a folder in the OS. For example, name it "i2ctest" and save it in the "Downloads" folder.
- In the terminal, run the following script using to see the output.
sudo python3 i2ctest.py
- Use a logic analyzer to observe the waveforms of writing and reading, which is comply with the datasheet specifications.
Write value 0x42 at address 0x0000
Read value from address 0x0000
FAQ
Q. From the waveforms for writing and reading showed by the logic analyzer, and the I2C address of the AT24C256 should be 0x80. Why is it 0x50 here?
A.
I²C Address Format
The I²C bus uses 7-bit addresses, with most devices, including the AT24C256, using a 7-bit address. An additional 1-bit read/write (R/W) bit is added to the 7-bit address, forming an 8-bit data transmission.
Explanation of AT24C256 Address
- 8-bit Address (including R/W bit): The write operation address for the AT24C256 is typically represented as 0xA0.
- 7-bit Address: In reality, the 7-bit address is 0x50. This is because 0xA0 shifted right by one bit (or divided by 2) results in 0x50.
Display Method of i2cdetect CMD
- The i2cdetect displays 7-bit addresses by default. Therefore, the address you detect using i2cdetect is 0x50.
- During actual communication, the I²C bus shifts the 7-bit address left by one bit and adds the read/write bit at the lowest position, making the write operation address 0xA0 and the read operation address 0xA1.