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

Some of those timings do seem a bit lengthy.
Like setting control lines. 300 uS seems like a long time
to get control lines set.

There are several optimizations that can be done to reduce
the overheads by eliminating many of the i/o accesses to the glcd.
(I did all the low level code for the ks0108 now glcd library).

You actually don't need to fully render everything in ram to move to
doing full byte/page accesses when possible.
All you have to do is have some clever
code (that is actually quite complex).
Turns out that you only need about 3 bytes and several local
status variables to ensure full byte accesses when possible.
It does get quite hairy/tricky to do any sized font rendering on
any boundary and paint the glyphs horizontally rather than
vertically.
Things like fills are not too bad.

Another thing that really helps is to keep track of the page
and address for each chip. That way you can take advange
of the auto increment to advance the address for you avoiding
that command when doing multiple horizontal operations (writes) such
as fill operations. Also if you track the page you only have to set it
when changing rows.

The code can also be made smart enough to detect
the boundaries of things like a fill operation such that
it can combine multiple pixels to build up a page/byte before it
is tossed to the physical display. It can also detect page boundaries
and full page fills and then do full byte writes (with no reads) when possible rather than doing 8 individual pixel operations.

So you only have to do reads when the updating data is not a full page.

The rule of thumb is always push pages to the lcd horizontally.
First handle the fraction pages at the top of a fill
then do full pages, then do the fractional pages along the bottom of the fill.

So in your example of
lcd.fillRect(20,20,50,50,1);

You would read the page 3 (pixels 16-23) then update/set pixels
20-23 and do that starting at address 20 out to address 50.
You would only set the page and address once and auto increment would
take care of the rest for that row.
Yes you have to read each page 3 as you go across but
it turns into a read operation followed by updating the byte
locally in ram and then a write. (if caching, then the read is eliminated)
Each byte written is updated with the same mask value.
Then for the next 3 rows below that, it would reduce
to nothing but full writes of the mask value (0xff or 00 depending on color)
No reads, no set pages, no set addresses just writes.
Yes there is an initial set page and set address to start the row
but then the next 30 pages (from pixel 20 to 50) would be written as full pages.
Then the pixels from 48-50 have to handled just like pixels at 16-23 since
they are not a full page.

So now instead of 900 set pixel operations,
which is set page, set address, read, set address, write

you have 60 reads, (30 at top and 30 at bottom) and 150 writes.
And the number of set page and set address operations would also
be dramatically reduced as you would only need one per row
to start off the row.
(actually there is 1 set address for every read as well to back up the address
after a read to prepare for the write)

Turn on caching and now the operations to the glcd would be:
(repeat 5 times) set page, set address, 30 writes

So instead of 900 reads (actaully 1800), 1800 set page, 1800 set address,
and 900 writes,
you do 5 set page, 5+60 set address, 150 writes.


This is how the glcd library works. It optimizes the operations
to full pages as much as it can.
Now I'm curious, how well the glcd library would work
sitting on top of a port expander because it already has all the logic
to strip out all the unneeded set page/address commands and collapses
everything down to full page accesses when possible to absolutely
minimize the traffic to the glcd module.

--- bill