rtems, gsoc, libbsd,

Using the I2C adaptation layer to read EEPROM

Vijay K. Banerjee (thelunatic) Vijay K. Banerjee (thelunatic) Jun 02, 2019 · 3 mins read
Using the I2C adaptation layer to read EEPROM
Share this

The I2C adaptation layer work is complete now and it is indeed working as a layer in between the RTEMS i2c stack and the iicbus stack in FreeBSD. But it’s not enough to see that the /dev/iic0 is being created as any call to the iic0 is basically going to the RTEMS i2c-0 device. That’s what we intended through the i2c-adaptation layer.

To test the driver I decided to create a sample application outside of the rtems-libbsd and use the RTEMS api to register the i2c-0 bus and then use the FreeBSD calls to read from the EEPROM, which will get directed to the i2c-0 device. As there has been no app like this in the RTEMS directories (in my knowledge), I forked the repo rtems-bbb created by Christian Mauderer. Then I started building my app in there. As I have discussed above, the app is going to be a very basic one and what we intend to do is something like this:

  • Register the i2c-0 device.
  • call the rtems_bsd_initialize().
  • Read the EEPROM using ioctl call.

So basically the Init() (The entry point of the app), was sorted. What we need is the function to read EEPROM. The approach is to first open() the iic0 device then set a test iic_msg * message. Store it in a variable of type iic_rdwr_data and call ioctl() on it.

Here’s the Sample eeprom_read() from the app. And that’s basically it:

int
read_eeprom(int address)
{
	int		fd;
	int		ret;
	uint8_t		wbuf[2];
	uint8_t		rbuf[2];
	struct iic_msg 	msg[2];
	struct iic_rdwr_data rdwr;

	if ((fd = open(I2C_BUS, O_RDWR)) < 0) {
		perror("open");
		return (-1);
	}

	msg[0].slave = EEPROM_ADDRESS << 1;
	msg[0].flags = 0;
	msg[0].len = 1;
	wbuf[0] = 0xff & address;
	msg[0].buf = wbuf;

	rbuf[0] = 0;
	rbuf[1] = 0;

	msg[1].slave = (EEPROM_ADDRESS << 1) | IIC_M_RD;
	msg[1].flags = IIC_M_RD;
	msg[1].len = 2;
	msg[1].buf = rbuf;

	rdwr.msgs = msg;
	rdwr.nmsgs = 2;

	ret = ioctl(fd, I2CRDWR, &rdwr);

	if (ret < 0) {
		perror("ioctl(I2CRDWR)");
		ret = (-1);
	} else
		ret = (rbuf[0] << 8) + rbuf[1];

	close(fd);

	return (ret);
}

It is to be noted that this is returning int and not dumping a hex, which would have been more desirable but since this is just to test the working of the driver, this would be just fine ;-)

Along with the EEPROM read function, I have added the i2c tool from FreeBSD and that acts as a full fledged test for the whole i2c stack, The tool works great with the current state of drivers but it lacks the transfer mode (as of now) but it will certainly work after the libbsd update as I have tested the latest patch in FreeBSD upstream that adds the transfer mode to the app.

Here’s the link to the exact app directory, since it is GitHub, you can keep an eye for any further changes in the application.

If anyone is trying to build and run the app on a Beaglebone Black, then you’ll have to remember to use the create-dtb.sh to create the dtb with the applied overlay to make the driver work. For now you’ll have to manually replace the original dtb with the generated dtb file. But I’ll soon try to to make it all automatic.

Thanks for the patient reading and as always, any feedback or discussion is really appreciated!