20x4 LCD has duplicate cursor coordinates

Hi,

I'm currently working with my new 20x4 LCD display. It's from Electronic Assembly, PartNr: DIP204B-4NLW (just for the case you want to know) The Datasheet says "KS0073 Controller (Nearly 100% compatible to HD44780)", might be the problem? I dunno...

So for addressing purpose, I made a littel programm which shows an X on the LCD and also displays the coordinates of that X, as you could use those in the lcd.setCursor(c,r) method. I resulted in a Coordinate-Map: I did not included multiple coordinates for a single cell, but see the red marked:

| 0,0 | 1,0 | 2,0 | 3,0 | 4,0 | 5,0 | 6,0 | 7,0 | 8,0 | 9,0 | 10,0 | 11,0 | 12,0 | 13,0 | 14,0 | 15,0 | 16,0 | 17,0 | 18,0 | 19,0 | | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | | 12,0 | 13,0 | 14,0 | 15,0 | 16,0 | 17,0 | 18,0 | 19,0 | 0,2 | 1,2 | 2,2 | 3,2 | 4,2 | 5,2 | 6,2 | 7,2 | 8,2 | 9,2 | 10,2 | 11,2 | | 0,1 | 1,1 | 2,1 | 3,1 | 4,1 | 5,1 | 6,1 | 7,1 | 8,1 | 9,1 | 10,1 | 11,1 | 12,1 | 13,1 | 14,1 | 15,1 | 16,1 | 17,1 | 18,1 | 19,1 | | 10,4 | 11,4 | 12,4 | 13,4 | 14,4 | 15,4 | 16,4 | 17,4 | 0,3 | 1,3 | 2,3 | 3,3 | 4,3 | 5,3 | 6,3 | 7,3 | 8,3 | 9,3 | 10,3 | 11,3 |

The red cells have the same coordinates and there are not multiple entries as for some other cells. So if I wan't to write something in the end of the first line, it will ALWAYS be also in the beginning of the second line and vice versa...

I went through a whole bunch of ranges, after all, 0 to 40 for the columns and 0 to 8 for the rows. Without getting any more address for those cells.

Is it the slightly different controller? Or am I doing things wrong?

Point is, the display should show the current time over it's whole size, so the Numbers are seperated into cells, representing a cell in the display.

Does anyone know anything about that behaviour?

P.S.: Sorry, I haven't figured out, how I can add lines to the table... would be better to read...

Post your code.

The code is nothing special, just a “walker” which walks through the LCD by command and shows the current coordinates:

#include "LiquidCrystal.h"

//Init LCD
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//Some vars
int a;//Column
int b;//Row
int command;//Serial Command

void setup(){
  Serial.begin(9600);
  lcd.begin(20, 4);
  
  //I use this to control the conrast of the LCD
  pinMode(10, OUTPUT);
  analogWrite(10, 130);
}

void loop(){
  //Serial input stuff
  if(Serial.available()){
   command = Serial.read(); 
  }
  
  //Check if 'n' has been sent to go one step per n ahead
  if(command == 'n'){
   if(a < 40){
    a = a + 1;
   }else{
     a = 0;
     b = b + 1;
   } 
  }
  
  //Clear previouse crap
  lcd.clear();
  
  //Print coords top-left
  lcd.setCursor(0,0);
  lcd.print(a);
  lcd.print(",");
  lcd.print(b);
  
  //Print coords bottom-right
  lcd.setCursor(3,3);
  lcd.print(a);
  lcd.print(",");
  lcd.print(b);
  
  //Print position marking X
  lcd.setCursor(a,b);
  lcd.print("X");
  
  //LOOP END Stuff
  command = '0';
  delay(250);
}

If you want to figure out the addressing then just follow the LCD Addressing link at http://web.alfredstate.edu/weimandn.

If you want to see how the display works in practice then try this (untested) sketch:

#include <LiquidCrystal.h>

//LiquidCrystal lcd(rs,en,d4,d5,d6,d7);
  LiquidCrystal lcd(12, 11, 5, 4, 3, 2);       // put your pin numbers here

void setup()
  {
    lcd.begin(20, 4);
    for (int i=47; i<127; i++)                 // send 80 consecutive displayable characters to the LCD
    {
    lcd.print(i,BYTE);
    delay(100);                                // this delay allows you to observe the addressing sequence
    }
  }
void loop()
  {  
  }

Don

Hm, ok, I checked the link and figured out, how the addressing should work/behave. And for me, it does not match! Check out the video I just made to demonstrate the Coordination issues: http://www.youtube.com/watch?v=9WCEsonXy1o

I think it is the different controller, it seems to have a slightly different behaviour in the DDRAM addressing. Next point on my list is, to read the specs on that thing and I might adjust the LiquidCrystal.cpp to match my requirements.

I think it is the different controller, it seems to have a slightly different behaviour in the DDRAM addressing.

It is much more likely that your logic and/or your implementation is incorrect. I am not proficient in 'C' so I can't troubleshoot your code.

Have you tried my sketch? It should allow you to determine if your controller is the same as all the others out there.

Don

Hm, I'm not that good in C either, but as far as I understand, you can simply user "setCursor(column, row)" to choose a column and row by it's number, without bothering about Hex-Values and Offsets and that stuff.

I tried your code and it also seems to be not as it's thought to be:

I think, the second line should be more like "CDEFG..." and not a "copy" of the second half of the first line.....

I think, the second line should be more like "CDEFG..." and not a "copy" of the second half of the first line.....

This is definitely not what I expected. Actually on most LCD modules it is the third line that typically starts with "CDEFG", and that line should be "CDEFG...RSTUV".

Could you make another video so that I can see the sequence of events as this display is created.

Don

Do you have a datasheet link of the LCD ?

OK - now it is coming back to me. The KS0073 is a new and improved controller that does indeed have a different memory map than the HD44780 controller and its derivatives. With only a cursory look at the data sheet here is my preliminary guess as to what is happening. When using the standard HD44780 there is no way of telling the controller what kind of display is attached, but with this controller there is. I think the controller is assuming that a display with a different configuration than yours is attached. If that is the case you should be able to fix things up with some changes to the initialization steps.

Don

I found a bug in the LCD.setCursor, see - http://arduino.cc/forum/index.php/topic,74729.msg563179.html#msg563179 - when looking through the cause of this, but I don’t think it is your bug.

In another thread I found people who changed the array in of starting points of the lines - int row_offsets = { 0x00, 0x40, 0x14, 0x54 }; - in the lib but that would not solve it. as it was to handle wrong positions.

Looks to me like a hardware failure that somehow two address lines are shorted. There are 8 positions visible that “are doubled” (and maybe 8 invisibles too) for both the upper part and the lower part. But the strange thing is that it only goes in one direction…

  • can you check if you use 8 datalines for the display?

  • BUG: your testcode allows a to become bigger than 20 19 and b to become bigger than 4 3 ==> that may cause the strange effects … (updated the numbers :slight_smile:

slight modification to keep a and b within bounds, not tested, please give it a try.

#include "LiquidCrystal.h"

//Init LCD
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  Serial.begin(9600);
  lcd.begin(20, 4);
  
  //I use this to control the contrast of the LCD
  pinMode(10, OUTPUT);
  analogWrite(10, 130);
}

void loop()
{
  for (b=0; b <4; b++)
    for (int a =0; a < 20; a++)
    {
  // debugging
  Serial.print(a);
  Serial.print(",");
  Serial.print(b);

  lcd.clear();
  
  //Print coords top-left
  lcd.setCursor(0,0);
  lcd.print(a);
  lcd.print(",");
  lcd.print(b);
  
  //Print coords bottom-right
  lcd.setCursor(3,3);
  lcd.print(a);
  lcd.print(",");
  lcd.print(b);
  
  //Print position marking X
  lcd.setCursor(a,b);
  lcd.print("X");
  }
}

results?

First things first, here's the link to the english datasheet of my LCD: http://www.lcd-module.com/html-seiten/eng/pdf/doma/dip204-4e.pdf I have the EA DIP204B-4NLW, it's the one with blue background and white characters (as you sure already know by my video/image :D )

I made a Video of running the init-code of floresta and the loop-walking-x-thing, improved by robtillaart: http://www.youtube.com/watch?v=RBo5TcW1eag

From coordinates 12,3 and 12,4 you can "see", that till 20,3 and 20,4 the characters are invisible.

The LCD is connected to the Arduino by the standard tutorial setup via 4 data pins:

LiquidCrystal lcd(12, 11, [b]5[/b], [b]4[/b], [b]3[/b], [b]2[/b]);

[Edit: Video added]

On page 3 of the datasheet is a small table :

Addressing: 1st. line $00..$13 2nd. line $20..$33 3rd. line $40..$53 4th. line $60..$73

As you might notice there are addresses missing and with the way you did the addressing you might have accessed these (undefined?) areas?

PLease try to patch the -int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 } - in LCD.setCursor() - to reflect the data addresses from the table.

void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
  int row_offsets[] = { 0x00, 0x20, 0x40, 0x60 };
  if ( row >= _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }
  
  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

Hm.... ok, yeah.. i totally overread that table...

But, it still does not work with the fixed address-offsets in the cpp-file.

I googled and found a german thread about it: http://www.roboternetz.de/community/threads/8939-DIP-LCD-%28KS0073%29-Problem

There it says in the second post (freely translated by me):

...After switching into the 4 bit mode, a specific bit needs to be set (in the command table the left column), then - and only then - the controller can be switch into the 4 line mode...

I'm currently going through the whole LiquidCrystal.cpp and try to find anything about that, but I'm not a C-Programmer, neither I'm pretty bad at that low-level hardware command stuff...

Ok, I have a question:

in the LiquidCrystal.h are all the definitions, like:

// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80

and more...

Now, in the datasheet of my LCD is the initialisation example for the 8-bit mode:

Function Set: $34
ext. Function Set: $09
Function Set: $30
Display ON/OFF: $0F
Clear Display: $01
Entry Mode Set: $06

Now these values differe from the definitions of the .h-file.
The “Entry Mode Set” for example is defined 0x04 in the .h-file, but the datasheet say 0x06.
As I mentioned, I don’t know much about that hardware-level command stuff.
Is this a problem? Is the whole LiquidCrystal-Library just not matching the commands for the different controller?

Near the bottom of page 4 of the data sheet for the display you will find a link to the datasheet for the KS0073 controller. There is much more information concerning the memory mapping in that datasheet but without a display to tinker with it is almost impossible for me to decipher some of the information. It must be even harder for you with an additional translation involved.

The controller is listed as being nearly compatible with the HD44780 so one would expect that, if you didn’t invoke any of the fancy features of this controller, it would perform like the Hitachi controller and work correctly with the LiquidCrystal library. This is obviously not the case. (Be aware that none of the versions of the LiquidCrystal library so far work properly with 16x4 displays, the row offsets are different for these displays and the library does not deal with this.) You might want to experiment with the LiquidCrystal440 library and see how it works with your display.

Your video was very interesting and it supports my theory that the memory map is different. Here are my observations.

The display shows up on rows 1 → 2 → 3 → 4 as a normal person would expect, not on rows 1 → 3 → 2 → 4 as the Hitachi chip works.
The chip works as expected for columns 1 → 12, it is columns 13 - > 20 that are duplicated. This is significant when you look at the memory maps in the controller datasheet.
The duplicate text occurs as : : then ; ; then < < … etc, not : ; < … at the end of row 1 followed by : ; < … on row 2.
There is a pause between the end of the display of the characters on line 2 and the beginning of the display of characters on line 3.
There are 8 characters, O P Q R S T U V, missing between the end of the display of the characters on line 2 and the beginning of the display of characters on line 3 (corresponding to the pause).
There are 8 characters missing after the end of line 4 as well and there would most likely be a pause before line 1 was overwritten if we had sent more than 80 characters.

All of this supports the fact that the memory map is indeed different, but that does not really explain the duplicate characters that occur. Tinkering with the row offsets in the LiquidCrystal library will probably not fix this problem since those offsets are only used for the cursor positioning routine which my sketch does not use.

It looks like we have something similar to ‘foldback memory’ where more than one address accesses the same memory location. Here we have the case of more than one memory location being accessed by one address. The answer is probably somewhere in the controller datasheet.

Don

(Reply #14)

Ok, I have a question:

The definitions in the .h file just represent the specific bits that identify the individual commands.

To evaluate the actual commands shown in the datasheet you have to convert the hex code to binary and compare the binary values to the command table on page 2 of your display datasheet.

The "Entry Mode Set" for example is defined 0x04 in the .h-file, but the datasheet say 0x06.

0x04 --> 0b00000100 this identifies the bit that must be high so that the controller knows it is an "Entry Mode Set" command 0x06 --> 0b00000110 this also has the actual command bits included, the ones that tells the controller what you want the "Entry Mode Set" command to do

Don

IT WORKS! It finally works!

OK, reference to the old german forum post: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1249053552

In Posting 4 XCV says:

command(0x2C);      //Function set RE on
delayMicroseconds(150);
command(0x09);  //ext. Function set 4-line display
delayMicroseconds(150);
command(0x28);  //Function set RE off

I inserted that code into the LiquidCrystal.cpp in line 158, right after those line:

  // set the entry mode
  command(LCD_ENTRYMODESET | _displaymode);

And of course I had to adjust the address offsets in line 182 (with the above code already inserted!), which are now:

  int row_offsets[] = { 0x00, 0x20, 0x40, 0x60 };

With these two adjustements, the cursor positions are now working just as they should!

Note: Due to the Line-Offsets, the lines are accessed in the order 1 > 2 > 3 > 4, not as known from the HD44780 controller way 1 > 3 > 2 > 4

Now I can finally relax and have dinner :)

Thank you all very much for your help!!