Interface HD44780 compatible LCDs with RCM3720

These are my notes of connecting a RCM3720 RabbitCore Ethernet Development kit, using the supplied development board; and a Sunlike SC1602BSLB 2x16 LCD display.

Github Repository

Schema: 4-bit mode interface

4-bit schema

4-bit Mode Setup

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". It is twice as much work. After adjusting example1 to implement 4-bit mode, Rabbit_RCM3720_to_HD44780LCD_example3.c shows the overhead. The extra function LcdInit() is now required to reliably initialize the 4-bit mode.

/***************************************************************************/
/* Rabbit_RCM3720_to_HD44780LCD_example3.c   http://fpga.fm4dd.com/        */
/*                                                                         */
/* 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 first and 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.

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 file 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 from 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

I make the HD44780 LCD library available under the terms of the LGPL.

Reference