My6502 (part seven) – LCD screen

Now I have a good few select lines available for peripherals, I can proceed with adding a few. I’ll start with an LCD screen – the common-as-muck HD44780.


<old git mode> The first time I bought one of these was for a project in the early nineties. It could display two lines of sixteen characters, had no backlight … and cost over forty pounds! These days you can get lovely and clear ones, in any combination of background and foreground colour you like, with backlight, for just a tenth of that price. I buy them by the dozen. Kids today, don’t know they’re born. Etc. </old git mode>

They’re a great display for all kinds of projects – you can send them data as slowly as you like, you only need to send them ASCII data (don’t need to worry about rasterisation or graphics code) and you only need to send them data when the display contents need to change – the rest of the time they look after themselves. They’re extremely common in Arduino and Raspberry Pi projects.

For me, it’ll be great to have one of these attached to my computer for debugging, status information, RAM testing and so on.

Interfacing with a microcontroller

hitachi_pinoutsThe screen is controlled with fourteen pins – plus an extra two if it has a backlight. Pins 1 and 2 are the 0v and 5v supply. Pin 3 is a contrast control – it should be connected to the wiper pin of a 10K linear preset (with the other two legs going between 0v and 5v). The remaining pins are for interfacing with the controller.

The most common configuration you see them in Arduino projects is in four-bit mode – so called because each byte of data is transmitted to it in two halves. Such configurations also tend to be “write-only” – that is, the circuits are built so that you can send data to them, but they rarely cater for reading anything back.

The reasoning in these situations is sound: on a small microcontroller like an Arduino, digital I/O pins are at a premium. If you can save a few at the cost of a slower data rate, then it’s worth it.

In my project however, these limitations do not apply. So I’m going to connect it directly to the CPU in full eight-bit mode, with full write and read ability.

Full credit for the wiring and the code examples should go to Chris Ward, who wrote this rather excellent page on which my circuit is based. Well … perhaps ‘based’ isn’t strong enough. ‘Direct copy’ would be more accurate!

Here’s Chris’ circuit, to which I’ve added some pin numbers and labelling, just to make things easier for me:


Worthy of note in this circuit:

  • /SELECT is one of the select lines I implemented in part six.
  • The RS pin is register select – as discussed in part four, I just connect this to A0. Then, accessing the correct register is simply a case of using an odd or even numbered addresses within this device’s range.
  • The R/W pin is connected to the equivalent on the bus, so that the CPU can read-from or write-to the display.
  • The logic feeding the enable (“E”) pin is activated based on the state of the select line and the clock signal (phi). The left and right NAND gates in the circuit are actually being used as NOT gates by having both their input pins connected together. This is done because the 74LS00 has four NAND gates in it, so it’s more cost efficient to just use one IC, rather than one IC for NAND gates and one for NOT gates.
  • The rightmost NAND gate is present because the enable-line on these displays is active-high. It’s more common for devices to be active-low.


After a brief test on breadboard to verify it worked, the circuit quickly moved on to PCB:

The row of sixteen pads at the top of the circuit are for the LCD screen. I’ve used Dupont jumper wires (available from eBay – if you haven’t already, I recommend you buy a truckload of these for your breadboarded prototypes) to connect the board to the screen.

In the lower-right corner, I’ve put a 2×5 array of header pins for a jumper as selector. I’ve decided that all the pins after D7 are going to be device select lines, and to give me the flexibility to change which line will select which device, I’ve put header pins in so that a jumper can select which device line will select the LCD.

Control code

I’m not going to embed the source code in the body of this blog post, because there’s just too much of it! Instead, here it is for download. It’s overly commented, because that’s how I like to work when I’m writing experimental code.

Click to download firmware01 source-code as a ZIP (2.5KBytes)

Now that I have working RAM (see part five) I can make use of JSR and zeropage and the stack, so I can implement the controlling code as subroutines. Also note that this code also reads back from the screen – it does it to check that the screen isn’t busy before sending it any data (which means we can access the screen as fast as we like, and not worry about introducing arbitrary delays) and we can read the current cursor position, to implement “wrapping”.



The white blob in the lower-left corner of the screen isn’t any fancy graphics – it’s some sort of manufacturing error. I use this screen for prototyping work, because I wouldn’t fit it into anything permanent. This screen and I have had some Good Times together!

Lastly …

Now’s probably a good time to mention that I’ve upped the clock speed, from 5Hz to about 50kHz. I’m quite giddy with exhilaration, I don’t mind telling you! :)

I’ve done this because now my code is getting bigger, I’m getting bored of watching the address lines tick over as the screen sloooooooooowly prints text. This increased speed means that my address display is of little use, as anything above about 10Hz is too fast to read. I’ll keep it connected for a bit in case I get any crashes … but I hope to remove it soon.

[Part 0] [Part 1] [Part 2] [Part 3] [Part 4] [Part 5] [Part 6]