Is it possible to ask an I2C/LCD adapter for display size ?

Hi,

I would like to write a sketch that should run on a few different devices. While I'm using 20x4 LCD's in most of them, some force me to use 16x2 alternatively for space reasons.

So my sketch needs to detect different display sizes and adapt to them.

I'm exclusively using character displays with I2C adapter. During my experiments with the I2C scanner sketch, I've found that they have different addresses. These addresses seem to be hard-coded in the adapter: If I use the same adapter with different sized displays, the address stays the same.

Side note ... my first few test objects all had address 0x27 on the 16x2 and 0x3f on the 20x4 LCD's, so my first hope was that the adapter discovers the display size and uses a different address based on that. But this hope was destroyed by later test objects.

I've already successfully managed to scan the I2C bus in setup() and use the discovered address for initializing the LiquidCrystal_I2C instance. Only thing that is missing is the auto-detection of the display size. I'd like to avoid needing a jumper on one of the pins.

I'm not using TFT, so this is not a duplicate of arduino 1 code fits all tft lcd screen size? - Displays - Arduino Forum

Thanx

There is no way, that I know of, to determine the size of the display programatically. Am I mistaken, Bill?

There are different addresses because some displays use the PCF8574 I2C expander (0x027) and some use the PCF8574A version (0x03F).

groundFungus:
There is no way, that I know of, to determine the size of the display programatically. Am I mistaken, Bill?

OK, then I'll have to use a jumper for the display size.

There are different addresses because some displays use the PCF8574 I2C expander (0x027) and some use the PCF8574A version (0x03F).

That's quite interesting, because the chip on all adapter modules I own has the printing "PCF8574AT".
However, the printing quality varies ... Some are in bright white with a readable Philips logo, some are in brown beige with a logo that seems to mimic the Philips logo, and so on ... The second and third line of the printing varies also. Looks like clones of the original chip.

So my sketch needs to detect different display sizes and adapt to them.

why? What is your real need?
a) Will you have the same sketch an several devices but with different displays,
b) or do you change the display on one device and do you expect the program to recognize that?
c) Something else?

for
a) I would just would write once a 16 2 in two bytes of the eeprom (or 20 4) in each device and read that value in the sketch
b) if you have only 0x27 and 0x3F as I2C addresses, just organize your LCD's: e.g.: on the 2004 you close all jumpers and set the address to 0x20 (or 0x38). Now you know by the I2C address if you have connected an 1602 (0x27, 0x3F) or a 2004 (0x20, 0x38)

noiasca:
why? What is your real need?
a) Will you have the same sketch an several devices but with different displays,
b) or do you change the display on one device and do you expect the program to recognize that?
c) Something else?

For the real life purpose, it will be a)
For my LCD test sketch, it will be almost b) except I don't change displays after power on. The detection is only needed during setup().

for
a) I would just would write once a 16 2 in two bytes of the eeprom (or 20 4) in each device and read that value in the sketch
b) if you have only 0x27 and 0x3F as I2C addresses, just organize your LCD's: e.g.: on the 2004 you close all jumpers and set the address to 0x20 (or 0x38). Now you know by the I2C address if you have connected an 1602 (0x27, 0x3F) or a 2004 (0x20, 0x38)

about a)
Oh ... the eeprom ... I forgot about that. OK, I'll take a look at this.
And for the test sketch I can use a jumper on one of the digital pins of the arduino.

about b)
I did not know that I can change the address of the I2C adapter modules, but thanks to your hint, I did a little research and found the A0, A1, A2 soldering pads on the modules (at first, I was confused because you wrote about jumpers). Looks like I can work with that. I think I'll do a test series with my modules to find out what addresses are available. It looks like the modules have a different range of available addresses, as the soldering pads on all of them are all open and they already have different addresses.

Just organizing the LCD's is not as easy as it seems. Currently, I have a few LCD's with I2C module already soldered on, a few LCD's without, and a handful of I2C modules. For the already soldered ones, I'm lucky as all of the 1602 have one address and all of the 2004 have the other. But looking at my not-yet-soldered ones, that was pure coincidence. :slight_smile:
Of course I can solder the remaining modules following that pattern, but when I order new stuff, I don't know what I will get. And I'm planning to save me the work and order already soldered ones, as they are also cheaper than ordering LCD's and I2C's separately.

You might want to have a look at the HD44780 library written by Bill Perry, it is capable of automatically locating the I2C address of the display, and auto-configuring the connections between the I2C module and LCD display (not all displays are wired the same). As for determining display size, I don't know of any way that would be possible, the controller used on most LCD displays (the HD44780 or compatible chip) does not detect display size, but has to be programmed for the size display it is being used with.

I think I'll do a test series with my modules to find out what addresses are available.

read again groundFungus post.
He has already explained it.

In my words:
there are two very similar chips the
PCF8574 and the PCF8574A

The PCF8574 has addresses from 0x20 to 0x27
The PCF8574A has addresses from 0x38 to 0x3F

most of the modules have 3 jumper or 3 soldering pads available.
If you solder them, you change the address - but again - either in the range 0x20 to 0x27 or 0x38 to 0x3F.

so basically, it doesn't matter when you have a mixture of PCF8574 or PCF8574A chips. Just take care what solder pads you are connecting.

read this short datasheet:

if you have currently the pads open = HIGH.
If you solder them you put them to ground = LOW

in other words:

"unsoldered"
0x27 = 0b00100111
0x3F = 0b00111111

vs
"soldered"
0x20 = 0b00100000
0x38 = 0b00111000

so after assigning one type of display different address(es) by soldering the pads, you can easily check by the last three bits of the address if they are 1602 or 2004

if you don't like to check the bits (address & 0b111 == 0) , than simple compare both addresses

if (address == 0x20 || address == 0x38)
// do the stuff for the 2004
else
// do the stuff for the 1602

Unfortunately, there is no way to auto detect the LCD geometry of a hd44780 display.
If there was, I'd add that to the auto configuration in the hd44780 library.

@Tux-Duino
You have noticed different i2c addresses for different backpacks, but what you may not have seen yet is different pin mappings used on the backpack between the PCF8574 chip and the hd44780 display.

If you want your code to work with any/all LCD backpacks, you must have a library that supports configuring the pin mappings.
The common LiquidCrystal_I2C library (not to be confused with the NewLiquidCrystal LIquidCrystal_I2C i/o class) has a hard coded pin mapping. If you get a LCD device that does not use that pin mapping, it will not work until you modify the actual library code.
NewLIquidCrystal solved this by allowing the user to manually configure everything. i.e. the i2c address, the pin mappings and the backlight control.

I took a newer/better approach in the hd44780 library.
The hd44780_I2Cexp i/o class solves the issue by locating the i2c address and self configuring the pin mappings between by auto-detecting the wiring and backlight control.

I'm not sure what you goal is. If you are looking for a automagic "plug an play" that "just works" by having the code self adjust to whatever LCD device is plugged in, that isn't possible since you can't automatically determine the geometry.

The hd44780 will solve everything other than the geometry issue.
For that, here are two options:

  • use the i2c address to indicate which geometry.

i.e. say odd addresses are 16x2 and even are for 20x4 displays.
The code can adjust based on the address of the device it sees.
It does require that the user do soldering to configure the display geometry.
Maybe that is too much but maybe not, if say 20x4 is the default and the most common and only rarely 16x2 is used.
Then users could just plug in any 20x4 with no soldering and it would "just work" and for 16x2 they have to solder the/jumper the A0 pin.
Note: the hd44780_I2Cexp i/o class as a function that can fetch the i2c address it discovered.

  • use the EEPROM to indicate the geometry.
    This also has pluses and minuses in that while it removes the requirement for soldering, it now requires having some way for the user to configure the geometry setting that gets saved in EEPROM.
    There are many ways to do this, like perhaps a pin that is read at powerup and used to set the geometry state.
    (Make sure to use EEPROM.update() vs EEPROM.write() to reduce eeprom wear)

You could even do something clever with the i2c pins.
For example, when using the hd44780 library, it will report an error if the initialization fails.
If initialization fails, particularity if it is code hd44780::RV_ENXIO
which means it scanned the bus and didn't find a device.
You could then go read the i2c pins using the SDA and SCL pin symbol names, to look at their state and use that to determine the geometry and save that to EEPROM.
However, you need to be able to detect the difference between just a disconnected device and the desire to set the geometry.
You can do this by using some carefully selected pin states.
i.e. shorting the SDA and SCL pins to ground can be used.

Here is what you could do: (once initialization has failed)

  • set SDA and SDL to INPUT_PULLUP
  • read both pins
  • If SCL is HIGH, then leave current configuration alone.
  • If SCL is LOW, then look at SDA and use its level to determine 16x2 vs 20x4 and save the desired geometry setting to EEPROM.

--- bill