Connecting a graphical LCD via a I2C using a 16-bit port expander

With respect to the resistors on the backlight. It depends on the module.
Some do need them and some don't. Some will actually burn out instantly with
no resistor. So I use a resistor all the time just to be safe.
Measure the current and see if falls within the spec
(if you can really believe the spec).
For several of mine I inserted a larger than necessary resistor because I power my circuits from USB and to keep the power under the USB spec
the display needs to be limited more than usual.
(most USB ports can supply way more than the spec - which is how
all these small external USB hard drives work - they use more than
double the spec when powering up)

In my experiments for using limiting resistors, I learned that the human
does not see brightness linearly. What that means is that it sees a change
in brightness (light energy level) easier when the level is low rather the bright
and that once you achieve a certain level of brightness, the eye really
can't detect it any more. So at least for my eyes, I can limit the current
a bit and not tell any noticeable difference.

Also some of my circuits are battery powered which benefit from the reduced
current. I noticed that often you can power it with half or less than the spec
and still see things quite well when indoors. - Outdoors, well that is
another matter.

And I'll agree with you that the only real way to learn about this stuff is to really
dig down into it by writing a real project.

I'm impressed with your i/o expander. Neat project.


On the graphics and speed optimization yet keeping things simple,
one thing that I've also thought about doing is to make a very slimmed
down "lean and mean" library that uses the CP437 font.
(if you haven't seen this google it).
With CP437, you could do many graphics like capabilities
(horizontal and vertical lines) without actually doing graphics.
There are even characters/glyphs that allow doing horizontal and vertical bars
for bar graphs on pixel boundaries.
And if you force the font to be 8x8 and always
land on row boundaries, you can slam the characters out and remove
the reads, even when doing graphic like line operations.
With CP437 and a 8x8 font you will not insert any pixel padding
between characters (it isn't needed for this type of font).
Sure the graphics are limited to some straight line functions, but
you can do quite a bit using only the CP437 font.
And it is much faster than plotting lines.
Also, it is easy to support a "wide/bold" mode and a "tall" mode.
Wide and tall modes simple double each pixel of the font.
Wide is really easy as you simply double each page/byte as
you go.
Tall is a little bit more complicated as you have to stretch the byte
into two bytes and interleave the bits.
Its kind of like was don't back in the late 70's and early 80's before
we really had the ability to set individual pixels.

What would be great would be a library that sat on top of the
cp437 font to provide the "graphic" functions.
Things to draw rectangles/boarders, horizontal and vertical lines,
and bar graphs etc...

For many applications cp437 would work fine.
I'm surprised that it isn't more widely
available on the character only lcds.

--- bill

bperrybap:
On the graphics and speed optimization yet keeping things simple, one thing that I've also thought about doing is to make a very slimmed down "lean and mean" library that uses the CP437 font. (if you haven't seen this google it).

Ah, that font! That brings back fond memories of when I used to work with Turbo Pascal. We used to make quite nice menus with boxes, bars, double lines, tick marks, etc. And the gray boxes could be put to good use too.

Indeed there is absolutely nothing stopping you adding that in, because in the case of my library I had a "bit blit" function that copies characters in groups of 8 pixels to the screen, so each glyph in an 8x8 pixel font would simply be 8 bytes. To build that into the library would take 1024 bytes (8 * 128), which is memory you may or may not want to spare. Perhaps with a define around it?

I wonder if anyone has the CP437 with the pixels written down as bytes? That way at least it could be offered as an option, and it is tedious doing it yourself. So far most of the links I have found have shown what the font looks like, or the Unicode equivalent, but not the pixels as a group of 8 bytes.

I've got it if you want it.
(Couple of different sizes but 8x8 is easiest to work with)
And the format of the data matches the bit order of the glcd pages.
I played around with it on ks0108s for a while.
PM me if interested.
--- bill

Thanks Bill. I got the file and incorporated it into the posting on the link I gave above. There is also a graphic showing which glyphs you get for each character.

I made it an optional include, being conscious that with only 32 Kb of memory, you may not want to spend 1 Kb on a font you never use.

How fast is it if you put "TWBR = 12;" after "Wire.begin();" in your library? (sets I2C speed to 400KHz instead of 100KHz)

Good question!

Without the speed change:

  • Clear screen: 588 ms
  • Draw 96 characters of text: 347 ms
  • Frame a rectangle: 278 ms
  • Fill a rectangle: 4687 ms

With the suggested change:

  • Clear screen: 229 ms
  • Draw 96 characters of text: 148 ms
  • Frame a rectangle: 120 ms
  • Fill a rectangle: 1753 ms

With the suggested change and write-through caching enabled:

  • Clear screen: 230 ms
  • Draw 96 characters of text: 147 ms
  • Frame a rectangle: 78 ms
  • Fill a rectangle: 976 ms

The activities which don't involve reading back were within 1 ms of before, but the ones which involved pixel drawing were somewhat faster.

Personally I think that writing all 96 characters (over half a 8x21 line screen) in just over 1/7 of a second is pretty reasonable.

Today I received some MCP23S17 chips, which are the SPI equivalent of the MCP23017. With some fairly minor circuit changes (the pins are almost identical), and some code changes, the library is now much faster (at the expense of having to run two more wires):

  • Clear screen: 62 ms
  • Draw 96 characters of text: 54 ms
  • Frame a rectangle: 58 ms
  • Fill a rectangle: 622 ms

That is without write-through caching enabled. With it enabled the relevant times dropped to:

  • Frame a rectangle: 48 ms
  • Fill a rectangle: 432 ms

With the exception of big block fills, it now fills the screen very quickly indeed.

Are you using software SPI or the hardware SPI transceiver for this?

At the Arduino end? The hardware SPI. Why would you not use it? It clocks out bytes at about 3 microseconds each. You can connect multiple SPI devices as long as each one has its own SS line. The library I wrote lets you choose the SS line you have dedicated to the LCD (it might not be D10) so you can also connect Ethernet shields, etc.

hey can use this library if i use 2 pcf8574p as port expander.

Not unchanged. You are addressing two port expanders rather than one. The datasheet I found seems a bit light on information about the protocol, but it is probably different. I'm sure it can be done, but you will need to modify things here and there.

i need to modify library or just hardware part

I'm not sure what you mean by that. You are replacing one chip by two chips? Surely that involves a hardware change.

So you need to modify both.

thank you sir

is there any other option for mcp23017 ic. it is not easily available in india1

Mail? I get most of my stuff from overseas.

hello sir,
i have done the same thing using pcf8574. but data display on lcd very slowly. what are the speed parameter of i2c ,mcp23017 you have used. does wire length of i2c effects speed.

ooh, good job with the library! this may come in useful to me later on :slight_smile: much appreciated!

cnavnath:
i have done the same thing using pcf8574. but data display on lcd very slowly. what are the speed parameter of i2c ,mcp23017 you have used. does wire length of i2c effects speed.

At normal speed I believe I2C runs at around 10K bytes/second, and with a speedup (higher speed set) you can get to 3.5 times that.

I don't see why wire length would affect it.

If the LCD is slow it could be you are sending too much (like updating more than you need). Also the LCDs have a settling time (you have to poll a pin to see if they are ready) so it could be that speed, and not I2C speed, that is the limiting factor.

ks0108s are really dumb so the commands or data accesses are usually very fast to execute.
Usually they are ready before you can generate the next command or data access.
I've occasionally seen them take and extra 3-4us to respond but that is not the norm.

I would think that ic2 should not have an issue overrunning the lcd as the byte transfer time at 400k bits/sec is 20us.
Even if you bump the i2c clock to 1Mhz, a byte transfer time is still 8us
and you have to transfer at least 2 bytes to control the 16 bits on the output port
plus you still have I2C START + ADDRESS + STOP overhead.

--- bill