Multiple hd44780 displays and memory size

I have a requirement to support up to 32 displays across four I2C buses. I’d be using 1601A, 1602 or 2004 displays with PCF8574T backpacks.

Bus switching is performed by a TCA9546A IC which requires a single I2C write to its own address to select the bus before writing to the I2C display adapter’s address. Thus I can have duplicate I2C addresses (0x20-0x27) on each bus. Clearly this means the library’s auto locate/autoconfig capability is not possible.

Memory would be an issue if I instantiated a hd44780_I2Cexp object for every display (at 45 bytes per object). Creating an object for each of the eight unique addresses (0x20-0x27) might be acceptable.

My target audience limits me to thru-hole parts, so ATMEGA328P it is for now. At a push I could go to 644P or 1284P with MightyCore.

I could recreate a single object each time I want to write to a device (new/delete), but I dislike dynamic memory allocation on small microcontrollers. Execution speed is not critical.

Is there are way to reconfigure a single hd44780_I2Cexp object with a new I2C address ?

Any creative thoughts would be welcome.

Autolocate is not possible for this, but autoconfigure is and may be desirable as you may end up with different/multiple backpack designs that use different pin mappings.

1st question is can you use a different controller? If so, the issue of RAM goes away. There are other modules that are through hole. For example, the Teensy boards (teensy2 & teensy 3) or ESP8266 WeMos D1 mini. They are quite small and fairly cost effective and have quite a bit more memory. The Wemos D1 mini is currently my favorite for projects at around $3 USD. Teensy has 2.5k RAM up to 64k and WeMos has 64k RAM.

Currently there is no way to alter the i2c address of an LCD object. In terms of how to hack the library to support patching the i2c address so you could share an lcd object across multiple physical LCD devices; it definitely can be done with out too much effort if the backpacks are all identical other than the i2c address. The simplest would be to move _addr to the public area then you could simply set the address as simple as

lcd._addr = I2CADDRESS-of-BACKPACK;

And then share the object across multiple physical devices. You would have to call begin() for each object to initialize the device.

Alternatively, a new function to set properties could be added that would mirror the getProp() function but would set properties in the object. i.e. something like:

int setProp(I2CexpProp propID, int val);

You would not be able to take advantage of the line wrapping capabilities if sharing an object across multiple devices.

--- bill

Thanks for the helpful thoughts Bill.

This is for a custom board that implements a mimic panel for a control system. I'm constrained by my audience who can't do surface-mount and need something that can be hidden away and be expected to work for 10+ years. I know Microchip will be making AVR processors forever :) but I can't guarantee that with other boards or modules. 644P (4K SRAM) and 1284P (16K) are possible although that means a different core.

I can mandate commonality of backpacks and the displays will likely all be 1601A (ugh) or 1602. I don't want to solve the issue of different I2C address ranges, even though that would give a larger number of addressable devices. Autolocate is not required as I will scan the buses to determine which I2C addresses are physically present. I can also init each display at this point and create any user-defined chars.

I don't need line wrapping as I'll probably have single-line displays and I need to manage the 1601A weirdness by formatting the display char by char.

I'll experiment with the library changes you suggest and fork if necessary.

Thanks again.

If you find that adding a setProp() would work for you, I could add it to the library.

I need to manage the 1601A weirdness by formatting the display char by char.

I'm assuming you know that there are two different types of 16x1 line displays. Some really one a 1 line display with a contiguous memory to screen mapping for all 16 characters and some are really two line display that has both of the 8 character lines on the same physical line on the display which are not 16 contiguous memory locations. The hd4470 library line wrapping code can hide the issue for the 8x2 displays. You still might be able to use the lineWrap() capability. As long as you do a setcursor() before you send your characters, then you could send up to 16 characters on the 16x1 display and they would all show up correctly on the 8x2 1601 type LCDs so you wouldn't have to deal with it in the user sketch code.

I'm amazed that the 8 bit AVR is continuing to survive given the low cost 32 bit alternatives out there. I think if Arduino were starting today, it would use something like a through hole pic32. Not sure if it would work for your case, but they have tons more resources and require fewer components for USB support.

--- bill

Thanks again Bill.

Yeah, I solved the 1601A weirdness. The first 8 chars start at 0,0 then the second 8 chars start at 40,0 ;)

The user is required to define the type(s) of display they have and I have code to handle the individual mixed types. I need to get a couple of 2002's to play with.

What ifs are interesting. Maybe if there had been an open-source toolchain for PICs 15 years ago and PICs of the time weren't such a weird architecture, we might be living in a different world.

Why AVR ? Because it 'looks' like an Uno and the instructions to install the code are (1) install the IDE, (2) add a couple of libraries, (3) press upload. Doesn't get much simpler. I put a USB connector and CP2102 bridge chip on most of my AVR boards.

I've moved most of my new projects to SAMD and SAMC (for CAN bus). SAMD11 is really cute. Or ESP where longevity isn't an issue.

Yeah, I solved the 1601A weirdness. The first 8 chars start at 0,0 then the second 8 chars start at 40,0 :wink:

That is why I suggested that you may be able to use lineWrap()
as it will transparently handle the line transition for you.
You just declare the display as a 8x2 and turn on lineWrap()
Then you can use it as if it were a 16x1 display.
You can set the cursor position from 0,0 to 0,15 and you don’t have to worry about crossing over the boundary.

— bill