chipKIT® Development Platform

Inspired by Arduino™

Adafruit I2C Backpack

Created Sat, 20 Aug 2016 02:26:25 +0000 by jmlynesjr


Sat, 20 Aug 2016 02:26:25 +0000

Hello all:

I purchased an Adafruit I2C Backpack(Product ID 292) and the 4 x 20 Character LCD.

Is this combination supported by the LiquidCrystal library under UECIDE? Any documentation/example code available?

Thanks, James


Sat, 20 Aug 2016 11:18:06 +0000

I have never worked with any of the I2C backpacks, so I have no idea if it will work or not. From what I have seen in the past you need "LiquidCrystal_I2C.h" wherever that comes from.

In theory, as long as it just works with Wire.h the standard Arduino library should just work with any board. It's only when they start doing strange things with AVR registers or assembly language that things go belly up. All I can suggest is try out the examples that come with the library and see what happens.


Mon, 22 Aug 2016 01:29:56 +0000


Thanks Matt.

I reviewed the Adafruit LCD library, Adafruit MCP23008 library, and the MCP23008 data sheet in gory detail.

Looks like I will be able to add MCP23008 initialization code to I2C code I have previously used with a Sparkfun I2C Backpack. I only need byte wide writes and can delete the bit manipulation code. Set all GPIO pins as outputs and write LCD control bytes through the GPIO register on the MCP23008.

Now I have a bunch of header pins to solder in.



Thu, 25 Aug 2016 19:07:17 +0000


"There are no five minute jobs..." (It's a long story)

The Sparkfun I2C backpack uses an Atmel chip and thus hides the bit twiddling from the user.

The Adafruit I2C backpack uses an I2C port expander chip which leaves all of the bit twiddling to the user.

Read Microchip's AN587, "Interfacing PICmicro MCUs to an LCD Module", LCD section of John Peatman's(my favorite college professsor at GT) "Design with PIC Microcontrollers", and the LCD section of Tim Wilmshurst's "Designing Embedded Systems with PIC Microcontrollers Principles and Applications", both of which have good assembly language examples, started reading the HD44780 data sheet.

I prefer to write my own drivers so that I know what's going on and so that I can document the process. What I've seen so far is very poorly documented, IMHO.



Thu, 25 Aug 2016 21:08:59 +0000

The LCD protocol is pretty easy really. There's only about 10 commands with different bits that can be set / not set. The tricky bit comes with making the I2C interface create the right clock pulses etc.

I am guessing it has an 8-bit expander and is running the LCD in 4-bit mode, which gives you 4 spare bits for the E, RS, and R/W pins leaving one over for maybe controlling the back-light or something.


Fri, 26 Aug 2016 15:43:24 +0000


You hit the nail on the head. 8-bit port expander, 4-bit interface, and a few commands.

I have about about accumulated enough examples to put something together. I found a copy of LiquidCrystal_I2C and it appears to be a stripped down version of the "standard" LCD library, but is set up for a different I2C port expander and bit definition.

For whatever reason Adafruit decided to stick the 4 data bits in the middle of the byte instead of on a nibble boundry. BIG DUH! Complicates the bit twiddling.

From what I have seen in several drivers, the hassle seems to come from reading the busy flag bit. They have to keep flipping the port expander between reading and writing. I may try a stripped down delay based implementation and forget the busy bit for now.

Soapbox: Folks, just because this is a hobby, don't release undocumented code on the world.



Fri, 26 Aug 2016 21:46:41 +0000

Documentation is a crutch for people who can't handle true excitement :P

Instead of bit-twiddling you should maybe use a union + anonymous struct. Something like:

typedef union {
    uint8_t val;
    struct {
        unsigned e:1;
        unsigned rw:1;
        unsigned data:4;
        unsigned :1;
        unsigned rs:1;
} __attribute__((packed)) xfer;

xfer myData; = 7;
myData.e = 1;
myData.e = 0;

If you understand what I am getting at there... Of course your anonymous struct has to be in the right order...


Mon, 29 Aug 2016 18:05:22 +0000


The union/struct looks very useful. I admit I had to look it up in a C++ tutorial doc that I have. Also a comment on Stack Overflow indicated that the construct is often used in embedded systems for breaking out groups of bits within words.

Next question: The Adafruit LCD library #include(s) the Adafruit MCP23008(port expander) library. I spent awhile looking for how the MCP23008 was being initialized. I expected to see a call from within the LCD constructor. What I found was Adafruit_MCP23008 _i2c; as the last line of the LCD header file. Is it common to instantiate a class member of one library from within the header file of another library?

Thanks, James


Mon, 29 Aug 2016 20:13:23 +0000

Not in the header file, no. In the CPP file, possibly yes, and then an extern reference in the header file. Although I would personally not do either.


Tue, 30 Aug 2016 14:54:57 +0000

I thought it looked weird too.

How would you set it up?



Tue, 30 Aug 2016 18:22:34 +0000

I would either inherit the expander as a parent class and (forgive the pun) expand on it, or pass an expander object (or a pointer to one) to the constructor of the LCD class.

If I absolutely had to have it within the LCD files then it would be within the LCD class.

By creating the object in the header file outside of any class you risk making multiple copies in different CUs.