Interfacing 40x4 LCD (SPLC780D or ST7066U)

TheCoolest:
You need to either hook up a POT or hook up Vo to ground, this is the contrast pin, without doing so you will not see anything on the display.

So the lcd should have these 2 rows that are dark square blocks? That's normal?

When you apply power, yes. After you initialize the display it should go blank and allow you to send data to it.

Anyone know someone who may be able to help with the coding to get this LCD working?

Doesn't the code you posted in the first post work?

Doesn't the code you posted in the first post work?

That is not really a good sketch to use for testing any LCD, much less one with four lines.

The most important problem is that by putting the code in loop() you are rewriting the same information to the display over and over again, even though the information does not change. That type of information should should be displayed in setup().

Also, you are not checking out the cursor positioning which is especially important with a display such as yours which has two controller chips.

Here's what I typically recommend for a generic 16x2 display.

#include <LiquidCrystal.h>

//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);      // put your pin numbers here

void setup()
  {
  lcd.begin(16, 2);                          // put your LCD parameters here
  lcd.print("hello, world!");
  lcd.setCursor(0,1)
  lcd.print("it works!");
  }

void loop()
  {
  }

If you use this code with your display and the standard LiquidCrystal library it should work correctly for either the upper or lower two lines depending on which chip select line you use. You can also use it to test out both halves of the display at once (with the same information on each half) by connecting both of your chip select lines to the same Arduino pin.

This code can also be modified fairly easily to test your display with the updated LiquidCrystal440 library. Make sure that you follow the Downloads link to get to the latest version as I mentioned earlier.

The reason my code is the way it is is because once the first row is filled up it will go to the next and so on(right??). So there shouldn't be a problem with how I have the lcd.print in the loop() instead of in the setup(). I've tried all the basics like using the normal liquidcrystal library and running half and half. So 40x2 with one enable pin and another 40x2 with the other enable pin. Nothing at all works. I've used pretty much all the libraries in the downloads link you suggested floresta.

I have a feeling your right when you said: "Many of the New Haven displays use a controller that has an instruction set based on that of the Hitachi HD44780U but the instructions are not identical nor are the timing requirements. It is likely that the library would have to be modified to work with those displays."

So that leaves coding the library which I don't have a clue on. Is there a chance we can get someone to help with modifying the 40x4 library to work with the controller used in this LCD? That would be a great service to myself and anyone else who purchases this LCD considering its on digikey and easy to purchase.

The reason my code is the way it is is because once the first row is filled up it will go to the next and so on(right??).

Yes, as long as you are not interested in controlling where your message appears.

So there shouldn't be a problem with how I have the lcd.print in the loop() instead of in the setup().

The display does not have to be 'refreshed'. If the information does not change it only has to be written to the display once. There's no problem in rewriting the information unless you try to do it too quickly and as long as you don't care about any flicker that may come up. BUT - you don't want to do this while you are verifying that your display is working. You want to write something to the display and see if it actually appears there. By doing this in loop() you are introducing the possibility that your information was written correctly and was then immediately overwritten by something else. The bottom line is that you don't really want to do anything in loop() while you are initially trying to get your LCD to work.

In order to determine if your New Haven display can use a library written for an HD44780U controller or if there is another problem you will need to get a copy of the datasheet for your particular display. The information at the link in your original post is more like a sales blurb than a datasheet.

Since there have been many questions in the forum about this topic I approached New Haven and asked them to send me one of their displays so that I could work with it and be better equipped answer such questions. They offered to sell me one but declined to send a complimentary sample. I am not inclined to spend money on a display just so I can do their product support for them.

Is there a chance we can get someone to help with modifying the 40x4 library to work with the controller used in this LCD?

John Raines, the author of LiquidCrystal440, used to participate in this forum (jrraines) but I have not seen him around in a while. You could try and contact him.

Don

Yeah, he hasn't been on since 2012. I doubt I'll have any luck finding him.

I could not find a datasheet other than the one I found that i posted on the first post. I did find the two controller datasheets.

Controller Information
Built?in SPLC780D. Download specification at http://www.newhavendisplay.com/app_notes/SPLC780D.pdf
Built?in ST7066U. Download specification at http://www.newhavendisplay.com/app_notes/ST7066U.pdf

Do you know why there are two different controllers and how do you select which controller to use when you want to display information on the lcd?

have you tried the standard LiquidCrystal library? It would work on half of the display, but should still let you test whether your display is good or bad.
Unless the controller on it is not HD47780 compatible.

TheCoolest:
have you tried the standard LiquidCrystal library? It would work on half of the display, but should still let you test whether your display is good or bad.
Unless the controller on it is not HD47780 compatible.

Yea i posted about that up on replay #10. I will probably redo my tests again using all the libraries just to make sure i didn't do something wrong. That would suck if it was a bad lcd to begin with but I don't think it is considering it does show the two dark lines across the screen whenever the VO pin is grounded.

Here are some pictures. The LCD is upside down btw. The one with the two lines is what happens when i use pins 5-8 and the other image with the weird characters is when i use pins 1-4. However now after i turned off the lcd and still using pins 1-4 it just shows a single blinking square in the middle of the screen. So maybe the weird characters were just temporary. I've also included an image of the pins from the datasheet.

Does this help anyone?

pins.JPG

Controller Information
Built?in SPLC780D. Download specification at http://www.newhavendisplay.com/app_notes/SPLC780D.pdf
Built?in ST7066U. Download specification at http://www.newhavendisplay.com/app_notes/ST7066U.pdf

Do you know why there are two different controllers and how do you select which controller to use when you want to display information on the lcd?

The wording on the spec sheet is "2 Built?in controllers (SPLC780D or ST7066U)".

There are two controllers on the board because each one has only enough memory to deal with 80 characters.

On any given board I would expect to find that under the epoxy blobs there are either two SPLC780Ds or there are two ST7066Us.

You determine which one to use by means of the two separate chip select pins.

Both of these chips are HD44780U compatible so there appears to be no reason why they won't work with the standard LiquidCrystal libraries. I guess it's time for you to provide us with some photographs of your setup etc.

Don

[Edit] I see that while I was writing this you posted some pictures. I'll look at them and get back to you.

The one with the two lines is what happens when i use pins 5-8 and the other image with the weird characters is when i use pins 1-4.

I think you are confused about the function of these data lines.

Part of the problem is that the pin numbering on your module is non-standard although the pin names are standard.

Pins 1 <--> 14 on your module are exactly backwards from those of a 'normal' LCD module.

Pins 15 on your module is the extra chip select for the lower two lines of your display.

Pins 17 and 18 of your module control the backlight as do pins 15 and 16 on most other modules. There is no 'standard' here.

To use any display with the standard LiquidCrystal libraries in the 4-bit mode you do not use DB3 <--> DB0 which are pins 5 <--> 8 on your module.

We need to be able to follow the wiring in your upper photo, or we need an accurate description of where each end of each wire is connected. We also need to see your sketch, specifically the descriptor if it's not the same as this one you showed us before.

//LiquidCrystal lcd(RS,RW,Enable1,Enable2,data3,data2,data1,data0); // for 40x4 lcd
LiquidCrystal lcd(31,33,35,37,39,41,43,45);

Also make sure loop() is empty as we discussed previously.

Don

I was trying to achieve the fastest possible write times with a HD47780 LCD so I wrote a low level code to handle the LCD's Busy flag.
I can post my code and a schematic if you want, but they are designed to work on an Atmega328, but since you have a Mega I'm not sure it will be of any help to you.

Using pins 1-4.

I connected:
lcd pin 1 to 39 on arduino
lcd pin 2 to 41 on arduino
lcd pin 3 to 43 on arduino
lcd pin 4 to 45 on arduino

so looking at this code:

//LiquidCrystal lcd(RS,RW,Enable1,Enable2,data3,data2,data1,data0);
LiquidCrystal lcd(31,33,35,37,39,41,43,45);

data3 = db7
data2 = db6
data1 = db5
data0 = db4

correct?

pinorder.JPG

Oh my god.. i switched all the pins to be in the other order and its working!

so the correct order should be:

lcd pin 1 to 45 on arduino
lcd pin 2 to 43 on arduino
lcd pin 3 to 41 on arduino
lcd pin 4 to 39 on arduino

data3 = db4
data2 = db5
data1 = db6
data0 = db7

Congrats, that's a beautiful screen :smiley:

data3 = db4
data2 = db5
data1 = db6
data0 = db7

No. The terminology in your descriptor comment is wrong.

I wasn't looking very carefully when I copy/pasted your code fragment.

//LiquidCrystal lcd(RS,RW,Enable1,Enable2,data3,data2,data1,data0);

This should most likely be (I haven't looked at the '440 library recently):

//LiquidCrystal lcd(RS,RW,Enable1,Enable2,data4,data5,data6,data7);

since you can never use D0 <--> D3 without also using D4 <--> D7 but you can use D4 <--> D7 without D0 <--> D3.

I see that you carefully did not follow my advice about using code in loop() while trying to get an LCD running for the first time.

Don

Yeah not sure why the arduino code comment was the way it was.

//LiquidCrystal lcd(RS,RW,Enable1,Enable2,data4,data5,data6,data7);

should be correct. maybe this lcd is slightly different than the standard.

no reason to not spam the screen with a 400ms delay in there :stuck_out_tongue:

TheCoolest it wouldn't hurt posting the fast code you mentioned in case someone else looking at this thread may want to try it.

Thanks for the help debugging guys.

Sure. This was just a proof of purpose code, it could probably be made a little faster yet, but I didn't bother.
This sketch is hardcoded for the following schematic (it should work on any Atmega328 chip, and 168s will probably work just as well):

*Click to enlarge

The code doesn't implement the analogWrites to control the backlight and Vo, so you can wire those as you normally would. Or add the required analogWrites.

// 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

// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00

// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00

// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00

#define RS 0x08
#define RW 0x10
#define EN 0x20

uint8_t initCmd = LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS;
uint8_t displayOn = LCD_DISPLAYCONTROL | LCD_DISPLAYON;// | LCD_BLINKON | LCD_CURSORON;
uint8_t displayMode = LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;

void command(uint8_t cmd);
void write(uint8_t data, uint8_t rs = RS);
void clearDisplay(bool hwClear = false);

void setup()
{
	Serial.begin(9600);
	Serial.println("Hello World");
	
	// Set all relevant pins as output
	uint8_t oldSREG = SREG;
	cli();
	DDRB |= 0x3E;
	PORTB = (PORTB & 0xC1) | 0x6;

	DDRC = 0xFF;
	PORTC = 0xFF;

	DDRD |= 0x30;
	PORTD &= ~0x30;
	SREG = oldSREG;
	
	initLcd();
	
	// LCD-Home command
	command(LCD_SETDDRAMADDR | 0x40);
	
	// Print 80 characters on the LCD, starting from '0'.
	uint8_t max = '0' + 80;
	unsigned long time = micros();
	for (uint8_t i = '0'; i < max; i++)
		write(i);
	time = micros() - time;
	Serial.print("Time to write 16 letters "); Serial.print(time); Serial.print("us");
}

void loop()
{

}


void initLcd()
{
	// Initialization sequence
	delay(50);
	command(initCmd);
	delay(5);
	command(initCmd);
	delay(1);
	command(initCmd);
	command(LCD_DISPLAYCONTROL | LCD_DISPLAYOFF);	
	command(LCD_CLEARDISPLAY);
	command(displayMode);
	// ----------------------------

	command(displayOn);
	command(LCD_RETURNHOME);
}



void command(uint8_t cmd)
{
	write(cmd, 0);
}

void write(uint8_t data, uint8_t cmd)
{
	cmd |= EN;
	
	// While LCDs DB7 pin is high, busy-wait.
	while (isLcdBusy());

	// Write data.
	PORTC = data & 0x3F;  // 6 LSBs
	PORTD = (PORTD & ~0x30) | ((data >> 2) & 0x30); // 2 MSBs

	// Issue Enable
	PORTB = (PORTB & 0xC7) | cmd;
	delayMicroseconds(1);
	PORTB &= ~cmd;
}

bool isLcdBusy()
{
	bool ret = false;
	// Set bits 4, 5 of portD as input
	DDRD &= ~0x30;
	// Set LCD to read busy flag
	PORTB |= (EN | RW);
	delayMicroseconds(1);
	PORTB &= ~(EN | RW);
	ret = (PIND & 0x20) != 0;
	// Set bit5 portD to output
	DDRD |= 0x30;	

	return ret;
}