Introduction


HD44780 Logo Rabbit Logo

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.

Connection Scheme

The 'soldering' part: Physical installation on the development board


Rabbit RCM3720 LCD connection top

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.

Rabbit RCM3720 LCD wiring bottom

The 'Testing' part: Learning how to programm the parallel LCD display


SC1602BSLB running testprogram1

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://fm4dd.com/electronics  */
/*                                                                         */
/* 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'
}

Rabbit RCM3720 LCD example program2

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://fm4dd.com/electronics  */
/*                                                                         */
/* 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


Rabbit RCM3720 LCD example web access
Rabbit RCM3720 LCD example program5

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


LGPL Logo

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:

Topics: