Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.Sign up
[bug fix and improvement] LiquidCrystal Library - Improve timing to make LESS blocking #4550
Tested using V1.6.7 IDE and DUE R3 hardware, 20 x 4 LCD in 4 bit and 8 bit mode
Current pulseEnable function always blocks AFTER sending data for 100 us.
Revision notes time (us) and delays amount needed to either get to the required delay or minimum time for how long Enable pin must be high. This way shorter delays inside pulseEnable take account of other software time processing. shortening any delay time.
Created a define at top of cpp file for minimu time between writes, and reduced to 80 us, probably could go lower but at just over twice the chip datasheet timing required, will allow for slow clones of the chip.
Test code in attached zip does a setCursor and write 20 characters to a line, measured time improvements of just under 1ms.This equates to a time saving of 20% for 4 bit mode and 33% for 8 bit mode. There are plenty of scope screenshots of the signals before and after for 4 and 8 bit modes also in the zip file. Example after change where 2.67 ms print became 1.70 ms -
This method actually means you can scope the Enable pin and see how long it is in delay (high) and how long is rest of software (low)
The major part of the time saving comes from code changes to work out how long to delay.
Does anyone know any displays that have a LONG write delay time ?
Currently Pull request sets the write delay time to 80 us, where as reducing this to 40 us (still more than the HD44780 base spec of 37 us) can mean a set cursor and 20 character write can be reduced to 900 us. I personally will use for myself 40 us write delay but wish to be sure no others are affected if a further release change was made to 40 us.
Any thoughts welcome
That is just as blocking if spin lock on that,, also depends if someone has wired up the R/W pin which library allows you to do or not do. So time delay is only way for ALL wiring configurations supported by the library and examples all over Arduino and other related sites.
Hopefully there does not exist a display where R/W goes nowhere (but I would not be surprised if one existed)
It's not a matter of R/W going nowhere... It's a question whether the design includes access to R/W. Some designs simply hard wire R/W, so that it is write-only. It would be interesting to have an option in the library that lets one provide the arduino pin number of the R/W pin. The software could then test to see if it works, and if it does, delay could be minimized.
Did some further checking on the datasheet for HD44780 Busy flag checking is only valid after the initail function set command (controller knows if 4 or 8 bit mode) this means extra checks would be needed to delay for a time if this has not been done yet. Additionally it most people follow Arduino's example of forcing R/W pin to GND (as all Arduino, Adafruit and other starter examples show) it would be of little gain.
HOWEVER I have noticed something from the datasheet that could mean 4 bit interfacing could also be speeded up more to get closer to 8 bit interface timing. Needs testing.
RIght I have done 4 bit mods and now using same test method the 4 bit mode timings have reduced DRAMATICALLY !
Test send setcursor and 20 character string to LCD
Original test 4.34 ms
Yes that is 3.11ms faster, yes nearly a quarter of the time in old library.
Because problem in 4 bit mode is the second nibble can be written 1 us later, but library was using the dealy for between COMPLETE commands between each nibble.
Comparison scope shots and a text file in updated
Update to github shortly.
Reduce delay between nibbles as per Datasheet Long delays are for between COMPLETE commands NOT nibbles of a byte Tidy functions write8bits and write4bits become one function and pass in bit size. Original functions were copy/paste with one number change between them. Change constant define from _MIN_WRITE_DELAY to more meaningful _LCD_COMMAND_DELAY
Finalised this now
1/ Reduce command delay time closer to chip spec of 37us (use 40us as default)
Overall performance improvements
on Due Old library set cursor and write 20 chars
4 bit mode 4.34 ms
On Mega latest version only timings
It has been clear to me for many years that whoever wrote the begin() and pulseEnable() code did not understand how the hd44780 interface really works.
in pulseEnable(), things like the comment about commands needing time "to settle" and delaying the 100us between nibbles made no sense.
This patch update resolves some of what was wrong with pulseEnable(); and the blind command delays by handling the LCD execution times in a smarter way however, if a new API function is going to be added it should handle configuring all the necessary execution times to make sure that it really allows slower LCDs to fully work.
To support LCDs that use a clock slower than the 270 kHz reference clock, the code must handle being able to configure not only the command/data instruction times but also the clear/home execution times.
So to really work with slower LCDs, extending and configuring both execution times must be supported.
The LCD API 1.0 spec
I have a hd44780 library that implements proper execution timing and supports the configuration of the two different execution times through a function called setExecTimes(chUs, insUs)
If adding a new API call to LiquidCrystal, my suggestion would be to first fix the code to support both types of execution times and then add a new API function that allows setting both the clear/home and cmd/data executions and call it either:
The hd44780 library comes with a sketch that will time the interface and give you a byte transfer time. This is a great tool for comparing i/o speed.
In my personal opinion a lot of the Arduino codespace is polluted with bad practises and bad code, too many uses of delays in ms range, bad structuring and 'oh this is good because it worked for me'. Too much forcing of very low level stuff into classes and the overhead of that as shown with the begin() method.
Don't even get me on the lack of common error handling, let alone libraries that have comments like
No real structure to the libraries and no in built scheduling, amongst other things like, everything is linear code is a cul-de-sac environment. Too many ludges in my view on the whole software environment, as everything has to be forced to be like AVR.
To that end all my Arduino work has now been moved to LEGACY code as too many folks are interested only in the Legacy device of the Uno as being the only platform.