LCD: 4 bit mode vs. 8 bit mode

Hi there, New to Arduino but not in hobby electronics I have a question regarding the LicquidCrystal library.

I have different types of LCD modules that behave strange depending on the selected bit mode, 4 or 8. I mean some displays works in both modes, some works only in one mode?!? See list below…

Hyundai HB16203 : 16*2 : both modes ok OPCVO L2432 : 24*2 : both modes ok Optrex PWB 20434 : 20*4 : works only in 4 bit mode Sharp LM40x2 IA : 40*2 : works only in 8 bit mode Delta Opto PDC1602M : 16*2 : never works 

I’m sure the Optrex can work in 8 bit mode since I used these displays for several projects based on 8051 controllers in 8 bit mode. So, why not when using the Arduino ?!!?

Any of you experienced this behaviour?

Just to be 100% clear, same 8 bit wiring used for the Hyundai works perfect.

Although I’m not the C specialist here I used Notepad++ to look at the code in the library and I have some questions… …

I suppose

void LiquidCrystal::init

routine is called with following code in the sketch, right ?

LiquidCrystal lcd(41, 40, 45, 44, 43, 42)

Why is the routine “begin” called from that “ini” routine? Even strange some default values (1 line, 16 char) are used :o The “ini” routine first initialize the display as a 1*16 display :o :confused:

The initialization routine as described in the data sheet of the HD44780 is in row 115 to 147, right? Any idea why in case of 4 bit mode the routine “write4bits” is used to send data to the LCD while in 8 bit mode everything goes via routines “command” and “send” ? Why not using the routine “write8bits” directly as in case of 4 bit mode?

I copied the full “LicquidCrystal” library, renamed it to “LCD_Lib” and tested above observations: a) No “begin” call in “ini” routine b) Use “write8bits” directly instead of “command” and “send”

With no luck :'( 4 bit mode is always ok, 8 bit always incoherent text on the display.

Any other ideas I can try????

Sorry for the very looooooooong message

Last but not least I’m using IDE 1.6.10

All of the 16x2 and 20x4 displays will work in 4-bit mode. There is no speed advantage in using 8-bit mode.

8-bit mode wastes 4 GPIO pins.

Having said that, the "LiquidCrystal.h" third party libraries vary in quality. The "official" library is not perfect. Unfortunately, they do not all provide the same methods and some do not even implement the datasheet properly.

I would install one library and use it for every LCD project. The Malpardita library is widely respected.

David.

David, thanks for your reaction! I think there is more wasted out there than 4 I/O pins :confused:

It’s not a question of speed it’s just the fact that it’s extremely strange that it works in 4 but NOT in 8 bit mode.

I found an old thread regarding an “old “ Optrex LCD that was solved by increasing the delays in the library. I changed the delays accordingly, guess what… … … no luck. In a certain way I’m not surprised since it works in 4 bit mode with original delays why can’t it work in 8 bit mode with same delays >:(

All suggestions I will try… … (*) Because it’s driving me crazy

Oh, btw the Malpartida lib was even worse, even in 4 bit mode crazy stuff on the LCD.

(*) except that ones that would destroy something :smiling_imp:

Why don't you try your displays without using a library. That should pin down the source of the problem.

Follow the [u]LCD Programming Examples[/u] link at http://web.alfredstate.edu/weimandn for suitable programs, both 4-bit and 8-bit configurations.

The [u]LCD Initialization[/u] link at the same site may answer your question about 'write4bits'.

The strange default values (1 line, 16 char) are probably a result of trying to emulate the default situation that arises if you try using the device without also using 'Initialization by Instruction'. It is absurd to use that as the default in a modern program (one written in the last 30 years) since you will have to look far and wide to find a true one-line display. Most 16x1 displays available now are actually configured as 8x2. Check out the [u]LCD Addressing[/u] link for more about this.

Don

david_prentice: All of the 16x2 and 20x4 displays will work in 4-bit mode. There is no speed advantage in using 8-bit mode.

This is incorrect. 4 bit mode will always be slightly slower since you have send the 8 bit data in two different nibbles vs all at once. If you were to dig deep into the low level timing, the difference can be seen. The IDE does some extra things in some of the low level code that do not need to be done that will add at least 100us to each byte transfer when using 4 bit mode.

From a practical stand point the difference is typically minimal so it is often not worth the extra pins.

It is possible that the LCDs that have issues with the Arduino code are not running at the default clock rate of 270kHz which is what the timing in table 6 of hd44780 spec shows.

The IDE LiquidCrystal library has padded out the timing quite a bit but it is possible that it may not be enough for much slower LCDs.

So while there could be some other issue, it could be that the timing in the LiquidCrystal library is simply not slow enough for some of the displays you have.

In looking at the code in begin() the limiting factor will be the first delay at 4.5ms that will limit the code to using a chipset clocked at no slower than 91.2kHz. You can do the math using the worst case instruction time from table 6 which is for a 270kHz clock. 1520/4500 * 270Khz = 91.2Khz

But that delay will only matter if this initialization code is called when the lcd is currently in 4 bit mode and out of sync with the host and the first nibble previously sent to the LCD was a 0. (This will not ever happen from a fresh start from powerup)

The delays in clear() and home() of 2ms will work down to a LCD clock rate of 1520/2000 * 270Khz = 205.2Khz

So if you had a display that was internally clocked at lower than about 200Khz you might have issues.

I'm not surprised that the new LiquidCrystal library has issues since it has pushed the evenlop of performance by crunching the timing down in many cases to the minimal specified for a 270Khz clocked LCD.

Which timings are you modifying?

--- bill

Ok, to be a little more pedantic.

4-bit mode requires an extra 1us to clock in a command. However the controller has received the command, it is still going to take the typical 37us to execute the command.

Yes, the nominal 270kHz RC clock used by the controller has a wide tolerance. So I would design for a 50us instruction time if not using BUSY.

Yes, two instructions take longer than the typical 37us. If not using BUSY, I would provide a 2.0ms delay.

Most Arduinos are clocked at 8MHz or 16MHz. So the realtime overhead of the extra 1us EN cycle in 4-bit mode might be a few microseconds.

Libraries don't need to be very efficient. A human can only read an LCD at a slow speed. The LCD does not even respond very fast.

David.

david_prentice: Ok, to be a little more pedantic.

ok lets....

4-bit mode requires an extra 1us to clock in a command. However the controller has received the command, it is still going to take the typical 37us to execute the command.

Yes, the nominal 270kHz RC clock used by the controller has a wide tolerance. So I would design for a 50us instruction time if not using BUSY.

Yes, two instructions take longer than the typical 37us. If not using BUSY, I would provide a 2.0ms delay.

Most Arduinos are clocked at 8MHz or 16MHz. So the realtime overhead of the extra 1us EN cycle in 4-bit mode might be a few microseconds.

Not sure what you meant by "two instructions take longer than the typical 37us". When using 4 bit mode, each nibble is not an instruction. Each nibble is simply 4 bits of the 8 bit instruction. The default 37us instruction execution time starts after the 2nd nibble is sent as that is when the LCD starts processing the instruction. There is no requirement to delay after sending the first nibble before sending the second. (other than meeting the minimum EN cycle time)

There is alot more going on than just an extra EN cycle (regardless of the actual pulse width) that happens when using 4 bit mode - with the current LiquidCrystal code.

The LiquidCrystal code attempted to delay/wait 100us after sending each command/instruction. However, the way the code is currently written it waits 100us after each strobe of EN not each instruction. The two are not the same. So that means that there is an extra unnecessary 100us delay between sending the two nibbles of a command along with all the other unneeded overhead in pulseEnable(). Like an unneeded set of En to low right at the beginning of pulseEnable(). (It is guaranteed to already be low, and if not, it wouldn't be working)

So by having unnecessary code in pulseEnable() and incorrectly putting the instruction execution delay in pulseEnable() vs in send(), 4 bit mode will have additional overhead that does not exist in 8 bit mode.

And that is the point I was making. That 4 bit mode will always be slower than 8 bit mode and that extra overhead might be enough to allow some slower LCDs to operate.

The biggest issue for slower lcds will be the code in home() and clear() as those delays may not be long enough for slower LCDs.

Libraries don't need to be very efficient. A human can only read an LCD at a slow speed. The LCD does not even respond very fast.

It really depends on the environment and the situation. In many cases inefficient code is ok and "good enough"; however, in others, it isn't. For example, while a GLCD has the same slow response time limitations of the actual liquiquid crystal molecules, and the same slow human eyes looking at the display, i/o speed and data transfer rate to the LCD make a dramatic difference in since it can involve updating thousands of pixels. Also, a more efficient library design can potentially use less RAM which can be an issue in parts like the AVRs.

--- bill

Bill,

It was quite clear that home() and clear() are the two commands that take longer than 37us.
The only extra time for 4-bit mode is the extra EN cycle time.

Yes, I am sure that Arduino libraries might have inappropriate delays and have inefficient port access.
The question was about 4-bit vs 8-bit from a theoretical point of view. For example, 4 consecutive bits on a single PORT is easily written and clocked by EN within the minimum 1us EN cycle width.

Yes, writing to the LCD via a timer interrupt is the most cpu efficient way.
In practice, strings are sent to the LCD and the cpu is waiting the 37us for the previous command to complete.

David.

david_prentice: Bill,

It was quite clear that home() and clear() are the two commands that take longer than 37us. The only extra time for 4-bit mode is the extra EN cycle time.

I think you are misunderstanding what I was saying about the delays as well as the current LiquidCrystal code.

What I was saying about the home() and clear() commands is that the current LiquidCrystal code delays 2 ms for those commands. 2ms is longer than the 1.52ms execution time in table 6 of the hd44780 spec which is based on the LCD chip running at 270kHz. So 2ms will support a chip running at 1520/2000 * 270kHz or 205.2khz. The current code in begin() is more conservative than that and supports a chip running down to around 91 khz.

The goofy code in the LiquidCrystal send() and pulseEnable() routines have a blind delay of 100us which has nothing to do with "commands settling" but rather is the execution time for instructions on a hd44780 chip running at 100khz However, due to the way they have incorrectly implemented their code, it executes unnecessary additional code to set a pin to a state that it is guaranteed to already be in & delays an additional 100us when using 4 bit mode.

So from a "slow lcd" perspective, the code in clear() & home() are not supporting a LCD chip as slow as the code in begin() and the other instructions, particularly when using 4 bit mode since that code has extra delays and overhead that allow the lcd to run slower, and that is why I was saying that the issue with slow LCDs is likely to be in the clear() and home() code as they only support a slightly slower chip at 205kHz vs begin() supporting a chip down to 91kHz.

Yes, I am sure that Arduino libraries might have inappropriate delays and have inefficient port access. The question was about 4-bit vs 8-bit from a theoretical point of view.

Even from a theoretical point of view 8 bit mode will always be measurably slower than 4 bit mode.

For example, 4 consecutive bits on a single PORT is easily written and clocked by EN within the minimum 1us EN cycle width.

Uh... No. Not in the real world using code running on a AVR based system with Arduino using digitalWrite() The digitalWrite() overhead for a single setting of a pin is just under 7us with IDEs prior to 1.6.10 1.6.10 has a new tool set that does massive code folding and so the digitalWrite() has been reduced to just under 4us. So just to set the d4-d7 pins the desired state will be at least 14us for a single nibble without considering the amount of time it takes to determine if the pin needs to be set to HIGH or LOW.

And even if all that real world overhead could be zero and sending the 2nd nibble did reduce the overhead all the way down to just an extra EN cycle, 4 bit mode would still be slower than 8 bit mode. So your statement in post #1:

There is no speed advantage in using 8-bit mode.

is incorrect. And that is what has lead to all this additional discussion. 8 bit mode will ALWAYS be faster than 4 bit mode. Depending on how the host code is implemented and controls the hd44780 interface, the amount of difference can vary, but there will always be a measurable difference.

Yes, writing to the LCD via a timer interrupt is the most cpu efficient way. In practice, strings are sent to the LCD and the cpu is waiting the 37us for the previous command to complete.

Not really. Using an ISR would incur more overhead than just handling the interface smarter. I have a new library that allows the CPU to continue running while commands are executing. No use of interrupts and it will be faster than polling BUSY as the overhead for setting up the pins to read and switching them back to writes is longer than all the instructions (other than clear() and home()) take to execute. And it always honors a user configurable execution time for instructions that uses reasonable defaults.

My apologies. Re-reading the OP, I see that it is specifically about the existing range of Arduino libraries. It was not a theoretical question about purpose designed LCD code.

Yes, it is important for Arduino libraries to be configurable for random pins. It is important for the LiquidCrystal class to have consistent methods including Print. No, efficiency or speed is not very relevant.

I still maintain that 4-bit vs 8-bit is typically 38us vs 37us in properly designed non-Arduino code that uses BUSY. Or 51us vs 50us in a write-only setup.

If you are controlling many tasks / peripherals, using the existing Timer interrupt for LCD output is a cpu-efficient strategy. Much the same as the Arduino uses interrupts for the USART. Or your PC handles keyboard, screen, printer, ...

Having said that. there is no valid reason why Arduino LiquidCrystal code should not be improved. But I am steering well clear of that particular quagmire.

David.

david_prentice: If you are controlling many tasks / peripherals, using the existing Timer interrupt for LCD output is a cpu-efficient strategy. Much the same as the Arduino uses interrupts for the USART. Or your PC handles keyboard, screen, printer, ...

The LCD is not like a USART, it isn't designed to send an interrupt when it needs attention or completes something. So all using a timer does is offer the ability to poll the LCD from an ISR. That adds considerable additional code and complexity including the need for using ram for a buffer.

Also, at some point, the LCD buffer could fill and the CPU will have to wait just like on the Serial ports. Using the timer polling methodology could time shift around when things are done but there is a cost to that, the main one being RAM usage.

The are some simple techniques that can be done that allow the CPU to continue execution while the LCD is processing instructions, so an AVR CPU will typically never have to busy wait for anything but the clear() and home() commands. These techniques require no buffering and do not use any interrupts or timers. It is just matter of being smarter about how to handle the execution times. And by doing it differently using these techniques, the LCD execution times can also be run time configured by the sketch.

--- bill

First off. We are NOT discussing Arduino libraries.

Most control programs will have a regular Timer interrupt that fires regardless. You service different tasks depending on the interrupt number. You might sleep between interrupts.

e.g. your system clock may 'tick' every 1ms e.g. you might multiplex a display every 5ms e.g. you might read a keypad every 10ms e.g. a countdown timer

Emptying an LCD buffer as one of these 'tasks' is very simple. It just involves strobing the EN line twice. You never have to wait or poll BUSY.

If there is nothing to print, you have only added about 250ns to the ISR() that is regularly firing.

This has veered off the original topic. It is not relevant to Arduinos. Most Arduino users are happy to just blink a LED with a 16MHz cpu doing nothing. It does apply to any real-life control system.

There is always a cost-benefit for 4-bit vs 8-bit. With sensible design 4-bit might cost you 51us vs 50us. The benefit is 4 extra GPIO pins. 5 extra if you hard-wire RW.

David.

david_prentice:
First off. We are NOT discussing Arduino libraries.

The OP, Don, and I were until you started wanting to talk about other environments.

The side track seems to have been triggered because you this said in post #1:

There is no speed advantage in using 8-bit mode.

Which I stated several times is incorrect since 8 bit mode will always be faster than 4 bit mode because 4 bit mode has additional i/o overhead compared to 8 bit mode.

And given the way the Arduino pin i/o API of digitalWrite() works and the way the LiquidCrystal code is currently written, and it doing extra unneeded delays between nibbles and it resetting the level on pin that it doesn’t need to do, the difference between 4 bit and 8 bit can potentially be larger on Arduino than in other environments.

The main point of all this was that the LiquidCrystal code has more overhead between commands when using 4 bit mode and that additional overhead can potentially allow a slower LCD to work.
But that added 4 bit overhead won’t be enough for the clear() and home() commands on a much slower than typical LCD.

All this was attempting to explain the observations the OP reported in the initial post.
The timings, can explain why one LCD works in 4 bit but not 8 and why another won’t work at all.
And also why fm’s new LiquidCrystal library would likely not operate correctly on slower LCDs.

All my posts were related to Arduino and trying to resolve the OPs issue with a few later comments either trying to debunk some incorrect information or to trying to get clarification on certain items.

All of the timings, code references and the smarter techniques of handling the LCD communications interface I mentioned were all related to the Arduino library environment. I am currently using these smarter ways of handling the i/o to the LCD in an Arduino LCD library and the difference is dramatic, all without violating any of the LCD timing, using any RAM buffers, or ISRs and still using the digitalWrite() API.
It is just a better way of doing things.

— bill

So... Just to pound in the final nail in the coffin that 8 bit is faster than 4 bit mode, I'll present some actual real world data to demonstrate the effects of 4 bit mode vs 8 bit mode and what can be gained by handling the execution times in a smarter way that is not depending on shorter execution times, just being smarter about how the execution time is accounted for in a way that doesn't depend on CPU clock speed either so it doesn't break on much faster CPUs.

No more guessing. No more assumptions, but pure actual real-world timing measurements.

I have a sketch that I wrote to test the communication interface to the LCD. It reports - byte transfer time - 16x2 frames per second - Frame Time

The byte transfer time is the amount of time to transfer a single byte from a sketch to the LCD. Because it is measured from the sketch it accurately measures how fast a sketch can write tothe LCD.

The 16x2 frames per second is the number times an entire 16x2 frame can be written per second. Frame time is the amount of time it takes to write a full 16x2 frame.

The test was done using Arduino IDE 1.6.9 on an Arduino UNO using a typical hd44780 16x2 display. The only thing changed between the test was the library and its configuration.

                   ByteTransfer  16x2FPS   16x2FrameTime
LiquidCrystal  4bit    316 us      93.04        10.75 ms
LiquidCrystal  8bit    196 us     150.02         6.67 ms
My "Smart" lib 4bit    105 us     280.46         3.57 ms

Note that using the stock IDE LiquidCrystal library 8 bit mode is more than 1/3 faster at transferring bytes to the LCD. And by simply handling the execution times in a smarter way, 4 bit mode can be faster than the 8 bit mode on the IDE LiquidCrystal library all while still using the Arduino digitalWrite() API interface.

Now the additional performance may not be needed but this shows that 8 bit mode is definitely faster than 4 bit mode and that by handling the execution times in a different and smarter way things can be even better.

While even the much slower LiquidCrystal 4 bit mode can udpate a display faster than the human eye could detect it and faster than the liquid crystal molecules can adjust - if that is all it is doing - the lower overhead and faster updates can still be very useful as it frees up the processor to do other things. i.e. if you can update the display in less time, there is more CPU to do other things.

Anyway this shows that there is a measurable difference between 8 bit mode and 4 bit mode, particularly when using Arduino libraries. So this comment from post #1:

There is no speed advantage in using 8-bit mode

has been officially debunked.

--- bill

It's all very interesting but the OP was not concerned about speed. He was concerned about displays that would apparently work in 4-bit mode but not in 8-bit mode or vice versa.

I am curious to find out if this phenomena occurred only when using the LiquidCrystal library or if it was duplicated when using stand-alone code.

Don

floresta: It's all very interesting but the OP was not concerned about speed. He was concerned about displays that would apparently work in 4-bit mode but not in 8-bit mode or vice versa.

While he was not interested in speed of LCD updates, speed & timing has everything to do with what is causing the issues. And that is why the explanations I offered included timing calculations which were offering an explanation why

ptrex PWB 20434 : 20*4 : works only in 4 bit mode

and

Delta Opto PDC1602M : 16*2 : never works 

The reason for certain displays not working was likely to be that it has everything to do with speed. If you send another instruction to the LCD before the previous one completes all kinds strange things can happen. 4 bit mode is slower at sending commands/data than 8 bit mode and so depending on the LCD execution timing of the LCD, 4 bit mode could offer just enough additional time for the commands to complete that would fail in 8 bit mode. And that is why I kept making such a big deal about david's comment about there being no speed advantage in using 8 bit mode being wrong. 8 bit mode is faster and when dealing with timing issues due to being too fast, being even just a little faster makes things even worse.

So my conclusion was that because of the LCD execution timing, 4 bit mode could possibly be just enough slower to allow the commands to work on the ptrex but not slow enough to work on the Delta Opto.

And from the other thread: http://forum.arduino.cc/index.php?topic=124727.msg938538#msg938538

timing (speed) was the issue. When delays waiting for some of command executions were increased, the slowest display started working.

The changes shown in that post didn't increase any of the timing for normal commands or data writes, It only increased the timing for - clear() and home() - 4 bit mode - timing for the first 3 FunctionSet commands - 8 bit mode - timing for the first 2 FunctionSet commands

But more than likely the only delays that needed to be longer were for clear() and home(). Since the normal commands are working with no added delays, then the 2nd and 3rd FunctionSet in begin() need no extra time and it is possible that the first FunctionSet in begin() doesn't need any extra either. Especially considering that the first FunctionSet command only needs extra time if the initialization sequence sends the first FunctionSet when the LCD is in 4 bit mode, is out of nibble sync with the host and the first nibble sent before the FunctionSet sequence was a 0. From a powerup state, that won't ever happen.

And in the end, all of this was about execution timing that was fixed by increasing the delays. And it was exactly what what I was predicting in my first post to this thread in response #4: http://forum.arduino.cc/index.php?topic=416796.msg2870646#msg2870646

I would be curious if the slow LCD works if the only thing changed were the delays in home() and clear().


BTW, the LiquidCrystal code with the increased delays posted in the other thread is not the code from IDE 1.6.10 is is much older. It is from an IDE that is before IDE 1.6.0 and it is slower LiquidCrystal code than the more recent IDEs are using so that affects timing as well. The older LiquidCrystal code re-programs the pinMode of each pin just before setting the output state on each transfer to the LCD. So in 4 bit mode, each pin's output mode gets re-programmed twice for each instruction. Whereas on the more recent code it is does this zero times. So with the older code regardless of 4 bit or eight bit mode, there is a bit more than an extra 50us of added overhead added to sending each byte.

This 50 us goes away in 1.6.0 and later. So on the later IDEs, it is is equivalent to waiting 50us less after sending each instruction.

--- bill

While he was not interested in speed of LCD updates, speed & timing has everything to do with what is causing the issues.

My point is that the code that I suggested for him to try is nice and straightforward and to the best of my knowledge satisfies all of the HD44780U (and older Optrex as well) datasheet speed, timing, and initialization requirements.

If that code works then the problem can be attributed to the library whereas if it doesn't then it is more likely to be a display problem. It should be much easier to tinker with the stand-alone code to determine where any extra delays might alleviate the problem.

Don

Edit: Your previous post gives a possible explanation for why the 4-bit mode may work when the 8-bit mode doesn't so in that respect it is certainly pertinent. Since this behavior is the opposite of what we usually encounter it certainly is interesting.

You gave me a lot to read guys!

Speed is not my biggest concern but it’s like when you buy a nice V8 powered car, you expect all cylinders to participate, right? Well with my display it was just a V8 running on only 4 cylinders and that was very strange.

Anyway the problem is solved, now you expect me to tell you how :grin:

I tried all sketches available at the Donald Weiman site (link provided by Don in post 3 of this thread). That is 4 bit mode / 8 bit mode / with busy flag / without busy flag (delays according to Hitachi datasheet). In all cases that display worked only in 4 bit mode. It can’t be software and/or timings anymore; it has to be hardware on the Optrex display.

I checked all header pins toward the HD44780 IC (pins 36 to 46). There was a problem with pin DB2, wire wrap wire directly between that pin and the header = problem solved. Display works well with both Arduino LiquidCrystal lib and Donald Weiman examples.

Thanks again to Don (aka floresta) for the Donald Weiman link 8)

There is a LiquidCrystalFast version I just learned about. Would love to see the math arguments about that.

The math arguments would be identical regardless of the library. The critical timing for a given LCD is determined by the LCD not the library and Math is well, math..... What can vary between libraries is how well a library honors the LCD timing and the time it takes a library to push data to the LCD.

Perhaps you mean performance numbers for the library instead? Probably best discussed in another thread. --- bill