Frank's Random Wanderings

Atmel Xmega HD44780 LCD Support

Over on AVRfreaks there are a lot of code snippets describing how to connect an AVR to a character LCD display, such as a standard HD44780-compatible display. But not a lot talking about how to do the same using an Xmega.

For a small project I’d been working on, I had an LCD display connected to an Xmega16 using the 8-bit parallel mode. As anybody who’s tried to migrate from an older AVR to an Xmega knows, the I/O port operations are slightly different, meaning that code written for an AVR won’t even compile using WinAVR (AVR GCC) for the Xmega. After a couple of aborted attempts, I decided to modify some existing AVR code LCD routines to support the Xmega.

4 vs 8 Bit Mode

The code given below is specifically for the 8-bit mode of the HD44780-compatible display. It does not support 4-bit mode. Not that there’s a lot of difference between the two modes, but of course in 4-bit mode every byte being sent to the display requires writing two 4-bit nibbles. So if you need to support 4-bit mode, you’ll need to edit this code slightly to add that in.

Delays vs Busy Flag

Ah, the eternal debate. This code does simple delays. It does not read the LCD busy flag. If you care to know more, read on.

When you write to the LCD display, it’ll be busy for some period of time before you can write again. So how to know when it’s safe to write again (for example to write the next character you want to be displayed)? You have two basic options.

Option 1 is to poll the busy flag of the LCD. However, this requires the ability to read the LCD. After all, you want to read its busy flag. Which means hardware. At the very least the R/W pin of the LCD must be connected to the Xmega so the Xmega can read from the device. Also, voltage levels may be a consideration. The Xmega is a 3.3V device that is not 5V tolerant. Which means that if you’re using a 5V powered LCD, which many of them are, you’re going to need some hardware to perform voltage-level translation on the LCD data bus. For example a 74xx245 IC. Otherwise the LCD will drive the data bus to 5V levels, which can damage the Xmega.

If being able to update the LCD display at the absolute fastest possible rate is important to you, this is the way to do it. By polling that busy flag, the moment the LCD is ready for its next write, you’ll know about it and you can write. The vast majority of applications don’t require this very fast LCD update rate, and so the extra difficulties and costs involved with supporting reading from the LCD are simply not worth it.

Option 2 is a simple delay. You write, then you delay for a while before you write again. The LCD module datasheets generally provide estimates on how long the delays need to be, but most people make their delays much much longer simply to be safe, and to help ensure compatibility with a variety of different LCD module manufacturers.

What you do while you’re delaying is up to you. This code simply waits, twiddling its thumbs. More complex code can set timers, return to an ongoing process and then return back here to write again when the timer expires, etc. But this code implementation just waits. It’s extremely simple. In the case of using a slow processor it’s a moot point anyway, because the delay may only work out to a relatively few CPU cycles. For hardware, simply tie the LCD module’s R/W pin low (to GND) so that the LCD module is told it’s always being written to. That’s it.

And Now, The Code…

Given below are three code sections. The first is the LCD routines. The second is a little .h file which you can include in your application to easily access the LCD routines. And the third is some example code on how to use the LCD routines.

First up are the LCD handling routines; lcd.c

Make sure you change the #define’s at the top of the code to reflect the AVR ports your LCD is connected to.

Then this is a simple lcd.h file you can create and include into your main application file.

Here are some code snippets on how to use the functions.

For the code snippets, the first couple should be pretty self-evident, where the initialisation of the LCD takes place, plus an example of how to clear the whole display in a single function call. The third snippet shows how to display a fixed string on the first line of the display. Note it’s using the lcd_write_string_p() function, with the trailing _p indicating it will read from program memory (flash). So the string is located in program memory by use of the PSTR() macro.

The fourth snippet takes this a small step further. It displays a string on the second line of the LCD display (assuming the LCD physically has two lines, of course). It uses the sprintf_P() function, which is a variant of the normal sprintf() function, to read from a fixed format string in program memory and write into a string in SRAM. Then the function lcd_write_string_0() is used to write that SRAM string’s contents to the LCD. The _0 at the end of the function name indicates it expects a SRAM string will a normal null-termination at the end. This helps distinguish it from the lcd_write_string() function, whose name is slightly misleading because it actually expects a parameter telling it how many characters to write. This code snippet shows just one possible way of how to display a variable’s value on the LCD display.

Hopefully this code proves useful. I’m using it on a small project and it works just fine.

3 thoughts on “Atmel Xmega HD44780 LCD Support

  1. Sudhir Owthar

    Hi Frank

    I am trying to interface an HD44780 LCD to an XMega16 MCU. I Have followed all your instructions on this page but nothing is being displayed on the LCD. I am using an STK600 development board with DC power and USB for programming. I gave connected the LCD to the port pins on the development board and i am using a separate 5V regulated power supply for the LCD power. I have grounded the RW pin as per your instructions. Port A is being used for DATA and PortB as the control. I compiled the program using AVR-GCC on the following IDE’s: AVR Studio 5.0 and AVR Studio 4.18. The program builds and compiled with o errors. I used all of your code snippets to test the LCD but nothing is being written.

    Please help me with this problem. I do not understand what I am doing wrong. Your help will be greatly appreciated.

    Thank you for a great webpage and all your time and effort.

    Sudhir owthar

  2. Stuart Goranson

    Hello Frank,

    I find this code very useful in a project of my own that I am working on. The one thing I am having troubles with is the correct code for displaying a graph like scene on the HD44780 LCD. If you follow this link (http://www.quinapalus.com/hd44780udg.html) I am looking for something like what is displayed in Row 6 Columns 1-5. I have some other pre-made code a libraries that I am trying to manipulate. I am using the HSC12-USB Dragonboard with C Code and using Codewarrior. If you have any ideas or other code samples you thing could help me out I would greatly appreciate it.

    Thanks for your time and efforts,

    Stuart Goranson

Leave a Reply

Your email address will not be published. Required fields are marked *