How do I convert a LCD backpack to generic 8-bit I2C expander?

Background

My junque box ("junque" means "fancy, high-class junk" :wink: ) contains several of those ubiquitous, PCF8574T-based LCD "backpack" I2C interface boards. But I have no generic I2C expander board, which I would like to use for connecting a 4x4 16-button keypad (using I2C).

The type of "backpack" boards that I have all look like this:

And the schematic is as follows (at least, I am pretty sure this is the correct schematic for the PCB shown above):

So I want to try to convert a LCD "backpack" into a generic 8-bit I2C expander, with all 8 bits available on (what used to be) the LCD connector pins.

Unfortunately for this project, PCF8574T signal P3 does not go directly to a LCD connector pin, but rather to the base of the switching transistor, to control the LCD backlight. So I want to remove the transistor and its 4.7K base pull-up resistor from the PCB, and then jumper a wire from the transistor base pad (on the PCB) to the LCD connector "DB0" signal (J1 pin 7). This would put the PCF8574T port signals P0 to P3 on J1 pins 4 to 7 (respectively), and PCF8574T signals P4 to P7 on J1 pins 11 to 14 (respectively).

For power saving (in case I ever want to battery-power my project), I would also remove the contrast control pot and the power indicator LED and/or its 1K resistor.

I am hoping that someone here might be familiar with this particular LCD Backpack board, and could answer a few questions.

Questions

  1. There are three 4.7K resistors on the board (marked "472"): one for the transistor base pull-up and the other two for the I2C pull-ups. Am I correct to assume that the transistor's 4.7K base pull-up resistor is the one that is physically located (on the PCB) between the transistor and the power filter capacitor?

  2. If I want to hang more devices on the I2C bus (e.g. a second LCD backpack that actually drives a LCD display :wink: ), should I remove the two I2C 4.7K pull-ups from one of the adapter (backpack) boards? (If so, then I would remove all three 4.7K resistors from the board I am using for the keypad.) I believe that the I2C spec calls for only one pull-up resistor on each of the SCL and SDA signals.

  3. I am wondering if the various I2C libraries (e.g. Wire.h, TinyWireM.h, etc.) actually use the AVR's internal input pull-ups for use as the I2C pullups? If the internal pull-ups are within the correct range (??), then doing this would make sense, and elminate the need for external pull-up resistors on the I2C lines. If the libraries do this, then, perhaps, none of the I2C adapter boards should have any on the I2C pins. (??)

Thanks, in advance, for your help.

I think there are multiple sources that indicate that the Arduino's built-in I2C pull-up is too high (in resistance) and won't work properly.
4.7K at 5V will result in about ... 1mA current. Most things can safely drain at least 5mA. You can leave them there. Just make sure there are nothing else that have the resistors.

I think I had looked into the Wire library (which is also the official Arduino I2C library) earlier but I found nothing helpful. Mostly because how it's insanely difficult to understand something when 20 files are interlinked together and are wrote by the same person/group.
Perhaps this explains why (the resistance is considered "too high") as I think the internal pull-ups are something like 26K, which is good for buttons but not for I2C. Unless there is dedicated hardware for the I2C (a likely case but maybe not at the output buffers/registers), that's what you get.

Thank you for your very quick reply, @cdr_xavier. So if I read your comment correctly, I should remove the I2C pull-ups from all I2C adapter boards, except one. Correct?

I think that would be what I am trying to say. You will need those resistors because the one on the microcontroller is too weak to power especially multiple devices

I think I got it! Thanks.

So my first question is moot, since I can safely remove all three 4.7K resistors from the "backpack" board used for the keypad (given that I am using a second backpack board for the actual LCD display). Since the second backpack board will keep the I2C pull-up resistors, these pull-ups are not needed on the first board.

And since I can remove all 3 4.7K resistors from the "keypad" board, it does not really matter which 4.7K resistor was the one used for the transistor base pull-up. :slight_smile:

Edit: Forgot to mention that, of course, I will also need to change the address jumpers on one of the two "backpack" boards. :slight_smile:

1 Like

Summary

So looking at the PCB, it looks like I can remove everything between the PCF8574T IC chip and the 2-pin backlight jumper headers, except the power filter capacitor. And I can also remove the contrast pot. Then connect a jumper wire from the transistor base pad (on the PCB) and J1 pin 7. This will result in a generic I2C expander board, with eight digital signals on J1 pins 4 to 7 and pins 11 to 14.

But it will need a second I2C adapter, to provide the I2C pull-up resistors (which will be provided with a second LCD backpack board that is actually used to drive a LCD display).

In a more systematic approach you'll remove all pullups and insert one pair in the cable from your controller to the first I2C module.

How do you connect multiple I2C boards to your controller?

Agreed. But since the manufacturer(s) of the LCD backpack boards chose to put the pull-ups directly on these boards, I will just use the pull-ups as-is on the board that I use for the LCD controller. However, as you wrote, the pull-ups should really be external, either at the I2C "master" or somewhere else on the I2C bus.

Curiously, I have seen projects on the web that connect two LCD backpacks (for two displays) on the same I2C bus without modification, so I presume these will still work with the two sets of pull-ups connected to the I2C bus. (But I do not know how many of these could be connected together before the I2C signaling starts to fail.)

So I probably do not actually have to remove the I2C pull-ups from one of my two "backpack" boards. But since I need to remove one 4.7K resistor from the "keypad board" (the switching transistor base pull-up) and since I am not sure (but have a good idea) which of the three 4.7K resistors that is, I may as well remove the other two 4.7K resistors (the I2C pull-ups) from my "keypad backpack" since, technically, they should not really be there, anyway (given that the I2C pull-ups already exist on the LCD backpack).

Keep in mind that I have not actually done this yet, but for prototyping, I will be using a UNO, NANO, or DigiSpark, and just have flying jumper leads to a breadboard, to connect the I2C signals and power/ground, between the Arduino processor board and the two "backpacks" (one for the LCD display and one for the keypad). Since there will be a gap in the 8 digital signal pins on the header for my "keypad backpack board", I will also need to connect the 8-pin keypad connector to the "backpack" board using jumpers/leads or some kind of header adapter.

I have not really figured out how it will all be connected in the final version. I expect that I will have a main PCB (or perf board) with an AVR processor chip (ATmega328 or ATtiny85; or possibly a NANO or DigiSpark "daughter board" - not decided yet) and somehow mount the main board directly onto the LCD 4-pin backpack connector. The "keypad backpack" board would have its 4-pin right-angle header replaced by a straight header, to allow mounting the "keypad backpack" on the main board.

(Of course, I could just order some PCF8574 chips to replace the "backpack" boards and mount them on my main PCB or perf-board. But since I already have the LCD backpack boards on-hand, I just may as well use them.)

That's the plan, anyway. :slight_smile:

AFAIR the spec allows for 3mA active current. You can measure the required current of a fully populated I2C bus with an ordinary current meter between the signal lines and GND.

That is dead easy. Just examine the board with a magnifier. The resistor controlling the transistor base is the single one adjacent to the capacitor. The top (nearest the 16 pins) goes to the transistor base (lower left) so when you remove both, you can connect that to pin 7.

OTOH you may actually want the 4k7 pull-up on the PCF8574 since it has only weak pull-ups. That is why it was there in the first place.

One thing to keep in mind is that the PCF8574 has very limited drive capability.
IoH is only 300uA so you can't drive much with the HIGH signals other than another input or a transistor.
IoL is 3mA so you can sink quite a bit more with the LOW signals enough to for something like an LED with the appropriate current limiter.

If you look around there are a couple of Arduino libraries out there for using this as a generic 8 pin expander.

--- bill

Wow! :thinking:

That sure is news to me! :astonished:

if you want to read a matrix keypad with I2C, try a SX1509 Breakout Board and the library from Sparkfun. It will make reading of buttons very easy.

https://learn.sparkfun.com/tutorials/sx1509-io-expander-breakout-hookup-guide

oops. I totally screwed that up. I grabbed the wrong IoL.
Somehow I incorrectly grabbed IoL for the SDA/SCL lines instead of the Px pins.
Don't know how I screwed that up.
Definitely around 10 to 25mA.

Point I was trying to make is that the HIGH level output on the Px pins can trip you up since it is so much lower current than the LOW output and the rating for an AVR pin.
So as an i/o pin expander it is only equivalent for active low signals.

--- bill

That was my assumption, but I was not 100% certain. If you zoom into the picture of the backpack board in my first post that started this topic, it appears that both the resistor chip and the transistor base are connected to vias (on that particular version of the board, anyway), and not a direct connection on the top layer. Presumably the vias are connected on another board layer.

In any case, since the modified backpack will be used for a 4x4 keypad, I believe I should remove the 4.7K transistor-base pull-up. Also, I believe I should remove the other two 4.7K resistors (I2C bus pull-ups), since the other, unmodified backpack (the one I will use as an actual LCD interface), will have the I2C pull-ups on the two-wire bus.

Yes, and that is, indeed, my intent. I will be using the modified backpack to connect a 4x4 matrix keypad, so I plan to use a keypad I2C library. For this application, the only connections for the PCF8574 port pins will be to each other, through the keypad switches, so current limits should not be an issue.

But the whole point of this exercise is to re-use an existing LCD backpack board that I already have available. (The LCD module it came with was wired directly to processor port pins without the I2C backpack.) Since there are "standard" 8-bit I2C port expanders using the same PCF8574 chip, I decided I could just use a modified LCD backpack as an 8-bit expander (albeit with a little extra work :slight_smile: -) ).

In my previous response a few minutes ago, I might have misinterpreted what you meant. Do you meant that there are libraries for specifically using a LCD backpack as a generic 8-bit expander?

If so, there would still need to be a modification to the board to allow P3 for use as a generic port pin. As originally wired on the LCD backpack, this bit is only available as an inverted open-collector output (no input capability).

There are libraries that use a PCF8574 for GPIO and there are also libraries that use a PCF8574 for reading a 4x4 keypad. None that I know of have anything in them specific to the LCD backpacks.
example: GitHub - RobTillaart/I2CKeyPad: Arduino libray for 4x4 (or smaller) KeyPad connected to an I2C PCF8574

From a quick look, using the existing PCF8574 keypad libraries would require modifying the backpack to get access to the Px pin used for backlight control.

If I were going to mod the backpack, I would remove the transistor and short the base pad/trace to the collector trace/pad. That will connect the Px backlight pin to the header. Yes there may still be pullup on the base which will add an external pullup to that pin, but it won't matter as the other Px pin will be more than capable of pulling that pullup down.
Alternatively, you could cut the trace on the collector and wire the base to the trace that still connects to 16 pin header.

If you are really ambitious I think it is possible to write some code or modify an exciting library like Tillart's keypad library code to work with the unmodified backpack.
i.e. it should be possible to figure out which key is pressed without having read capability on one of the keypad lines. (the Px pin that controls the backlight)
You can do this through the process of elimination.
i.e. if key is not on any of the other 3, then it can assume it is the one associated with the line you can't read.

Keep in mind that as you noticed the backpacks tend to put out an inverted signal for the backlight control pin and some designs use PNP transistor and some use a NPN transistor so the active level for controlling the transistor can vary and hence the associated output signal on the 16 pin header.

Also keep in mind that there are multiple backpack designs so while the most common on uses P3 for the backlight control pin, It is not always P3. There are backpacks that use P7 instead and use a different wiring for the Px pins that go to RS,R/W,E, D4,D5,D6,D7
Also, some have a pullup on the base of the transistor and some don't.
Some connect the transistor to the anode (pin 15) and some connect the transistor to the cathode (pin 16)

The most common backpack uses P3 to control the transistor with active HIGH input which outputs a LOW on LCD pin 16 (cathode)

If using the unmodified backpack, it means you would need to invert the pin when using it on the output, and then modify the code not read that pin but rather assume it is that pin if none of the other pins on the column read low.

--- bill

Thank you, Bill.

Oh, okay. I had already come across some of those libraries. In fact, there is even an I2C keypad library that can use port expanders based on other I2C chips, as well as the PCF8574. (One needs to indicate the I2C chip type when creating an instance of the keypad object.)

Yes. That was kind of the main point when I started this topic. :slight_smile:

I'm not really that ambitious. :slight_smile: It seems to me that it would be far easier just to remove the transistor and jumper P3 to a pin on J1 and use an existing library.

As to wiring, I am re-thinking that a bit. The keypad (one of those cheap membrane pads) has a single row of pin sockets (8 position), and I was envisioning having to modify or adapt the socket to plug into the split-up digital signals on the header pins.

But the backpack's LCD header has four unused pins (7 to 10, labelled "DB0" to "DB3"), adjacent to the next four data signals ("DB4 to "DB7"). So now I am thinking that I would jumper the P3 signal from the PCF8574 to header pin 10 ("DB3") and jumper header pins 4, 5, 6 ("RS", "RW", "CS") to, respectively, header pins 7,8,9 ("DB0", "DB1", "DB2").

That way, all of pins "DB0" to "DB7" would be connected, respectively, to PCF8574 signals P0 to P7, and there would be no need to modify or adapt the keypad connector - it would just plug directly into the eight data signal pins on the backpack header.

I could also jumper the PCF8574 "/INT" signal to header pin 15 (the old LCD "A" pin; the backlight jumper would, of course, be removed so that "A" is otherwise unconnected).

To avoid possible mis-connections, I would then cut off all of the no-longer-used pins from the backpack header. So the only pins kept would be pins 7 to 15 (the eight data pins and the /INT pin). (I may optionally keep the VCC and GND pins in case the target circuit, in a more generic application, requires power and/or ground.)

OK, but since I have/ had it right in front of me (amongst many other things :grin:) and my magnifiers ...

Bad guess! :grimacing:

To use it with a matrix keypad you have to add the 4k7 resistors - or 10k - to the adjacent three pins in order to make it work. The "trick" with the PCF8574 with its "8-bit quasi-bidirectional I/O port" is that it has negligible "pull-up" capability, so you need those resistors.

I'll leave you to figure out the I²C pull-ups.

I thought of simply jumpering base to collector but @DuinoSoar preferred to get the four pins in order.

But while there were multiple designs, the one @DuinoSoar and I have in hand is now virtually the only one available.

That one. :grin:

You will however need the pull-ups.

I was hoping to do some experimenting over the weekend to either confirm or disprove this, but did not have time.

But I have seen several tutorials (for example, this one on Instructables.com) where a keypad is connected to one of those blue PCF8574-based "break-out" boards, with no extra pull-ups on the keypad connections or PCF8574 digital port pins. (If you find and zoom into top and bottom view pictures of those boards, there are only two chip resistors on the board for the I2C pull-ups - no pull-up on the digital port pins.)

This was only so that no external adapter or jumpers would be needed to connect the keypad to the backpack digital I/O pins. I figured I could just do the "adapting" directly on the backpack board, by adding the extra jumpers between the header pins (as described in my previous post #18 above). Otherwise, using the existing backpack RS, RW and CS pins (for PCF8573 pins P0, P1 and P2), and the existing K pin (after modification; for P3), would be perfectly fine if one does not mind adding extra external jumper wires, or some kind of header adapter, between the keypad connector and the backpack board. As well, adding jumper wires directly on the backpack board would also allow me to "bring out" the PCF8574 /INT pin for processor wake-up capability when a keypad key is pressed.