Monday, April 28, 2014

4x20 LCD Display and the BeagleBone Black

Have a 4x20 character LCD Display from Newhaven (NHD-0420AZ-FSW-GBW-33V3) that I wanted to get working on a BeagleBone Black.  Did some searching and found a good reference that I thought would work for me here.  However, I couldn't get it to work out of the box (mostly I assume because this particular LCD Display has an interesting startup routine.  So I used the python code referenced in the linked blog and modified it for use with my display and Python3.  For my purposes I decided to just run the LCD with 4 lines (instead of 8).  

The following our my pin connections (Very minimal test setup):

     LCD                        BeagleBone Black
Pin 1 (Ground)       ->     P9-1 (Ground)
Pin 2 (VDD)           ->     P9-3 (3.3 V)
Pin 3 (Contrast)      ->    P9-45 (Ground)
Pin 4 (RS)               ->     P9-23
Pin 5 (R/W)            ->     P9-2 (Ground)
Pin 6 (E)                 ->     P9-24
Pin 7 (DB0)            ->     Not Connected
Pin 8 (DB1)            ->     Not Connected
Pin 9 (DB2)            ->     Not Connected
Pin 10 (DB3)          ->     Not Connected
Pin 11 (DB4)          ->     P9-15
Pin 12 (DB5)          ->     P9-16
Pin 13 (DB6)          ->     P9-21
Pin 14 (DB7)          ->     P9-22
Pin 15 (BackLight) ->     P9-4 (3.3V)
Pin 16 (Ground)     ->      P9-46 (Ground)


I didn't worry about control of contrast, backlight, or reading the LCD but all could be added to other IO pins if needed, really just wanted to see if I could get it to work.

Here is the python code:

#!/usr/bin/env python3


import Adafruit_BBIO.GPIO as GPIO
from time import sleep

#----------------------------------------------------------------------#
#   Pins used to transfer data to the LCD display
#----------------------------------------------------------------------#
PINS = {'E':'P9_24',    # pin 6 on LCD
'RS':'P9_23',   # pin 4 on LCD
'DB7':'P9_22',  # pin 14 on LCD
'DB6':'P9_21',  # pin 13 on LCD
'DB5':'P9_16',  # pin 12 on LCD
'DB4':'P9_15',  # pin 11 on LCD
}

#----------------------------------------------------------------------#
#   Font Table
#----------------------------------------------------------------------#
#
#   Corresponding 8bit definition for each character
#
CHARS = {'a':0b01100001, 'b':0b01100010, 'c':0b01100011, 'd':0b01100100,
'e':0b01100101, 'f':0b01100110, 'g':0b01100111, 'h':0b01101000,
'i':0b01101001, 'j':0b01101010, 'k':0b01101011, 'l':0b01101100,
'm':0b01101101, 'n':0b01101110, 'o':0b01101111, 'p':0b01110000,
'q':0b01110001, 'r':0b01110010, 's':0b01110011, 't':0b01110100,
'u':0b01110101, 'v':0b01110110, 'w':0b01110111, 'x':0b01111000,
'y':0b01111001, 'z':0b01111010, 'A':0b01000001, 'B':0b01000010,
'C':0b01000011, 'D':0b01000100, 'E':0b01000101, 'F':0b01000110,
'G':0b01000111, 'H':0b01001000, 'I':0b01001001, 'J':0b01001010,
'K':0b01001011, 'L':0b01001100, 'M':0b01001101, 'N':0b01001110,
'O':0b01001111, 'P':0b01010000, 'Q':0b01010001, 'R':0b01010010,
'S':0b01010011, 'T':0b01010100, 'U':0b01010101, 'V':0b01010110,
'W':0b01010111, 'Y':0b01011001, 'Z':0b01011010, '1':0b00110001,
'2':0b00110010, '3':0b00110011, '4':0b00110100, '5':0b00110101,
'6':0b00110110, '7':0b00110111, '8':0b00111000, '9':0b00111001,
'0':0b00110000, ':':0b00111010, ';':0b00111011, '<':0b00111100,
'=':0b00111101, '>':0b00111110, '?':0b00111111, '!':0b00100001,
'#':0b00100011, '$':0b00100100, '%':0b00100101, '&':0b00100110,
'(':0b00101000, ')':0b00101001, '*':0b00101010, '+':0b00101011,
',':0b00101100, '-':0b00101101, '.':0b00101110, '/':0b00101111,
' ':0b11111110
}

#----------------------------------------------------------------------#
#   Helper functions 
#----------------------------------------------------------------------#

def initalizePins(pins):
for pin in pins.values():
GPIO.setup(pin, GPIO.OUT)
set_all_low(pins)

def set_to_state(pin, state):
if (state):
GPIO.output(pin, GPIO.HIGH)
else:
GPIO.output(pin, GPIO.LOW)

def set_high(pin):
set_to_state(pin, GPIO.HIGH)

def set_low(pin):
set_to_state(pin, GPIO.LOW)

def set_all_low(pins):
for pin in pins.values():
set_low(pin)

def getBit(value, bit):
return ((value >> bit) & 0x01)

#----------------------------------------------------------------------#
#   LCD control 
#----------------------------------------------------------------------#
class Screen:

def __init__(self):
self.pins = dict(PINS)
initalizePins(self.pins)
self.initializeLCD()

def initializeLCD(self):
set_low(PINS['E'])
sleep(0.015)
set_low(PINS['RS'])
self.sendHalf(0x03)
sleep(0.005)
set_low(PINS['RS'])
self.sendHalf(0x03)
sleep(0.000160)
set_low(PINS['RS'])
self.sendHalf(0x03)
sleep(0.000160)
set_low(PINS['RS'])
self.sendHalf(0x02)   # Command: bit 5) always 1; bit 4) 8 bit(hi), 4 bit (lo); bit 3) 2 lines or 1 line; bit 2) font
sleep(0.000160)
self.sendCommand(0x2C)   # Command: bit 5) always 1; bit 4) 8 bit(hi), 4 bit (lo); bit 3) 2 lines or 1 line; bit 2) font
sleep(0.000160)
self.sendCommand(0x10)   # set cursor
self.sendCommand(0x0C)   # Always 1 (3rd bit); Display on (2nd bit); Cursor off (1st bit); Blinking (0 bit)
self.sendCommand(0x06)   # Entry mode set (2nd bit); cursor direction (1st bit); display shift (0 bit)


def transfer(self):
set_high(PINS['E'])
sleep(0.000032)
set_low(PINS['E'])

def sendHalf(self, half):
set_to_state(PINS['DB7'], getBit(half,3))
set_to_state(PINS['DB6'], getBit(half,2))
set_to_state(PINS['DB5'], getBit(half,1))
set_to_state(PINS['DB4'], getBit(half,0))
self.transfer()

def sendCommand(self, command):
set_low(PINS['RS'])
self.sendHalf(command >> 4)
set_low(PINS['RS'])
self.sendHalf(command & 0x0F)
sleep(0.000064)

def sendData(self, command):
set_high(PINS['RS'])
self.sendHalf(command >> 4)
set_high(PINS['RS'])
self.sendHalf(command & 0x0F)
sleep(0.000064)

def clearDisplay(self):
self.sendCommand(0x01)
sleep(.002)

def returnHome(self):
self.sendCommand(0x02)
sleep(.002)

def startPosition(self, index):
self.sendCommand(index | 0x80)

def moveCursor(self, line_number):
self.returnHome()
line_command = {1:0x00, 2:0x40, 3:0x14, 4:0x54}
try:
self.startPosition(line_command[line_number])
except:
self.startPosition(line_command[1])

def printLine(self, line, line_number=1):
self.moveCursor(line_number)
if len(line)>20:
line = line[:20]

for char in line:
try:
command = CHARS[char]
except:
command = CHARS['?']
self.sendData(command)


if __name__ == '__main__':
lcdOutput = Screen()
lcdOutput.clearDisplay()
lcdOutput.printLine('123456789!123456789!', 1)
lcdOutput.printLine("ABCDEFGHIJKLMNOPQRST", 2)
lcdOutput.printLine("Hello World and Moon", 3)
lcdOutput.printLine("Don't Worry Be Happy", 4)



If you run this python script you should see the above text on the LCD screen.