How-To EEPROM
Description
The Pi-Tron CM4 has an M24C32 EEPROM onboard, which offers the user 4 Kbytes of special storage for any kind of data. What's interesting about this EEPROM is, that it is compatible with a similar EEPROM named AT24xxx for which the Raspberry Pi OS includes a driver to access the EEPROM via a SysFS interface. However, currently there is no device tree file which uses this AT24 driver.
This How-To will try to show 2 ways to use and work with the EEPROM on the Pi-Tron CM4. The first part will be a direct communication via I2C with the chip programmed in Python. The second part will use a self-made device tree file which activates the AT24 driver and creates a SysFS interface in the OS for the user to work with.
Requirements
- 24 volts power supply with 2 pin power plug for the Pi-Tron CM4.
- Development computer with network access to the Pi-Tron CM4 or alternatively connect an HDMI monitor, mouse and keyboard.
- To login into the Pi-Tron CM4 via network, it is requires that the SSH server is running.
- The login details are by default: username: pi and password: raspberry
- Note: The latest version of the Raspberry Pi OS requires the user creating the initial SD card or writing the system to eMMC memory to choose a username and password or the information has to be entered during first boot of the system. The above mentioned defaults may not apply to your situation.
- A Terminal application (e.g. TeraTerm or Putty on the Windows host, or screen on Linux).
- An active Internet connection to install additional software.
- The EEPROM is connected to I2C bus 1 and has the address 0x50.
How-To
Preparation
Activate I2C
First make sure the I2C bus 1 is activated. Use the raspi-config program to enable the I2C interface, if this is not already the case. Afterwards reboot the Pi-Tron CM4.
Install the SMBus Python module
To access any device on the I2C bus from Python, the module SMBus can be used. To install the SMBus module use pip for example.
On Raspberry Pi OS versions before Bullseye run this command to install the module globally.
sudo pip3 install smbus
If the Raspberry Pi OS version is Bullseye or later, try this command instead.
sudo pip install smbus
Starting with Raspberry Pi OS Bullseye only Python 3 is installed by default, which means pip3 defaults to pip and python3 defaults to python. In the past pip and python without a number would default to Python 2.
Install the i2c-tools
Installing the i2c-tools allows the user to perform an I2C bus scan to see which addresses (devices) are available on the bus.
sudo apt update
sudo apt install i2c-tools
Accessing the EEPROM via I2C
The EEPROM is connected to I2C bus 1 on the Pi-Tron CM4 and has the address 0x50. This means using the SMBus module in Python, the EEPROM can be accessed directly via I2C under that address. With a few lines of Python code reading and writing from and to the chip can be done in a fairly straightforward manner.
The examples shown below utilize a byte oriented access, which might not offer the best performance but allows for a free access to the stored data or to write/modify existing data on the chip.
-
Log in into the Pi-Tron CM4 and run the i2cdetect program to see if the EEPROM is present at address 0x50.
sudo i2cdetect -y 1
-
The result should look something like the following table:
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: 50 -- 52 -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Write data to the EEPROM
-
With the EEPROM now accessible, writing data to it can be done with the following example or download the example program eeprom_write_example.py.
#!/usr/bin/env python3 import smbus import time # The EEPROM address is by default 50h eepromadr = 0x50 # To write a byte to an address byte of the EEPROM, a 2 byte address is needed eepromdata = [0] * 2 # The EEPROM is connected to I2C Bus 1 i2cbus = 1 # Create an I2C Bus 1 instance mybus = smbus.SMBus(i2cbus) # Wait for the bus to initialize time.sleep(1) # Data (text) to store in the EEPROM mytext="The quick brown fox jumps over the lazy dog" # Convert the string to bytes mybytes = mytext.encode() # Write mytext to the EEPROM for i in range(0 ,len(mytext)): # Using "i" as the address selector and splitting it up into # the 2 needed address bytes for the EEPROM chip eepromdata[0] = i & 0xFF # Low address byte eepromdata[1] = (i >> 8) & 0xFF # High address byte # Create an address and data array combination. # The first byte must be the lower address byte and the byte # to write to the EEPROM must be second byte. data = [eepromdata[0], mybytes[i]] # Writing one byte to the EEPROM. The high address byte # is used for the address parameter. The SMBus function then creates # the needed sequence: Device-Selector, Adr-Byte-1, Adr-Byte-0, Data-Byte # on the bus as shown in the datasheet for the M24C32 EEPROM chip. mybus.write_i2c_block_data(eepromadr, eepromdata[1], data) # After a write, wait a short while time.sleep(0.015) print(str(len(mytext)) + " bytes written to EEPROM")
-
Run the Python program to write some data to the EEPROM.
pi@raspberrypi:~ $ sudo python eeprom_write_example.py 43 bytes written to EEPROM
Read data from the EEPROM
-
Once the program completes, the information is now stored on the EEPROM and is available for further use. The next example will try to read the data from the EEPROM and print it to the console. Download the example program eeprom_read_example.py.
#!/usr/bin/env python3 # Note: Run the EEPROM write example before running the read example! import smbus import time # The EEPROM address is by default 50 hex eepromadr = 0x50 # To read an address byte from EEPROM, a 2 byte address is needed eepromdata = [0] * 2 # The EEPROM is connected to I2C Bus 1 i2cbus = 1 # Create an I2C Bus 1 instance mybus = smbus.SMBus(i2cbus) # Wait for the bus to initialize time.sleep(1) # Store the text read from the EEPROM. Requires that the # EEPROM write example was run beforehand. mytext="" # The text whih should be in the EEPROM textineeprom="The quick brown fox jumps over the lazy dog" # Read the first bytes as needed from the EEPROM in sequence for i in range(0, len(textineeprom)): # Using "i" as the address selector and splitting it up into # the 2 needed address bytes for the EEPROM chip eepromdata[0] = i & 0xFF # Low address byte eepromdata[1] = (i >> 8) & 0xFF # High address byte # Send the address change request to the EEPROM mybus.write_byte_data(eepromadr, eepromdata[1], eepromdata[0]) # Read the selected byte from the EEPROM j = mybus.read_byte(eepromadr) # Convert the read byte into a character and add it to a string mytext += chr(j) # Once done, print the string to the console print (mytext)
-
Run the Python program to read back the data which was just written to the EEPROM.
pi@raspberrypi:~ $ sudo python eeprom_read_example.py The quick brown fox jumps over the lazy dog
Accessing the EEPROM through SysFS
The EEPROM can also be access through a SysFS interface which is provided by the Linux driver at24 (24c32). The only problem right now is that there is no device tree overlay to activate the driver. This means an overlay has to be created in order to utilize the EEPROM. An example DTS file can be downloaded from here.
Device Tree Overlay
This device tree file will load the at24 driver and also tells the driver that the EEPROM has address 0x50, a pagesize of 32, has 4096 bytes of storage and the register-address is 16 bits.
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c1>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
clock-frequency = <100000>;
status = "okay";
at24@50 {
compatible = "atmel,24c32","at24";
reg = <0x50>;
pagesize = <32>;
size = <4096>;
address-width = <16>;
};
};
};
};
Compiling
In order for the Raspberry Pi OS to use the device tree overlay, the above shown text version has to be compiled in to a dtbo file which the OS can read.
- Place the downloaded file on the Pi or create one manually and name it at24c32.dts for example.
-
Place the file in the pi users home folder for example and then issue the compile command
dtc -O dtb -o at24c32.dtbo -b 0 -@ at24c32.dts
-
Now the compiled device tree file can be copied to the overlays folder in the boot partition of the SD card or eMMC memory.
sudo cp at24c32.dtbo /boot/overlays/
Configure Overlay
-
The final step is to edit the config.txt file and add the overlay for the EEPROM.
sudo nano /boot/config.txt
-
At the end of the file add
# EEPROM at adr 0x50 dtoverlay=at24c32
-
Reboot the Raspberry Pi
sudo reboot
Verify the driver was loaded
After the reboot it makes sense to check that the driver for the EEPROM was actually loaded, otherwise the following examples would not work.
pi@raspberrypi:~ $ dmesg | grep at24
at24 1-0050: supply vcc not found, using dummy regulator
at24 1-0050: 4096 byte 24c32 EEPROM, writable, 32 bytes/write
The driver should produce to messages in the Kernel log, otherwise something went wrong.
Write data to the EEPROM
To write data to the EEPROM using the SysFS interface the commands echo and tee can be combined.
echo 'Hello World!' | sudo tee /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom
Executing this command will initiate a data transfer of the string Hello World! to the EEPROM, but also print Hello World! to the console.
Read data from the EEPROM
To read data from the EEPROM through the SysFS interface the command more can be used.
sudo more /sys/class/i2c-dev/i2c-1/device/1-0050/eeprom
This command will read the entire EEPROM storage and print it to the console. The first part should be the Hello World! text from earlier, but the rest are just some placeholder characters signaling that the remaining space in the EEPROM is empty.
Hello World!
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
This concludes the How-To for the EEPROM on the Pi-Tron CM4. Writing and read to and from the EEPROM should now be possible, either directly with a program or through the SysFS driver.
Restrictions
- No known Restrictions
Related documentation
- Covering all aspects of the Raspberry Pi, the official documentation: https://www.raspberrypi.com/documentation
- Documentation for the raspi-config tool: https://www.raspberrypi.com/documentation/computers/configuration.html
- Linux I2C-Tools package: https://i2c.wiki.kernel.org/index.php/I2C_Tools
- Manpages i2c-tools: https://manpages.debian.org/bullseye/i2c-tools/index.html
- Raspberry Pi OS Bullseye release: https://www.raspberrypi.com/news/raspberry-pi-os-debian-bullseye
- Raspberry Pi OS now requires users to create their own login credentials on first boot: https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022