How to Use the I2C Pins on LattePanda Mu in Ubuntu OS

userHead Youyou 2024-10-08 01:57:35 260 Views1 Replies

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

 

- LattePanda Mu

 

- Lite Carrier

 

- 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 PinsAT24C256 Module Pins
3V3VCC
GNDGND
SCLSCL
SDASDA

 

Software

 

- Ubuntu OS

 

- 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.