3 wire lcd speed up?

Hello, I am using 16x2 lcd and 4094 wired like this http://arduino.cc/playground/Code/LCD3wires I tried few libraries, and all of them are working fine, but my problem is that when using this shift register, it slows the entire code down.. the more i write to the lcd the slower it gets.. I understand that this is due to the shift register... I was wondering if there is some way to speed this up by modifying the library or something... I am only using lcd to display data...

If you hook the shift register to the SPI pins you can use the SPI hardware instead of shiftOut(). It will mean changes deep in the library but should speed up data transfers.

There are a few things you can do: 1) use faster/better lcd code 2) don't write to the lcd so much/often

1) As far as faster/better code, the best way to get faster code to control pins is to not use any of the Arduino core code like digitalWrite() to drive the pins. I'm not sure which lcd SR libraries you have tried but this library will give you the fastest code which means it has the lowest overhead: https://bitbucket.org/fmalpartida/new-liquidcrystal/overview It does not use the digitalWrite() routines and also has been optimized not to do additional/un-needed longer than necessary delays that are in most of the liquidcrystal libraries out there. The SR3W sub-device class can be configured for any wiring with a shift register including your current 4094 wiring.

With a few extra components you can switch to using only 2 wires and get even higher performance with the SR2W sub-device that I did that is available in fm's library. SR2W is faster than SR3W because SR2W requires a specific wiring and is not configurable.

SR3W is 3.3 times faster than the 4bit parallel mode LiquidCrystal Library that ships with Arduino. SR2W is 5.5 times faster than the 4bit parallel mode LiquidCrystal Library that ships with Arduino.

I haven't updated the SR2W code in the repository but here is a wiring diagram for 2 wire mode that should work with the 4094 you have and the SR2W sub-device class: (It isn't in LiquidCrystal_SR2W.h yet)

// Wiring for a 4094
// NOTE: pin 1 is not connected to pin 2
//                          4.7k
//                 +----[ Resistor ]----------------+---(LCD Enable)
//                 |                                |
//                 |      74HC4094                  |
// (data pin)------+       HEF4094    (VCC)         |
//                 |     +----u----+    |           |
// (clock pin)+----|---1-|STR   VCC|-16-+           |
//            |    |     |         |    |           |
//            |    +---2-|D      OE|-15-+          _V_ diode 1N4148
//            |          |         |                |
//            +--------3-|CP    QP4|-14--(LCD D5)   |
//                     4-|QP0   QP5|-13--(LCD D6)   |
// (BL circuit)--------5-|QP1   QP6|-12--(LCD D7)   |
// (LCD RS)------------6-|QP2   QP7|-11-------------+
// (LCD D4)------------7-|QP3   QS2|-10
//                   +-8-|GND   QS1|--9
//                   |   +---------+
//                   |      0.1uf
//                 (gnd)-----||----(vcc)

2) As trite as it sounds, Not updating the lcd display can be a huge benefit in the code. For example, if the lcd is being updated in the main loop each time through the loop then the lcd is probably being updated more often than it needs to be. Humans are very slow at seeing changes relative to the speed of these processors. Humans will not be able to see updates faster than about 50-70 times per second and so updates faster than that isn't very useful. And in order to actually read the data on the display, faster than about 2-3 times per second is overkill for most things other than animations. So what can help remove the LCD overhead, is to keep track of elapsed time using say millis() and not update the display unless a certain amount of time has passed. This will allow the loop() code to spin faster and have extra time to do other things since the lcd overhead is not happening every time through the loop but rather only at periodic time intervals. An alternative is to only update the lcd when something changes. If the data that is being displayed is not changing there is no point in re-writing the same information to the display since it is already there.

While these techniques can improve the overage average time through the loop() code it does not help reduce the worst case timing latency because when the lcd is actually updated, the additional overhead needed to update the lcd will be inserted/experienced.

--- bill

I read 132 us to put a character on an LCD using a 74HC164 shift register.
I use shiftout,clock on D3,data&RS on D4 and enable on D2.
I don’t consider this slow. The attached scope photo has the enable on the top and the 8 clock pulses below.
I have posted full details on http://projects.worsleyassociates.com

I read 132 us to put a character on an LCD using a 74HC164 shift register.
I use shiftout,clock on D3,data&RS on D4 and enable on D2.
I don’t consider this slow. The attached scope photo has the enable on the top and the 8 clock pulses below.
I have posted full details on http://projects.worsleyassociates.com

I didn’t see anything about LCDs there. Did I miss it? Is that link to the details correct?

In terms of “slow”, it depends on your view of what “slow” is. Every thing is relative.
To me, 132 us is VERY slow compared what an AVR at 16mhz is capable of doing.
It is the Arduino core code that is so slow. shiftout() calls digitalWrite() to set the pins
and the digitalWrite() code implementation in the core code is quite slow compared to what can
be done even when the Arduino pins are configurable and not constants.
(if using constants the clock on the SR could be strobed every 125ns)
shiftOut() itself is not very optimized code. It runtime checks on shift direction and doesn’t
do its loops as well as it could (should).
Just re-rewriting shiftout(), even when still using the slow Arduino core code digitalWrite()
functions can speed things up.

The shiftout code used in fm’s library (which does not use any Arduino core code) can shift out a byte
and strobe a separate E/Strobe line in under 16us. - see the attached analyzer shot.
It reduces to a couple of microseconds on the Chipkit Uno32.

It is isn’t clear what is represented by the 132us analyzer shot.
I can’t tell if it is the full amount of time to put a character on the display
or just the time it takes to shift out a byte, set up RS and strobe E.
i.e. can you sustain that time/rate for back to back character writes?
In order to measure that time, it is best to measure between two back to back character writes.
I say “character writes” because there is more timing overhead than just the shift operation and the E strobe to the LCD.
There is also LCD timing overhead that must be honored to ensure that the lcd is given enough time to process the
operation before another operation can be done to the lcd.

The best time measurement is the time between to back to back lcd.write() calls.
This measures all the overhead as seen by the sketch. It includes all overheads including
any s/w overhead in the library as well as the the time to get the data to the lcd.
It is a true measurement of how long it takes to write something on the lcd.

I noticed that you are using 8 bit mode but most of these 8 bit shift register LCD libraries
are usually operating in 4 bit mode to have other capabilities like backlight control.
For 4 bit mode it means you have to do a minimum of 2 shiftout operations just to get the data there.
And then there are 2 more shift register register loads to raise lower E.
So in 4 bit mode there are a minimum of 4 shiftout() operations that must be done in order to transfer a single character to the lcd vs the one that is possible when the LCD is in 8 bit mode and RS and Data share a line.

However, if even if the lcd library is using 4 bit mode it can still be faster than 8 bit mode if it avoids
using Arduino core code shiftOut() function.

I have measured back to back lcd.write() timing with an analyzer and now have a sketch that can do it.
With fm’s library the back to back write times are:
72us - using only 2 wires, 4 bit mode and a fixed SR pin wiring
102us - using 3 wires, 4 bit mode and a fully flexible SR pin wiring

These numbers are doing 4 shiftout operations per byte transfered to the LCD.
They represent the full and total overhead of back to back lcd.write() operations.
i.e. you can write to the display with back to back writes
forever with each byte taking the shown time away from the sketch.

For comparison, here is the total timing overhead for the Standard Arduino 4 bit parallel library:
338 us - Standard LiquidCrystal library using 4 bit mode with directly connected pins.

You can see the effects of how slow digitalWite() is.
Setting up the pins directly is slower then all the many additional toggles that must be done to shift out the bits.
The difference is using better i/o code vs the Arduino core code to do i/o operations and optimizing the lcd
processing timing to strictly match the hd44780 spec.
Luckily in most cases, such low level timing is not an issue for typical Arduino stuff.
But when time really matters, you must avoid using the Arduino core code.

— bill

bperrybap - Thanks for your comprehensive and knowledgeable reply concerning LCD writing times.
I will try to fill in the blanks a well I can.

  1. The link is OK - the button linking to my first, and only, Arduino project is at the very bottom, since they are in chronological order.
    However I have attached a screen shot showing an inter-character interval of 188 us, plus the class I wrote and the shield circuit diagram I made.
  2. "fast’ does depend on your expectations and experiences. I have been using Picaxe with the same circuit and it takes milliseconds, it even requires bit-banging!
  3. It is a HD44780 character display, so great speed is not needed - there are only 40 characters and the user must read it.
  4. You are supposed to monitor the HD44780 busy flag and then wait another 4us. Time after write to end of busy is listed as 37 us.
    I didn’t bother, just put in a 45us delay.
  5. With an 8-bit shift register, I saw no point in using 4-bit mode. If I wanted to control the backlight I could put another SR in tandem.
  6. My SerialLCD class is customized for my display and application, it is not general-purpose.

SerialLCD.cpp (2.1 KB)

3. It is a HD44780 character display, so great speed is not needed - there are only 40 characters and the user must read it.

It kind of depends on what is being done in the rest of the code and how it is being done.
There is the refresh rate and then there is the latency.
The refresh rate is the rate at which the LCD is updated or changed.
The latency is the amount of time it takes to get the information to the display
once the display needs to be updated.

In a shift register implementation like these 100% of the latency is processing
time that is robbed from the CPU.
So even though the refresh may not need to very high say as low as a few times a second,
there may be some critical realtime needs that do not allow a particular amount of latency
when updating the LCD.

Normally for such instances, the overall code would use interrupts to yank the CPU away from something like
the LCD library into the more critical code.
But in some cases the code may not be using interrupts, in that case,
as long as the LCD code is fast enough to meet the minimum latency,
all the code could be done in the foreground without having to use interrupts.

---- bill