[Solved] LiquidCrystal library ignores display width set by lcd.begin()

I'm trying to set character display width with lcd.begin() function but I get unexpected results. It does not matter if I call "lcd.begin(24, 4)" or "lcd.begin(16, 4)", width remains 20 anyway. What am I doing wrong?

In LiquidCrystal.cpp this function is declared as "void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize)" but it seems like cols variable is ignored (never used in the code). But how LiquidCrystal determines display width then?

Here is detailed description of my problem. I have 24x4 character LCD (HDM24416L-1-L30P, datasheet and full spec.), it uses "HD44780 or equivalent".

I tried with LiquidCrystal.h but I get unexpected result. This is my code:

#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,4,5,6,7);

void setup() {
  lcd.begin(24, 4);
  // Print a message to the lcd.
  lcd.print("abcdefghijklmopqrstuvwxy"); // 24 characters
  lcd.print("ABCDEFGHIJKLMOPQRSTUVWXY"); // 24 characters
  lcd.print("0123456789_-.,9876543210"); // 24 characters
  lcd.print("ZYXWVUTSRQPONMLKJIHGFEDC"); // 24 characters
}
void loop() {}

Expected result:

abcdefghijklmopqrstuvwxy
ABCDEFGHIJKLMOPQRSTUVWXY
0123456789_-.,9876543210
ZYXWVUTSRQPONMLKJIHGFEDC

But instead I see the following on the LCD:

RQPONMLKJIHGFEDCrstuRQPO
vwxyABCDEFGHIJKLMOPQvwxy
RSTUVWXY0123456789_-RSTU
.,9876543210ZYXWVUTS.,98

Basically it "works" like 20x4 display. 4 last characters on the right are always like 4 characters on the left. According to full spec., address space for first row is 0x00..0x17. I do not know why characters written to 0x00..0x03 are copied to 0x14..0x17 (same for other rows). HD44780 is not supposed to support more than 80 characters but obviously this LCD have some HD44780-compatible controller capable of this.

At the moment my biggest problem is that I do not see a way to set display width of 24 characters instead of 20. I even tried lcd.begin(24, 2), but this did not change anything.

Most libraries don't really use the number of columns you provide at all. There are some 16x4 LCDs which are a little bit more tricky, and some libraries were modified to support them.
The HD44780 controller has 80 bytes for characters, and it can operate in either single line to 2-line mode. This is the only parameter the libraries use.
In a 20x4 LCD the first row in the LCD's RAM gets divided, 20 chars on the first row and 20 on the 3rd. The second row in the RAM is split into row 2 and 4 on the screen itself.
If you want to limit your application to display information on specific area of the screen you will either have to find a library which can do that (or write your own) or simply do it in your own code when you print the data.

Here is detailed description of my problem. I have 24x4 character LCD (HDM24416L-1-L30P, datasheet and full spec.), it uses "HD44780 or equivalent".

It can't really be HD44780 equivalent if it has more than 80 characters. It's instruction set may be the same but it's memory map has to be different.
For a complete explanation of the HD44780 addressing idiosyncracies then follow the LCD Addressing link at http://web.alfredstate.edu/weimandn.

Don

There are some 16x4 LCDs which are a little bit more tricky, and some libraries were modified to support them.

As far as I can tell all of the 16x4's are 'tricky'. The Arduino LiquidCrystal library is among those that do not handle the 16x4 displays properly. It also does not handle most 16x1 displays properly either.

The link in my previous post explains the whole addressing mess.

Don

Don,
Is the 24x4 addressing as shown in the datasheet Lissanro provided "standardized"?
That geometry does not show up on the link you provided.
If it is, I'll add in support for 24x4 to fm's library.

--- bill

Is the 24x4 addressing as shown in the datasheet Lissanro provided "standardized"?
That geometry does not show up on the link you provided.

I doubt that there is anything 'standard' about that display, it seems to be a one-of-a-kind device unique to Hantronix. There was quite a bit of discussion about it on avrfreaks (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=112835) almost two years ago and there was a link to that exchange in another Arduino thread just yesterday.

They have an interesting way of numbering the pages in their supposedly 'full' specifications (3 --> 48 --> 44 --> 42 --> 43 --> 46 --> 5 --> 47). Somehow I suspect there may be more information that we are not seeing.

Don

OK - I have unearthed some additional information. It is possible that this display uses a KS0078 controller or something similar. This controller has 96 bytes of display RAM (the HD44780U has 80 bytes) which would allow it to handle the extra characters in a 24x4 display. It also has a command set that, at a glance, appears to be a superset of that of the HD44789U controller.

This means that the standard LiquidCrystal library will not be able to use the 'extra' capabilities of this controller such as handling the 24 character line length since it doesn't deal with the bits needed to invoke the enhanced commands. On the other hand it shouldn't be much of a job to write some extra instructions to do so.

Don

I already mentioned that on the right side of each row I get "copies" of first 4 left characters, but now I noticed that they are not exact copies - they are shifted 1 pixel downwards. I googled, and found LCD 24x4 wrong display thread on AVRfreaks, somebody encountered exactly the same problem with 24x4 LCD. At the end of the thread he was going to try 8-bit interface, but did not report back. After carefully reading full spec., I noticed this note: "# Set to 1 on 24x4 modules", where "#" is part of Function Set command, and it must be set by D0 pin. But 4-bit interface uses D4-7 pins.

So 4-bit interface is not really supported by this 24x4 LCD (you can use it with 4-bit interface as 16x4 with 4 spaces on left and right side or as 20x4 with some garbage on the right side but that is not very nice). I of course want to use it as 24x4, so I connected it via 8-bit interface. Then I have downloaded LiquidCrystal_V1.2.1.zip (because in the future I may need extra capabilities of this library) and wrote the following patch:

-- LiquidCrystal/LCD.h 2012-04-05 16:19:54.000000000 +0000
+++ LiquidCrystal/LCD.h 2013-09-04 15:29:20.909576830 +0000
@@ -123,6 +123,7 @@
 #define LCD_4BITMODE            0x00
 #define LCD_2LINE               0x08
 #define LCD_1LINE               0x00
+#define LCD_24x4                0x01
 #define LCD_5x10DOTS            0x04
 #define LCD_5x8DOTS             0x00
 
--- LiquidCrystal/LiquidCrystal.cpp     2012-04-05 16:19:54.000000000 +0000
+++ LiquidCrystal/LiquidCrystal.cpp     2013-09-04 15:29:50.777864373 +0000
@@ -258,7 +258,7 @@
    if (fourbitmode)
       _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
    else 
-      _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
+      _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_24x4;
    
    // Now we pull both RS and R/W low to begin commands
    digitalWrite(_rs_pin, LOW);
--- LiquidCrystal/LCD.cpp       2012-04-05 16:19:54.000000000 +0000
+++ LiquidCrystal/LCD.cpp       2013-09-05 01:03:30.561860873 +0000
@@ -172,6 +172,7 @@
 {
    const byte row_offsetsDef[]   = { 0x00, 0x40, 0x14, 0x54 }; // For regular LCDs
    const byte row_offsetsLarge[] = { 0x00, 0x40, 0x10, 0x50 }; // For 16x4 LCDs
+   const byte row_offsets24x4[]  = { 0x00, 0x20, 0x40, 0x60 }; // For 24x4 LCDs
    
    if ( row >= _numlines ) 
    {
@@ -181,13 +182,11 @@
    // 16x4 LCDs have special memory map layout
    // ----------------------------------------
    if ( _cols == 16 && _numlines == 4 )
-   {
       command(LCD_SETDDRAMADDR | (col + row_offsetsLarge[row]));
-   }
-   else 
-   {
+   else if ( _cols == 24 && _numlines == 4 )
+      command(LCD_SETDDRAMADDR | (col + row_offsets24x4[row]));
+   else
       command(LCD_SETDDRAMADDR | (col + row_offsetsDef[row]));
-   }
    
 }

To apply the patch above save it to file 24x4.diff, cd to where LiquidCrystal_V1.2.1 is installed (in my case /usr/share/arduino/libraries/LiquidCrystal) and apply it by running "patch -p1 < 24x4.diff". After that full support for 24x4 LCD will be available in 8-bit mode, so if I lcd.print("ABCDEFGHIJKLMOPQRSTUVWXY") then I will see all 24 characters on one line, as expected. The patch can be easily adapted for standard LiquidCrystal library. I guess LCD_24x4 bit set by D0 pin will probably be ignored by standard LCD but for 24x4 display it is essential.