EmbeddedRelated.com
Forums
Memfault Beyond the Launch

HD44780 Initialisation (20x4 display in 4-bit mode)

Started by Kevin Townsend October 4, 2008
I've spent the last couple day trying to get a 20x4 character HD44780
LCD working with my Olimex H2148, and have poured over at least 5
different examples (including the one in the files section here)
trying to put together a basic class to work with 44870 LCD.

I'm almost certain I have the board wired up properly (including &
10K resistor for contrast on pin 3), and I've read through the entire
Hitachi datasheet and double-checked my command codes, comparing them
with other people's examples, but whatever I feed the board it
doesn't seem to do anything. Line 1 and 3 have solid blocks, and
line 2 and 4 have nothing.

It must be something with the way the commands are sent, but I don't
see it myself. If anyone has any experience, I'd certainly
appreciate another set of eyes and someone else's experience. My
guess is I screwed something up with either 'hd77480_Send_4Bits'
or 'hd77480_SendCommand' with the 4-bit business..

NOTE: The code below uses JCWren's (excellent) lpc210x.h, which isn't
included below, and the delay.h file from the lpc2000 group Files
section.

Example:
--------
hd44780_Init();
hd44780_SendCommand(HD44780_DISPON_CURSBLINKING);
hd44780_SendCommand(HD44780_CLEAR_DISPLAY);
hd44780_DisplayString("Test Test\n");
hd44780_SendCommand(HD44780_MOVE_CURSOR_DOWN);
hd44780_DisplayString("Test Test\n");

*********** START 44780.h ******************************
typedef enum
{
PIN_RS = 0x00080000, // 1.19 Register Select
PIN_RW = 0x00100000, // 1.20 Read/Write
PIN_E = 0x00200000, // 1.21 Enable
PIN_D4 = 0x00400000, // 1.22 Data 4
PIN_D5 = 0x00800000, // 1.23 Data 5
PIN_D6 = 0x20000000, // 1.18 Data 6 (1.24 is used on the
Olimex H2148)
PIN_D7 = 0x02000000 // 1.25 Data 7
}
hd44780_Pins_t;

typedef enum
{
HD44780_CLEAR_DISPLAY = 0x01, // Clear LCD
Display 1.52 mS
HD44780_HOME = 0x02, // Move the cursor to
the home position 1.52 mS
HD44780_DISPON = 0x0C, // Turn display on
with no cursor and no blink 37 S
HD44780_DISPON_CURSUNDERNEATH = 0x0E, // Turn display on,
with cursor under 37 S
HD44780_DISPON_CURSBLINKING = 0x0F, // Turn display on,
with blinking 37 S
HD44780_DISPOFF = 0x08, // Turn display
off 37 S
HD44780_ENTRYMODE_INCR_NOSHIFT = 0x06, // Auto increment
cursor position, no shift 37 S (Default entry mode)
HD44780_ENTRYMODE_INCR_SHIFT = 0x07, // Auto increment
cursor position, shift text 37 S
HD44780_ENTRYMODE_DECR_NOSHIFT = 0x04, // Auto decrement
cursor position, no shift 37 S
HD44780_ENTRYMODE_DECR_SHIFT = 0x05, // Auto decrement
cursor position, shift text 37 S
HD44780_MOVE_CURSOR_RIGHT = 0x14, // Shift cursor one
character to the right 37 S
HD44780_MOVE_CURSOR_LEFT = 0x10, // Shift cursor one
character to the left 37 S
HD44780_MOVE_CURSOR_UP = 0x80, // Shift cursor up
one character 37 S
HD44780_MOVE_CURSOR_DOWN = 0xC0, // Shift cursor down
one character 37 S
HD44780_SHIFT_TEXT_RIGHT = 0x1C, // Shift text one
space to the right 37 S
HD44780_SHIFT_TEXT_LEFT = 0x18, // Shift text one
space to the left 37 S
HD44780_SETFUNC_8BIT_2LINE_5x8 = 0x38, // 8 bit interface, 2
line display, 5x8 pix chars 37 S
HD44780_SETFUNC_8BIT_1LINE_5x8 = 0x30, // 8 bit interface, 1
line display, 5x8 pix chars 37 S
HD44780_SETFUNC_4BIT_2LINE_5x8 = 0x28, // 4 bit interface, 2
line display, 5x8 pix chars 37 S
HD44780_SETFUNC_4BIT_1LINE_5x8 = 0x20, // 4 bit interface, 1
line display, 5x8 pix chars 37 S
HD44780_BUSY = 0x80, // Check if the
controller is busy (1) or not (0)
HD44780_LINE2 = 0x40, // LCD display
address offset for line 2 (20x4)
HD44780_LINE3 = 0x14, // LCD display
address offset for line 3 (20x4)
HD44780_LINE4 = 0x54 // LCD display
address offset for line 4 (20x4)
}
hd44780_Commands_t;

// Method Prototypes
void hd77480_Send_4Bits(unsigned char v);
void hd44780_SendCommand(hd44780_Commands_t command);
void hd44780_Init(void);
void hd44780_DisplayString(char* str);
*********** END 44780.h ********************************
*********** START 44780.c ******************************
#include "lpc210x.h"
#include "44780.h"
#include "delay.h"

void hd77480_Send_4Bits(unsigned char v)
{
GPIO1_IOCLR |= ( PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 );
GPIO1_IOSET |= (v << 22);
}

void hd44780_SendCommand(hd44780_Commands_t command)
{
// Make sure that D4, D5, D6, D7, RS, RW, E are set to output ports
GPIO1_IODIR |= (1 << PIN_D4)
| (1 << PIN_D5)
| (1 << PIN_D6)
| (1 << PIN_D7)
| (1 << PIN_RS)
| (1 << PIN_RW)
| (1 << PIN_E);

// Write higher order bits
GPIO1_IOSET |= PIN_E;
hd77480_Send_4Bits((command>>4) & 0x0F);
GPIO1_IOCLR |= PIN_E;

DelayMS(2); // 2 ms

// Write lower order bits
GPIO1_IOSET |= PIN_E;
hd77480_Send_4Bits((command) & 0x0F);
GPIO1_IOCLR |= PIN_E;

DelayMS(2); // 2 ms
}

void hd44780_Init(void)
{
// Make sure that the pins are set for GPIO
PCB_PINSEL1 |= (PCB_PINSEL1_P019_GPIO
| PCB_PINSEL1_P020_GPIO
| PCB_PINSEL1_P021_GPIO
| PCB_PINSEL1_P022_GPIO
| PCB_PINSEL1_P023_GPIO
| PCB_PINSEL1_P018_GPIO
| PCB_PINSEL1_P025_GPIO);

// Set D4, D5, D6, D7, RS, RW, E to output ports
GPIO1_IODIR |= (1 << PIN_D4)
| (1 << PIN_D5)
| (1 << PIN_D6)
| (1 << PIN_D7)
| (1 << PIN_RS)
| (1 << PIN_RW)
| (1 << PIN_E);

// wait for LCD to reset itself
DelayMS(20);

// Set default states
GPIO1_IOCLR |= PIN_RS;
GPIO1_IOCLR |= PIN_RW;
GPIO1_IOCLR |= PIN_E;

// Wait for device to power up
DelayMS(500);

// Start initialisation sequence

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET |= PIN_E;
hd77480_Send_4Bits(0x3);
GPIO1_IOCLR |= PIN_E;
DelayMS(10);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET |= PIN_E;
hd77480_Send_4Bits(0x3);
GPIO1_IOCLR |= PIN_E;
DelayMS(120);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET |= PIN_E;
hd77480_Send_4Bits(0x3);
GPIO1_IOCLR |= PIN_E;
DelayMS(2);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 0
GPIO1_IOSET |= PIN_E;
hd77480_Send_4Bits(0x2); // Set interface to be 4 bits long
GPIO1_IOCLR |= PIN_E;
DelayMS(2);

// Function set (specify the number of lines and character font)
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 0
// 0 0 N F * *
hd44780_SendCommand(HD44780_SETFUNC_4BIT_2LINE_5x8);

// Display OFF
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 1 0 0 0
hd44780_SendCommand(HD44780_DISPOFF);

// Display CLEAR
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 0 0 0 1
hd44780_SendCommand(HD44780_CLEAR_DISPLAY);

// Set Entry Mode
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 0 1 I/D S
hd44780_SendCommand(HD44780_ENTRYMODE_INCR_NOSHIFT);
}

void hd44780_WriteChar(char c)
{
GPIO1_IOSET |= PIN_E; // Set E high
GPIO1_IOSET |= PIN_RS; // Set RS high

hd44780_SendCommand(c); // Write character to ram

DelayUS(50); // Wait 50 microseconds

GPIO1_IOCLR |= PIN_E; // Set E low
GPIO1_IOCLR |= PIN_RS; // Set RS low

DelayUS(50); // Wait 50 microseconds
}

void hd44780_DisplayString(char* str)
{
unsigned int i=0;

while (str[i] != '\0')
{
if (str[i] == '\n')
hd44780_SendCommand(HD44780_MOVE_CURSOR_DOWN); // New line
else
hd44780_WriteChar(str[i]);

i++;
}
}
*********** END 44780.c ********************************

An Engineer's Guide to the LPC2100 Series

I see a couple problems right off the bat.
1) You shouldn't be using |= with _IOSET and _IOCLR. These need to be a
straight assignment. So GPIO1_IOCLR = PIN_E;

2) This code:

void hd77480_Send_4Bits(unsigned char v)

> {
>
GPIO1_IOCLR |= ( PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 );
>
GPIO1_IOSET |= (v << 22);
>
}
>

is flawed. You have the pins defined as

PIN_D4 = 0x00400000, // 1.22 Data 4

PIN_D5 = 0x00800000, // 1.23 Data 5

PIN_D6 = 0x20000000, // 1.18 Data 6 (1.24 is used on the Olimex H2148)

PIN_D7 = 0x02000000 // 1.25 Data 7
Yet, you're shifting by 22. That would work if your pins were 1.22. 1.23,
1.24 and 1.25. But 1.18 is biting you here. It's ALWAYS zero. You need to
explicitly assign the bits

if (v & 0x01)
GPIO1_IOSET = PIN_D4;
if (v & 0x02)
GPIO1_IOSET = PIN_D5;
if (v & 0x04)
GPIO1_IOSET = PIN_D6;
if (v & 0x08)
GPIO1_IOSET = PIN_D7;

A cuter way that uses a few more bytes is to define an array:

unsigned int foo [16] = {0, PIN_D4, PIN_D4 | PIN_D5, PIN_D4 | PIN_D6, etc};

so that you have all 16 combinations. Then you can say GPIO1_IOSET = foo
[v]; This would be a very quick table lookup, but it does use 64 bytes.

There may be other problems, but I'd resolve these first.

--jc

On Sat, Oct 4, 2008 at 6:36 PM, Kevin Townsend wrote:

> I've spent the last couple day trying to get a 20x4 character HD44780
> LCD working with my Olimex H2148, and have poured over at least 5
> different examples (including the one in the files section here)
> trying to put together a basic class to work with 44870 LCD.
>
> I'm almost certain I have the board wired up properly (including &
> 10K resistor for contrast on pin 3), and I've read through the entire
> Hitachi datasheet and double-checked my command codes, comparing them
> with other people's examples, but whatever I feed the board it
> doesn't seem to do anything. Line 1 and 3 have solid blocks, and
> line 2 and 4 have nothing.
>
> It must be something with the way the commands are sent, but I don't
> see it myself. If anyone has any experience, I'd certainly
> appreciate another set of eyes and someone else's experience. My
> guess is I screwed something up with either 'hd77480_Send_4Bits'
> or 'hd77480_SendCommand' with the 4-bit business..
>
> NOTE: The code below uses JCWren's (excellent) lpc210x.h, which isn't
> included below, and the delay.h file from the lpc2000 group Files
> section.
>
> Example:
> --------
> hd44780_Init();
> hd44780_SendCommand(HD44780_DISPON_CURSBLINKING);
> hd44780_SendCommand(HD44780_CLEAR_DISPLAY);
> hd44780_DisplayString("Test Test\n");
> hd44780_SendCommand(HD44780_MOVE_CURSOR_DOWN);
> hd44780_DisplayString("Test Test\n");
>
> *********** START 44780.h ******************************
> typedef enum
> {
> PIN_RS = 0x00080000, // 1.19 Register Select
> PIN_RW = 0x00100000, // 1.20 Read/Write
> PIN_E = 0x00200000, // 1.21 Enable
> PIN_D4 = 0x00400000, // 1.22 Data 4
> PIN_D5 = 0x00800000, // 1.23 Data 5
> PIN_D6 = 0x20000000, // 1.18 Data 6 (1.24 is used on the
> Olimex H2148)
> PIN_D7 = 0x02000000 // 1.25 Data 7
> }
> hd44780_Pins_t;
>
> typedef enum
> {
> HD44780_CLEAR_DISPLAY = 0x01, // Clear LCD
> Display 1.52 mS
> HD44780_HOME = 0x02, // Move the cursor to
> the home position 1.52 mS
> HD44780_DISPON = 0x0C, // Turn display on
> with no cursor and no blink 37 S
> HD44780_DISPON_CURSUNDERNEATH = 0x0E, // Turn display on,
> with cursor under 37 S
> HD44780_DISPON_CURSBLINKING = 0x0F, // Turn display on,
> with blinking 37 S
> HD44780_DISPOFF = 0x08, // Turn display
> off 37 S
> HD44780_ENTRYMODE_INCR_NOSHIFT = 0x06, // Auto increment
> cursor position, no shift 37 S (Default entry mode)
> HD44780_ENTRYMODE_INCR_SHIFT = 0x07, // Auto increment
> cursor position, shift text 37 S
> HD44780_ENTRYMODE_DECR_NOSHIFT = 0x04, // Auto decrement
> cursor position, no shift 37 S
> HD44780_ENTRYMODE_DECR_SHIFT = 0x05, // Auto decrement
> cursor position, shift text 37 S
> HD44780_MOVE_CURSOR_RIGHT = 0x14, // Shift cursor one
> character to the right 37 S
> HD44780_MOVE_CURSOR_LEFT = 0x10, // Shift cursor one
> character to the left 37 S
> HD44780_MOVE_CURSOR_UP = 0x80, // Shift cursor up
> one character 37 S
> HD44780_MOVE_CURSOR_DOWN = 0xC0, // Shift cursor down
> one character 37 S
> HD44780_SHIFT_TEXT_RIGHT = 0x1C, // Shift text one
> space to the right 37 S
> HD44780_SHIFT_TEXT_LEFT = 0x18, // Shift text one
> space to the left 37 S
> HD44780_SETFUNC_8BIT_2LINE_5x8 = 0x38, // 8 bit interface, 2
> line display, 5x8 pix chars 37 S
> HD44780_SETFUNC_8BIT_1LINE_5x8 = 0x30, // 8 bit interface, 1
> line display, 5x8 pix chars 37 S
> HD44780_SETFUNC_4BIT_2LINE_5x8 = 0x28, // 4 bit interface, 2
> line display, 5x8 pix chars 37 S
> HD44780_SETFUNC_4BIT_1LINE_5x8 = 0x20, // 4 bit interface, 1
> line display, 5x8 pix chars 37 S
> HD44780_BUSY = 0x80, // Check if the
> controller is busy (1) or not (0)
> HD44780_LINE2 = 0x40, // LCD display
> address offset for line 2 (20x4)
> HD44780_LINE3 = 0x14, // LCD display
> address offset for line 3 (20x4)
> HD44780_LINE4 = 0x54 // LCD display
> address offset for line 4 (20x4)
> }
> hd44780_Commands_t;
>
> // Method Prototypes
> void hd77480_Send_4Bits(unsigned char v);
> void hd44780_SendCommand(hd44780_Commands_t command);
> void hd44780_Init(void);
> void hd44780_DisplayString(char* str);
> *********** END 44780.h ********************************
>
> *********** START 44780.c ******************************
> #include "lpc210x.h"
> #include "44780.h"
> #include "delay.h"
>
> void hd77480_Send_4Bits(unsigned char v)
> {
> GPIO1_IOCLR |= ( PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 );
> GPIO1_IOSET |= (v << 22);
> }
>
> void hd44780_SendCommand(hd44780_Commands_t command)
> {
> // Make sure that D4, D5, D6, D7, RS, RW, E are set to output ports
> GPIO1_IODIR |= (1 << PIN_D4)
> | (1 << PIN_D5)
> | (1 << PIN_D6)
> | (1 << PIN_D7)
> | (1 << PIN_RS)
> | (1 << PIN_RW)
> | (1 << PIN_E);
>
> // Write higher order bits
> GPIO1_IOSET |= PIN_E;
> hd77480_Send_4Bits((command>>4) & 0x0F);
> GPIO1_IOCLR |= PIN_E;
>
> DelayMS(2); // 2 ms
>
> // Write lower order bits
> GPIO1_IOSET |= PIN_E;
> hd77480_Send_4Bits((command) & 0x0F);
> GPIO1_IOCLR |= PIN_E;
>
> DelayMS(2); // 2 ms
> }
>
> void hd44780_Init(void)
> {
> // Make sure that the pins are set for GPIO
> PCB_PINSEL1 |= (PCB_PINSEL1_P019_GPIO
> | PCB_PINSEL1_P020_GPIO
> | PCB_PINSEL1_P021_GPIO
> | PCB_PINSEL1_P022_GPIO
> | PCB_PINSEL1_P023_GPIO
> | PCB_PINSEL1_P018_GPIO
> | PCB_PINSEL1_P025_GPIO);
>
> // Set D4, D5, D6, D7, RS, RW, E to output ports
> GPIO1_IODIR |= (1 << PIN_D4)
> | (1 << PIN_D5)
> | (1 << PIN_D6)
> | (1 << PIN_D7)
> | (1 << PIN_RS)
> | (1 << PIN_RW)
> | (1 << PIN_E);
>
> // wait for LCD to reset itself
> DelayMS(20);
>
> // Set default states
> GPIO1_IOCLR |= PIN_RS;
> GPIO1_IOCLR |= PIN_RW;
> GPIO1_IOCLR |= PIN_E;
>
> // Wait for device to power up
> DelayMS(500);
>
> // Start initialisation sequence
>
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 1 1
> GPIO1_IOSET |= PIN_E;
> hd77480_Send_4Bits(0x3);
> GPIO1_IOCLR |= PIN_E;
> DelayMS(10);
>
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 1 1
> GPIO1_IOSET |= PIN_E;
> hd77480_Send_4Bits(0x3);
> GPIO1_IOCLR |= PIN_E;
> DelayMS(120);
>
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 1 1
> GPIO1_IOSET |= PIN_E;
> hd77480_Send_4Bits(0x3);
> GPIO1_IOCLR |= PIN_E;
> DelayMS(2);
>
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 1 0
> GPIO1_IOSET |= PIN_E;
> hd77480_Send_4Bits(0x2); // Set interface to be 4 bits long
> GPIO1_IOCLR |= PIN_E;
> DelayMS(2);
>
> // Function set (specify the number of lines and character font)
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 1 0
> // 0 0 N F * *
> hd44780_SendCommand(HD44780_SETFUNC_4BIT_2LINE_5x8);
>
> // Display OFF
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 0 0
> // 0 0 1 0 0 0
> hd44780_SendCommand(HD44780_DISPOFF);
>
> // Display CLEAR
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 0 0
> // 0 0 0 0 0 1
> hd44780_SendCommand(HD44780_CLEAR_DISPLAY);
>
> // Set Entry Mode
> // RS RW DB7 DB6 DB5 DB4
> // 0 0 0 0 0 0
> // 0 0 0 1 I/D S
> hd44780_SendCommand(HD44780_ENTRYMODE_INCR_NOSHIFT);
> }
>
> void hd44780_WriteChar(char c)
> {
> GPIO1_IOSET |= PIN_E; // Set E high
> GPIO1_IOSET |= PIN_RS; // Set RS high
>
> hd44780_SendCommand(c); // Write character to ram
>
> DelayUS(50); // Wait 50 microseconds
>
> GPIO1_IOCLR |= PIN_E; // Set E low
> GPIO1_IOCLR |= PIN_RS; // Set RS low
>
> DelayUS(50); // Wait 50 microseconds
> }
>
> void hd44780_DisplayString(char* str)
> {
> unsigned int i=0;
>
> while (str[i] != '\0')
> {
> if (str[i] == '\n')
> hd44780_SendCommand(HD44780_MOVE_CURSOR_DOWN); // New line
> else
> hd44780_WriteChar(str[i]);
>
> i++;
> }
> }
> *********** END 44780.c ********************************
>
>
>

Ooops. And there's more :)

> GPIO1_IODIR |= (1 << PIN_D4)

| (1 << PIN_D5)

| (1 << PIN_D6)

| (1 << PIN_D7)

| (1 << PIN_RS)

| (1 << PIN_RW)

| (1 << PIN_E);
You're shifting 1 by 0x00400000 (PIN_D4), which I'm pretty sure is going to
be more than 32 :) You need to set these as GPIO1_IODIR = (PIN_D4 | PIN_D5,
etc);

Once you get this working, you should be able to remove the timing delays in
your send command code, and poll D7. Then the only fixed delays you need
are in the initialization code.

--jc

Thanks (A LOT) for the reply ... I appreciate the effort. Alas,
still no luck. I've made the mentionned changes (stupid oversights
on my part, being quite new to ARM development), but still don't seem
to get any visible response back. How would you normally go about
debugging this yourself, of out curiousity?

Kevin

void hd77480_Send_4Bits(unsigned char v)
{
// Clear all bits by default
GPIO1_IOCLR = ( PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 );

// Set individual bits
if (v & 0x01)
GPIO1_IOSET = PIN_D4;
if (v & 0x02)
GPIO1_IOSET = PIN_D5;
if (v & 0x04)
GPIO1_IOSET = PIN_D6;
if (v & 0x08)
GPIO1_IOSET = PIN_D7;
}

void hd44780_SendCommand(hd44780_Commands_t command)
{
// Make sure that D4, D5, D6, D7, RS, RW, E are set to output ports
GPIO1_IODIR |= (PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 | PIN_RS | PIN_RW
| PIN_E);

// Write higher order bits
GPIO1_IOSET = PIN_E;
hd77480_Send_4Bits((command>>4) & 0x0F);
GPIO1_IOCLR = PIN_E;

DelayMS(2); // 2 ms

// Write lower order bits
GPIO1_IOSET = PIN_E;
hd77480_Send_4Bits((command) & 0x0F);
GPIO1_IOCLR |= PIN_E;

DelayMS(2); // 2 ms
}

void hd44780_Init(void)
{
// Make sure that the pins are set for GPIO
PCB_PINSEL1 |= (PCB_PINSEL1_P019_GPIO
| PCB_PINSEL1_P020_GPIO
| PCB_PINSEL1_P021_GPIO
| PCB_PINSEL1_P022_GPIO
| PCB_PINSEL1_P023_GPIO
| PCB_PINSEL1_P018_GPIO
| PCB_PINSEL1_P025_GPIO);

// Set D4, D5, D6, D7, RS, RW, E to output ports
GPIO1_IODIR |= (PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 | PIN_RS | PIN_RW
| PIN_E);

// wait for LCD to reset itself
DelayMS(20);

// Set default states
GPIO1_IOCLR = PIN_RS;
GPIO1_IOCLR = PIN_RW;
GPIO1_IOCLR = PIN_E;

// Wait for device to power up
DelayMS(500);

// Start initialisation sequence

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET = PIN_E;
hd77480_Send_4Bits(0x3);
GPIO1_IOCLR = PIN_E;
DelayMS(10);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET = PIN_E;
hd77480_Send_4Bits(0x3);
GPIO1_IOCLR = PIN_E;
DelayMS(120);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET = PIN_E;
hd77480_Send_4Bits(0x3);
GPIO1_IOCLR = PIN_E;
DelayMS(2);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 0
GPIO1_IOSET = PIN_E;
hd77480_Send_4Bits(0x2); // Set interface to be 4 bits long
GPIO1_IOCLR = PIN_E;
DelayMS(2);

// Function set (specify the number of lines and character font)
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 0
// 0 0 N F * *
hd44780_SendCommand(HD44780_SETFUNC_4BIT_2LINE_5x8);

// Display OFF
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 1 0 0 0
hd44780_SendCommand(HD44780_DISPOFF);

// Display CLEAR
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 0 0 0 1
hd44780_SendCommand(HD44780_CLEAR_DISPLAY);

// Set Entry Mode
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 0 1 I/D S
hd44780_SendCommand(HD44780_ENTRYMODE_INCR_NOSHIFT);
}

I've posted some LCD code that works under FreeRTOS at http://jcwren.com/arm
I'm not sure your settling times after setting the data then strobing E are
within spec. On a 48Mhz LPC-2148 with partial MAM, I found I had to insert
some delays to meet the specs on the LCD. The LCD code is setup for an 8
bit interface, and uses the D7 polling to determine command completion. The
LCD model is a CrystalFontz CFAH1602Z-YYH-ET. There's a nifty little
negative voltage charge pump circuit that uses two diodes and a PWM channel
to control the contrast.

--jc

You've still got that |= action going on. Change those to ='s. And check
the followup about additional delays for data line and control line settling
times.
Truth be told, in a case like this, experience. I've been using HD44780
LCDs for something like 20 years, on 8051's, PICs, AVRs, ARMs, Z80s, and
1802's. I just kinda know their quirks at this point. But when this sort
of problem does hit, my best friend is a logic analyzer. At work I have
access to expensive test equipment. At home, I have a HP 1630G I picked up
off of eBay for $100 or so. I also have a USBee ZX 8 channel logic
analyzer, left over from a company that folded. The software is sorta
funky, but it's much faster than the 1630G.

A 'scope helps a lot, but you really want to see all the control lines and
examine the relationships between them and the data sheets.

--jc

--- In l..., "J.C. Wren" wrote:
>
> I've posted some LCD code that works under FreeRTOS at
http://jcwren.com/arm

Thanks ... I'll take a look at it now.

Kevin.
The first step perhaps could be - power input and contrast setting.

(1) Do u see the dots turning darker with contrast adjustment?

We use O'scope to monitor e-signal. Read, write Chip selects.

While we were working on LPC 2xxx for the first time:

Some times the port pins dp not behave as expected.

Now: We toggle every bit and monitor to ensure that all the port bits behave right. This is after we struggled to make Graphic display interfacing. Initially we believed that the port pins would behave normally.

Some port pins needed pull-up which we failed to take note of.

When we follow these steps our dev process is flowing free and smooth.

We used to get in the market some 25 / 30 years ago a product called pulser / probe.

This can apply a pulse where the probe is placed .

Also a re-triggerable monostable multivibrator can substitute to a small extent, an oscilloscope. It can be built in one hour max. With this, we can monitor the pulses.

You might find the ccts in archives of electronic magazines.

Natarajan
--- On Sun, 10/5/08, Kevin Townsend wrote:

From: Kevin Townsend
Subject: [lpc2000] Re: HD44780 Initialisation (20x4 display in 4-bit mode)
To: l...
Date: Sunday, October 5, 2008, 4:57 AM

Thanks (A LOT) for the reply ... I appreciate the effort. Alas,
still no luck. I've made the mentionned changes (stupid oversights
on my part, being quite new to ARM development) , but still don't seem
to get any visible response back. How would you normally go about
debugging this yourself, of out curiousity?

Kevin

void hd77480_Send_ 4Bits(unsigned char v)
{
// Clear all bits by default
GPIO1_IOCLR = ( PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 );

// Set individual bits
if (v & 0x01)
GPIO1_IOSET = PIN_D4;
if (v & 0x02)
GPIO1_IOSET = PIN_D5;
if (v & 0x04)
GPIO1_IOSET = PIN_D6;
if (v & 0x08)
GPIO1_IOSET = PIN_D7;
}

void hd44780_SendCommand (hd44780_ Commands_ t command)
{
// Make sure that D4, D5, D6, D7, RS, RW, E are set to output ports
GPIO1_IODIR |= (PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 | PIN_RS | PIN_RW
| PIN_E);

// Write higher order bits
GPIO1_IOSET = PIN_E;
hd77480_Send_ 4Bits((command> >4) & 0x0F);
GPIO1_IOCLR = PIN_E;

DelayMS(2); // 2 ms

// Write lower order bits
GPIO1_IOSET = PIN_E;
hd77480_Send_ 4Bits((command) & 0x0F);
GPIO1_IOCLR |= PIN_E;

DelayMS(2); // 2 ms
}

void hd44780_Init( void)
{
// Make sure that the pins are set for GPIO
PCB_PINSEL1 |= (PCB_PINSEL1_ P019_GPIO
| PCB_PINSEL1_ P020_GPIO
| PCB_PINSEL1_ P021_GPIO
| PCB_PINSEL1_ P022_GPIO
| PCB_PINSEL1_ P023_GPIO
| PCB_PINSEL1_ P018_GPIO
| PCB_PINSEL1_ P025_GPIO) ;

// Set D4, D5, D6, D7, RS, RW, E to output ports
GPIO1_IODIR |= (PIN_D4 | PIN_D5 | PIN_D6 | PIN_D7 | PIN_RS | PIN_RW
| PIN_E);

// wait for LCD to reset itself
DelayMS(20);

// Set default states
GPIO1_IOCLR = PIN_RS;
GPIO1_IOCLR = PIN_RW;
GPIO1_IOCLR = PIN_E;

// Wait for device to power up
DelayMS(500) ;

// Start initialisation sequence

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET = PIN_E;
hd77480_Send_ 4Bits(0x3) ;
GPIO1_IOCLR = PIN_E;
DelayMS(10);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET = PIN_E;
hd77480_Send_ 4Bits(0x3) ;
GPIO1_IOCLR = PIN_E;
DelayMS(120) ;

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 1
GPIO1_IOSET = PIN_E;
hd77480_Send_ 4Bits(0x3) ;
GPIO1_IOCLR = PIN_E;
DelayMS(2);

// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 0
GPIO1_IOSET = PIN_E;
hd77480_Send_ 4Bits(0x2) ; // Set interface to be 4 bits long
GPIO1_IOCLR = PIN_E;
DelayMS(2);

// Function set (specify the number of lines and character font)
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 1 0
// 0 0 N F * *
hd44780_SendCommand (HD44780_ SETFUNC_4BIT_ 2LINE_5x8) ;

// Display OFF
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 1 0 0 0
hd44780_SendCommand (HD44780_ DISPOFF);

// Display CLEAR
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 0 0 0 1
hd44780_SendCommand (HD44780_ CLEAR_DISPLAY) ;

// Set Entry Mode
// RS RW DB7 DB6 DB5 DB4
// 0 0 0 0 0 0
// 0 0 0 1 I/D S
hd44780_SendCommand (HD44780_ ENTRYMODE_ INCR_NOSHIFT) ;
}






I was wondering if someone could confirm for me if it was normal that
when I add power to my 20x4 display, and connect the third pin to a
10K resistor on pin 1 and 2 (for contrast), that I have two lines of
solid blocks and two empty lines. I've attached a photo for reference
sake:

http://img503.imageshack.us/my.php?image=hd44780defaultstatevy5.jpg

Also, I hooked up a cheapo ebay oscilloscope that I bought, and
noticed when monitoring the different pins that the 4 data bits seems
to work (I see activity going up and down), but I don't seem to get
any response out of the E pin when it should be bouncing up and down
as I enter the following methods:

static inline void lcdEnableHigh()
{
GPIO1_IOSET = PIN_E;
}

static inline void lcdEnableLow()
{
GPIO1_IOCLR = PIN_E;
}

Admittedly, I'm completely new to all this, but shouldn't the IOSET
and IOCLR cause the pin to go up and down on the 'scope? I'm sure it
it connected to the probe properly, and the connection is fine between
the 2148 and the LCD board ... any ideas what might be explain this?
I've attached another image to show what I mean, with the breakpoint
on the left (after I've entered the method a few times):

http://img117.imageshack.us/my.php?image=escopedda7.jpg

I appreciate any feedback anyone can offer.
>I was wondering if someone could confirm for me if it was normal that
> when I add power to my 20x4 display, and connect the third pin to a
> 10K resistor on pin 1 and 2 (for contrast), that I have two lines of
> solid blocks and two empty lines. I've attached a photo for reference
> sake:
>
> http://img503.imageshack.us/my.php?image=hd44780defaultstatevy5.jpg

Yes it's normal. Until the LCD is initialized that's what you'll see.

GB

Memfault Beyond the Launch