Introduction
I recently upgraded from a BL1800 Jackrabbit system. To get networked I got
the Rabbit Ethernet Connection kit, featuring the newer and more powerful
RCM3720 Core. The old BL1800
(picture) had been running with a serialized 2x16 LCD display
BPI-216
from Parallax, which needed only 3 wires in total. When I could not find
one quickly for the RCM3720, I looked at the many parallel port LCD displays.
Well, I had ports enough on the RCM3720, so I got a HD44780-compatible type.
It turned out that the parallel-port LCD was much more difficult to connect
and to program, googling around didn't help much. When I worked out the
correct wiring and programming, I thought I share the knowledge to save
you trouble and time... This guide has been developed with a RCM3720
RabbitCore Ethernet Development kit using the supplied development board
and a Sunlike SC1602BSLB 2x16 LCD display.
The 'schematic' part: Wiring the display in 8-bit mode
According to the specs, HD44780-compatible displays can be connected in 8-bit and 4-bit mode. While the 4-bit mode cuts down on valuable in/out pins, it complicates programming. So lets start with all 8 data lines connected and see about the 4-bit shortcut later on. In addition to the 8 data lines, we need 3 data control lines plus the obligatory 'ground' VDD and '+5V' VSS lines with a contrast regulating V0 line. The V0 connection can simply be 'grounded' to VDD. This will set the display to full contrast and saves a 10kOhm potentiometer. I selected the free Port A for the 8 data lines. The control lines I put on 3 of the remaining free pins of port B. Port B is already partially used by the development board and the internal clocks.
The 'soldering' part: Physical installation on the development board
With 14 lines to wire, the Sunlike SC1602BSLB display conveniently provides 2 rows of 7 soldering holes in a raster to fit a standard 14 pin wiring terminal. We have only limited breadboard space on the Rabbit development board, so I placed a female terminal close to the 40-pin RabbitCore breakout terminal while soldering the male terminal to the display itself. I placed a second 'dummy' terminal at the other end of the display using the holes for the external backlight connections.
The 'Testing' part: Learning how to programm the parallel LCD display
Once we power-up the development board, the LCD display should already give us a sign of live by showing a row of black squares in the upper line. Very good! This is normal for a uninitialized display. Let's create a first test program in Dymanic 'C' named Rabbit_RCM3720_to_HD44780LCD_example1.c, simplified as much as possible. We are trying to display two characters 'Hi', using the code below.
/***************************************************************************/
/* Rabbit_RCM3720_to_HD44780LCD_example1.c http://www.frank4dd.com/howto */
/* */
/* Written for a 16x2 HD44780 compatible LCD display on a Rabbit RCM3720 */
/* Ethernet Development Kit. Connected in 8bit mode with datalines going */
/* to port A while RS, E and RW are connected to Port B on B2, B3 and B4. */
/* Written and tested under Dynamic C Version 9.21 Frank4dd, @2008 */
/***************************************************************************/
#class auto
#define RSADDR 2 // Register Select port B-2
#define ENADDR 3 // Enable signal port B-3
#define RWADDR 4 // Read/Write signal port B-4
void MsDelay(unsigned long milliSeconds) {
unsigned long ul0;
ul0 = MS_TIMER; // get the current timer value
while(MS_TIMER < ul0 + milliSeconds);
}
LcdWrite(int mode, char hex) {
BitWrPortI(PBDR, &PBDRShadow, mode, RSADDR); // Choose command or data mode
BitWrPortI(PBDR, &PBDRShadow, 0, RWADDR); // Set LCD write mode
WrPortI(PADR, &PADRShadow, hex); // Set LCD command on port A
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data
MsDelay(1); // Wait 1 ms for LCD to receive
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission
MsDelay(1); // Wait 1 ms until next write
}
void main() {
brdInit(); // Enable development board
WrPortI(SPCR, NULL, 0x84); // Set Rabbit port A to output
WrPortI(PADR, &PADRShadow, 0x0); // Zero out all bits of port A
LcdWrite(0, 0x30);
MsDelay(4);
LcdWrite(0, 0x30);
LcdWrite(0, 0x30);
LcdWrite(0, 0x38); // Send "8bit, 2 lines, 5x7 font"
LcdWrite(0, 0x06); // Send "entry mode, increm. move"
LcdWrite(0, 0x10); // Send "display and cursor shift"
LcdWrite(0, 0x0E); // Send "display and cursor on"
LcdWrite(0, 0x01); // Send "LCD clear, jump to zero"
LcdWrite(1, 0x48); // Send data 'H'
LcdWrite(1, 0x69); // Send data 'i'
}
After running our test program, we should be greeted by our first two
characters. Now we are ready to run a more advanced example program that adds many
helpful functions to control display and cursor settings:
Rabbit_RCM3720_to_HD44780LCD_example2.c
This program maps ASCII characters to the equivalent of the LCD character map. The LCD character map has some extra symbols not available in the standard ASCII table, like arrows and currency symbols. HD47780 compabtible displays have a second character map that provides additional characters for Japanese Katakana, Hiragana, accent and formula characters. The test program allows addressing both display lines through a easy-to-use LcdWriteStr() function, as the picture to the left demonstrates. From here we return to the question on how to run with only 4 data lines instead of 8.
The '4-bit' part, cutting down on 4 data lines
In 4-bit mode, the data lines 0-3 are unused and we only need to connect data lines 4-7. But laying off half of the data-transmitting workforce comes at a price. Now we need to add code for splitting bytes into bits, plus transmitting each of the "half-bytes" is twice as much work. After adjusting example1 to implement 4bit mode, Rabbit_RCM3720_to_HD44780LCD_example3.c shows the extra overhead required. The extra function LcdInit() is now required to reliably initialize the 4bit mode.
/***************************************************************************/
/* Rabbit_RCM3720_to_HD44780LCD_example3.c http://www.frank4dd.com/howto */
/* */
/* Written for a 16x2 HD44780 compatible LCD display on a Rabbit RCM3720 */
/* Ethernet Development Kit. Connected in 4bit mode with datalines going */
/* to port A-4 to A-7 while RS, E and RW are connected to Port B on B2, B3 */
/* and B4. Written and tested under Dynamic C Version 9.21 Frank4dd, @2008 */
/***************************************************************************/
#class auto
#define RSADDR 2 // Register Select port B-2
#define ENADDR 3 // Enable signal port B-3
#define RWADDR 4 // Read/Write signal port B-4
void MsDelay(unsigned long milliSeconds) {
unsigned long ul0;
ul0 = MS_TIMER; // get the current timer value
while(MS_TIMER < ul0 + milliSeconds);
}
void ByteSplit(char byte, int bit[8]) {
int i, j;
j=0;
for(i=128; i>0; i=i/2) {
if ((byte & i) != 0) bit[j] = 1;
if ((byte & i) == 0) bit[j] = 0;
if (j == 7) break;
else j++;
}
}
LcdInit() {
BitWrPortI(PBDR, &PBDRShadow, 0, RSADDR); // Set command mode
BitWrPortI(PBDR, &PBDRShadow, 0, RWADDR); // Set LCD write mode
BitWrPortI(PADR, &PADRShadow, 1, 4); // Set port A-4
BitWrPortI(PADR, &PADRShadow, 1, 5); // Set port A-5
BitWrPortI(PADR, &PADRShadow, 0, 6); // Set port A-6
BitWrPortI(PADR, &PADRShadow, 0, 7); // Set port A-7
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data upper 4bit
MsDelay(1); // Wait 1 ms for LCD to read
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission upper 4bit
MsDelay(5);
BitWrPortI(PADR, &PADRShadow, 1, 4); // Set port A-4
BitWrPortI(PADR, &PADRShadow, 1, 5); // Set port A-5
BitWrPortI(PADR, &PADRShadow, 0, 6); // Set port A-6
BitWrPortI(PADR, &PADRShadow, 0, 7); // Set port A-7
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data upper 4bit
MsDelay(1); // Wait 1 ms for LCD to read
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission upper 4bit
MsDelay(1);
BitWrPortI(PADR, &PADRShadow, 1, 4); // Set port A-4
BitWrPortI(PADR, &PADRShadow, 1, 5); // Set port A-5
BitWrPortI(PADR, &PADRShadow, 0, 6); // Set port A-6
BitWrPortI(PADR, &PADRShadow, 0, 7); // Set port A-7
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data upper 4bit
MsDelay(1); // Wait 1 ms for LCD to read
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission upper 4bit
MsDelay(1);
BitWrPortI(PADR, &PADRShadow, 0, 4); // Set port A-4
BitWrPortI(PADR, &PADRShadow, 1, 5); // Set port A-5
BitWrPortI(PADR, &PADRShadow, 0, 6); // Set port A-6
BitWrPortI(PADR, &PADRShadow, 0, 7); // Set port A-7
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data upper 4bit
MsDelay(1); // Wait 1 ms for LCD to read
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission upper 4bit
MsDelay(1);
}
LcdWrite(int mode, char hex) {
int bits[8];
// First we split the byte into its bits, then we send the first an second half
ByteSplit(hex, bits);
BitWrPortI(PBDR, &PBDRShadow, mode, RSADDR); // Set command or data mode
BitWrPortI(PBDR, &PBDRShadow, 0, RWADDR); // Set LCD write mode
BitWrPortI(PADR, &PADRShadow, bits[3], 4); // Set port A-4
BitWrPortI(PADR, &PADRShadow, bits[2], 5); // Set port A-5
BitWrPortI(PADR, &PADRShadow, bits[1], 6); // Set port A-6
BitWrPortI(PADR, &PADRShadow, bits[0], 7); // Set port A-7
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data upper 4bit
MsDelay(1); // Wait 1 ms for LCD to read
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission upper 4bit
MsDelay(1);
BitWrPortI(PADR, &PADRShadow, bits[7], 4); // Set port A-4
BitWrPortI(PADR, &PADRShadow, bits[6], 5); // Set port A-5
BitWrPortI(PADR, &PADRShadow, bits[5], 6); // Set port A-6
BitWrPortI(PADR, &PADRShadow, bits[4], 7); // Set port A-7
MsDelay(1);
BitWrPortI(PBDR, &PBDRShadow, 1, ENADDR); // Start sending data lower 4bit
MsDelay(1); // Wait 1 ms for LCD to read
BitWrPortI(PBDR, &PBDRShadow, 0, ENADDR); // Finish transmission lower 4bit
MsDelay(1);
}
void main() {
brdInit(); // Enable development board
WrPortI(SPCR, NULL, 0x84); // Set Rabbit port A to output
WrPortI(PADR, &PADRShadow, 0x0); // Zero out all bits of port A
LcdInit();
LcdWrite(0, 0x28); // Send 4bit, set 2 lines, 5x7 font
LcdWrite(0, 0x06); // Send "Entry mode, increm. move"
LcdWrite(0, 0x10); // Send "display and cursor shift"
LcdWrite(0, 0x0E); // Send "display and cursor on"
LcdWrite(0, 0x01); // Send "LCD clear, jump to zero"
LcdWrite(1, 0x48); // Send data char 'H'
LcdWrite(1, 0x69); // Send data char 'i'
}
To show another 4-bit example, Rabbit_RCM3720_to_HD44780LCD_example4.c is our second program converted into 4-bit mode.
The 'scalable' part, creating a library for easy access to LCD functions

After being able to fully control the LCD, I converted the functions into a library for easy re-use in all future programs. I created a library file called hd44780lcd.lib and I placed it in C:\DCRABBIT_9.21\Lib\Displays. Then I added the library to Dynamic C's library inclusion list in C:\DCRABBIT_9.21\Lib.dir.
To use the LCD functions provided in the library, add the line #use "hd44780lcd.lib" to programs. If necessary, adjust the library definitions to your ports and pins if they are different from my setup (data lines port A, control lines on port B2, B3, and B4) and define the number of data lines used with #define INTERFACE 8 or #define INTERFACE 4 on top of your program. The library's default is set to 8bit.
To test the newly created library file, I modified the previous code from example4.c to use it and called the resulting code
Rabbit_RCM3720_to_HD44780LCD_example5.c.
The example program BROWSELED.C in C:\DCRABBIT_9.21\Samples\RCM3720\Tcpip provided by Rabbit Inc. is a additional modification to
Rabbit_RCM3720_to_HD44780LCD_example6.c.
After running it, connecting to the Rabbit through the network port, I can switch the evaluation board's LED on and off using a browser. The board's IP address and netmask is conveniently displayed and alternates with showing the LED state on the LCD display.
Credits, copyrights, links and software
I make the library available under the terms of the LGPL.
Any comments, improvements and thanks are welcome to: public[at]frank4dd[dot]com, there is much left to be perfected. Thanks to my wife and child for their patience. Below is a selection of links and documents that helped me to extract the information needed:
- How to use intelligent L.C.D.s - URL by Julyan Ilett (local copy: Part 1 and Part 2)
- Sunlike 2x16 LCD SC1602 datasheet (local copy)
- HD44780-Based LCD by Erik Nordin, (local copy)
- Rabbit microprocessors and their manuals are made by Rabbit Semiconductor® Inc.
- A zip file containing all RCM3720 examples, plus the library version 1.0 Rabbit RCM3720_to_HD44780.zip
- How to connect a Rabbit 4000 CPU Connecting a HD44780 compatible LCD to a Rabbit RCM4010
- Updated examples for the RCM4010, plus the latest library version 1.1 Rabbit RCM3720_to_HD44780.zip
