24x Serial EEPROM ICs driver in Rust

AT24C256 module

I have been learning Rust on and off for quite a while and embedded systems have always been interesting for me.

At some point I discovered the Discovery book and decided to turn back to the embedded fun I did not touch since my childhood.

After completing the book I was looking for something useful to do and wrote this driver for the common 24x Serial EEPROM IC series as part of the Weekly Driver Initiative. This platform-agnostic driver is based on embedded-hal.

I wrote this driver following Test-Driven-Development using the embedded-hal-mock crate which was very helpful.

The devices

The devices are serial EEPROM (Electrically Erasable and Programmable Read-Only Memory) ICs, with different capacities, which communicate using I²C. With these devices it is possible to store data which will persist on the absence of power.
There are many vendors that have compatible ICs on their portfolios and seem to have a common “24“ family name, hence the name of the driver.
For example, Microchip has ICs like AT24C32, 24AA32A and AT24C256 whereas STMicroelectronics has ICs like M24C32.

There may also be other vendors that have compatible ICs under a different name. If you know of some of these, please let me know and I will add them to the list of compatible devices.

This driver attempts to be compatible with many of these ICs.

In this blog post I will use the AT24C256C. You can buy the device on AliExpress or eBay for a few cents.

There are also many Real-Time-Clock (RTC) modules, typically for Arduino, that include an RTC IC like the DS1307 and also an AT24C32 EEPROM IC so you may already have an EEPROM IC that you can use.

The driver

This driver allows you to:

  • Read a single byte from a memory address. See: read_byte
  • Read a byte array starting on a memory address. See: read_data
  • Read the current memory address (please read notes). See: read_current_address
  • Write a byte to a memory address. See: write_byte
  • Write a byte array (up to a memory page) to a memory address. See: write_page

Can be used at least with the devices AT24C32, AT24C64, AT24C128, AT24C256 and AT24C512.

Using the driver

To use the device from Rust, you have to add the eeprom24x crate to your project as well as a concrete implementation of the embedded-hal traits. For example if you are using the Raspberry Pi running Linux, you can use linux-embedded-hal.

1
2
3
4
5
# Cargo.toml
...
[dependencies]
eeprom24x = "0.1"
linux-embedded-hal = "0.1"

This is an example program writing and reading some data from the memory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extern crate embedded_hal;
extern crate linux_embedded_hal;
extern crate eeprom24x;

use embedded_hal::blocking::delay::DelayMs;
use linux_embedded_hal::{I2cdev, Delay};
use eeprom24x::{Eeprom24x, SlaveAddr};

fn main() {
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let mut eeprom = Eeprom24x::new_24x256(dev, SlaveAddr::default());
let memory_address = [0x12, 0x34];
let data = 0xAB;

eeprom.write_byte(&memory_address, data).unwrap();

Delay.delay_ms(5u16);

let retrieved_data = eeprom.read_byte(&memory_address).unwrap();

println!("Read memory address: [{},{}], retrieved content: {}",
memory_address[0], memory_address[1], &retrieved_data);
}

This example is also available in the crate sources here.

Where to go from here?

There is much more information and example programs in the crate documentation.
Please give this driver a try and report any issues you may encounter in the issue tracker.
Feedback, suggestions and improvements are gladly welcome.

What’s next?

I have a driver for the popular DS1307 real-time clock (RTC) and a WIP driver for the popular I/O expanders PCF8574, PCF8574A and PCF8575. I will announce them here soon.

Thanks for reading and stay tuned!

Links:

Share