Re: Nokia Pi LCD
Posted: Tue Jan 15, 2013 9:58 pm
That's the package. I installed it using pip:
I have been programming on Linux -- desktop and embedded -- for some time, but I am new to Python. Still, it was simple to get spidev working. I adapted some code I had found on the forums to use the SPI interface via spidev. I've been playing with it for the last week since my Nokia displays arrived. The code is listed below, but it's not pretty to look at right now. I have been hacking through it to see if I can use PIL for doing graphics and general rendering. All I can say is it works.
You may need to update the pin assignments to match your configuration. When you run the code, it will cycle between three screens and print timing information. The first is the text dump as originally in the code. The second is a test of the custom characters on the first row. The third is a simple graphic with text from PIL.
Maybe it will be of some use...
Enjoy!
Bill
Code: Select all
sudo pip install spidev

Code: Select all
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# code improvements
# 9/10/12
######
# WGG - picked up from Raspberry Pi forums and modified with a heavy hand
# -- added spidev support
# -- testing with PIL
import time
import wiringpi
import spidev
from PIL import Image,ImageDraw,ImageFont
# White backlight
CONTRAST = 0xa4
# Blue backlight
#CONTRAST = 0xb4
ROWS = 6
COLUMNS = 14
PIXELS_PER_ROW = 6
ON = 1
OFF = 0
#gpio's :
DC = 3 # gpio pin 15 = wiringpi no. 3 (BCM 22)
RST = 0 # gpio pin 11 = wiringpi no. 0 (BCM 17)
LED = 1 # gpio pin 12 = wiringpi no. 1 (BCM 18)
# SPI connection
SCE = 10 # gpio pin 24 = wiringpi no. 10 (CE0 BCM 8)
SCLK = 14 # gpio pin 23 = wiringpi no. 14 (SCLK BCM 11)
DIN = 12 # gpio pin 19 = wiringpi no. 12 (MOSI BCM 10)
CLSBUF=[0]*(ROWS * COLUMNS * PIXELS_PER_ROW)
FONT = {
' ': [0x00, 0x00, 0x00, 0x00, 0x00],
'!': [0x00, 0x00, 0x5f, 0x00, 0x00],
'"': [0x00, 0x07, 0x00, 0x07, 0x00],
'#': [0x14, 0x7f, 0x14, 0x7f, 0x14],
'$': [0x24, 0x2a, 0x7f, 0x2a, 0x12],
'%': [0x23, 0x13, 0x08, 0x64, 0x62],
'&': [0x36, 0x49, 0x55, 0x22, 0x50],
"'": [0x00, 0x05, 0x03, 0x00, 0x00],
'(': [0x00, 0x1c, 0x22, 0x41, 0x00],
')': [0x00, 0x41, 0x22, 0x1c, 0x00],
'*': [0x14, 0x08, 0x3e, 0x08, 0x14],
'+': [0x08, 0x08, 0x3e, 0x08, 0x08],
',': [0x00, 0x50, 0x30, 0x00, 0x00],
'-': [0x08, 0x08, 0x08, 0x08, 0x08],
'.': [0x00, 0x60, 0x60, 0x00, 0x00],
'/': [0x20, 0x10, 0x08, 0x04, 0x02],
'0': [0x3e, 0x51, 0x49, 0x45, 0x3e],
'1': [0x00, 0x42, 0x7f, 0x40, 0x00],
'2': [0x42, 0x61, 0x51, 0x49, 0x46],
'3': [0x21, 0x41, 0x45, 0x4b, 0x31],
'4': [0x18, 0x14, 0x12, 0x7f, 0x10],
'5': [0x27, 0x45, 0x45, 0x45, 0x39],
'6': [0x3c, 0x4a, 0x49, 0x49, 0x30],
'7': [0x01, 0x71, 0x09, 0x05, 0x03],
'8': [0x36, 0x49, 0x49, 0x49, 0x36],
'9': [0x06, 0x49, 0x49, 0x29, 0x1e],
':': [0x00, 0x36, 0x36, 0x00, 0x00],
';': [0x00, 0x56, 0x36, 0x00, 0x00],
'<': [0x08, 0x14, 0x22, 0x41, 0x00],
'=': [0x14, 0x14, 0x14, 0x14, 0x14],
'>': [0x00, 0x41, 0x22, 0x14, 0x08],
'?': [0x02, 0x01, 0x51, 0x09, 0x06],
'@': [0x32, 0x49, 0x79, 0x41, 0x3e],
'A': [0x7e, 0x11, 0x11, 0x11, 0x7e],
'B': [0x7f, 0x49, 0x49, 0x49, 0x36],
'C': [0x3e, 0x41, 0x41, 0x41, 0x22],
'D': [0x7f, 0x41, 0x41, 0x22, 0x1c],
'E': [0x7f, 0x49, 0x49, 0x49, 0x41],
'F': [0x7f, 0x09, 0x09, 0x09, 0x01],
'G': [0x3e, 0x41, 0x49, 0x49, 0x7a],
'H': [0x7f, 0x08, 0x08, 0x08, 0x7f],
'I': [0x00, 0x41, 0x7f, 0x41, 0x00],
'J': [0x20, 0x40, 0x41, 0x3f, 0x01],
'K': [0x7f, 0x08, 0x14, 0x22, 0x41],
'L': [0x7f, 0x40, 0x40, 0x40, 0x40],
'M': [0x7f, 0x02, 0x0c, 0x02, 0x7f],
'N': [0x7f, 0x04, 0x08, 0x10, 0x7f],
'O': [0x3e, 0x41, 0x41, 0x41, 0x3e],
'P': [0x7f, 0x09, 0x09, 0x09, 0x06],
'Q': [0x3e, 0x41, 0x51, 0x21, 0x5e],
'R': [0x7f, 0x09, 0x19, 0x29, 0x46],
'S': [0x46, 0x49, 0x49, 0x49, 0x31],
'T': [0x01, 0x01, 0x7f, 0x01, 0x01],
'U': [0x3f, 0x40, 0x40, 0x40, 0x3f],
'V': [0x1f, 0x20, 0x40, 0x20, 0x1f],
'W': [0x3f, 0x40, 0x38, 0x40, 0x3f],
'X': [0x63, 0x14, 0x08, 0x14, 0x63],
'Y': [0x07, 0x08, 0x70, 0x08, 0x07],
'Z': [0x61, 0x51, 0x49, 0x45, 0x43],
'[': [0x00, 0x7f, 0x41, 0x41, 0x00],
'\\': [0x02, 0x04, 0x08, 0x10, 0x20],
']': [0x00, 0x41, 0x41, 0x7f, 0x00],
'^': [0x04, 0x02, 0x01, 0x02, 0x04],
'_': [0x40, 0x40, 0x40, 0x40, 0x40],
'`': [0x00, 0x01, 0x02, 0x04, 0x00],
'a': [0x20, 0x54, 0x54, 0x54, 0x78],
'b': [0x7f, 0x48, 0x44, 0x44, 0x38],
'c': [0x38, 0x44, 0x44, 0x44, 0x20],
'd': [0x38, 0x44, 0x44, 0x48, 0x7f],
'e': [0x38, 0x54, 0x54, 0x54, 0x18],
'f': [0x08, 0x7e, 0x09, 0x01, 0x02],
'g': [0x0c, 0x52, 0x52, 0x52, 0x3e],
'h': [0x7f, 0x08, 0x04, 0x04, 0x78],
'i': [0x00, 0x44, 0x7d, 0x40, 0x00],
'j': [0x20, 0x40, 0x44, 0x3d, 0x00],
'k': [0x7f, 0x10, 0x28, 0x44, 0x00],
'l': [0x00, 0x41, 0x7f, 0x40, 0x00],
'm': [0x7c, 0x04, 0x18, 0x04, 0x78],
'n': [0x7c, 0x08, 0x04, 0x04, 0x78],
'o': [0x38, 0x44, 0x44, 0x44, 0x38],
'p': [0x7c, 0x14, 0x14, 0x14, 0x08],
'q': [0x08, 0x14, 0x14, 0x18, 0x7c],
'r': [0x7c, 0x08, 0x04, 0x04, 0x08],
's': [0x48, 0x54, 0x54, 0x54, 0x20],
't': [0x04, 0x3f, 0x44, 0x40, 0x20],
'u': [0x3c, 0x40, 0x40, 0x20, 0x7c],
'v': [0x1c, 0x20, 0x40, 0x20, 0x1c],
'w': [0x3c, 0x40, 0x30, 0x40, 0x3c],
'x': [0x44, 0x28, 0x10, 0x28, 0x44],
'y': [0x0c, 0x50, 0x50, 0x50, 0x3c],
'z': [0x44, 0x64, 0x54, 0x4c, 0x44],
'{': [0x00, 0x08, 0x36, 0x41, 0x00],
'|': [0x00, 0x00, 0x7f, 0x00, 0x00],
'}': [0x00, 0x41, 0x36, 0x08, 0x00],
'~': [0x10, 0x08, 0x08, 0x10, 0x08],
'\x7f': [0x00, 0x7e, 0x42, 0x42, 0x7e],
}
ORIGINAL_CUSTOM = FONT['\x7f']
def bit_reverse(value, width=8):
result = 0
for _ in xrange(width):
result = (result << 1) | (value & 1)
value >>= 1
return result
BITREVERSE = map(bit_reverse, xrange(256))
spi = spidev.SpiDev()
def setup():
# Set pin directions.
wiringpi.wiringPiSetup()
for pin in [DC, RST]:
wiringpi.pinMode(pin, ON)
wiringpi.pinMode(LED,2)
wiringpi.pwmWrite(LED,128)
spi.open(0,0)
spi.max_speed_hz=5000000
def lcd_cmd(value):
wiringpi.digitalWrite(DC, OFF)
spi.writebytes([value])
def lcd_data(value):
wiringpi.digitalWrite(DC, ON)
spi.writebytes([value])
def gotoxy(x, y):
wiringpi.digitalWrite(DC, OFF)
spi.writebytes([x+128,y+64])
def cls():
gotoxy(0, 0)
wiringpi.digitalWrite(DC, ON)
spi.writebytes(CLSBUF)
def begin(contrast):
setup()
# Toggle RST low to reset.
wiringpi.digitalWrite(RST, OFF)
wiringpi.digitalWrite(LED, ON)
time.sleep(0.100)
wiringpi.digitalWrite(RST, ON)
# Extended mode, bias, vop, basic mode, non-inverted display.
wiringpi.digitalWrite(DC, OFF)
spi.writebytes([0x21, 0x14, contrast, 0x20, 0x0c])
# cls()
def init():
begin(CONTRAST)
def led(led_value):
wiringpi.pwmWrite(LED,led_value)
def load_bitmap(filename, reverse=False):
mask = 0xff if reverse else 0x00
gotoxy(0, 0)
with open(filename, 'rb') as bitmap_file:
for x in xrange(6):
for y in xrange(84):
bitmap_file.seek(0x3e + y * 8 + x)
lcd_data(BITREVERSE[ord(bitmap_file.read(1))] ^ mask)
def show_custom(font=FONT):
display_char('\x7f', font)
def define_custom(values):
FONT['\x7f'] = values
def restore_custom():
define_custom(ORIGINAL_CUSTOM)
def alt_custom():
define_custom([0x00, 0x50, 0x3C, 0x52, 0x44])
def pi_custom():
define_custom([0x19, 0x25, 0x5A, 0x25, 0x19])
def display_char(char, font=FONT):
try:
wiringpi.digitalWrite(DC, ON)
spi.writebytes(font[char]+[0])
except KeyError:
pass # Ignore undefined characters.
def text(string, font=FONT):
for char in string:
display_char(char, font)
def gotorc(r, c):
lcd_cmd(c * 6 + 128)
lcd_cmd(r + 64)
def centre_word(r, word):
gotorc(r, max(0, (COLUMNS - len(word)) // 2))
text(word)
def put_image(im):
# Rotate and mirror the image
rim = im.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
# Change display to vertical write mode for graphics
wiringpi.digitalWrite(DC, OFF)
spi.writebytes([0x22])
# Start at upper left corner
gotoxy(0, 0)
# Put on display with reversed bit order
wiringpi.digitalWrite(DC, ON)
spi.writebytes( [ BITREVERSE[ord(x)] for x in list(rim.tostring()) ] )
# Switch back to horizontal write mode for text
wiringpi.digitalWrite(DC, OFF)
spi.writebytes([0x20])
def main():
start, end = 32, 116
print 'LCD Display Test: ASCII %d to %d' % (start, end)
# do not include init() in the timing tests
init()
while 1:
start_time = time.time()
cls()
led(768)
for i in xrange(start, end):
display_char(chr(i))
finish_time = time.time()
print 'Cls, LED on, %d chars, total time = %.3f' % (
end - start, finish_time - start_time
)
print
time.sleep(1)
# Test a custom character for 0x7f (supposed to be a bell)
# . . . - - - - -
# . . . - - X - -
# . . . - X X X -
# . . . - X - X -
# . . . X - - - X
# . . . X X X X X
# . . . - - X X -
# . . . - - - - -
define_custom([0x30,0x2c,0x66,0x6c,0x30])
cls()
text("\x7f \x7f \x7f \x7f \x7f \x7f \x7f ")
text(" Hello ")
text(" Raspberry Pi")
# Backlight PWM testing -- off -> 25% -> off
#for i in range(0,255):
# led(i)
# time.sleep(0.025)
#for i in range(255,0,-1):
# led(i)
# time.sleep(0.025)
time.sleep(1)
## Generate an image with PIL and put on the display
## First time through is slow as the fonts are not cached
##
start_time = time.time()
# load an available True Type font
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSansBold.ttf", 14)
# New b-w image
im = Image.new('1', (84,48))
# New drawable on image
draw = ImageDraw.Draw(im)
# Full screen and half-screen ellipses
draw.ellipse((0,0,im.size[0]-1,im.size[1]-1), outline=1)
draw.ellipse((im.size[0]/4,im.size[1]/4,im.size[0]/4*3-1,im.size[1]/4*3-1), outline=1)
# Some simple text for a test (first with TT font, second with default
draw.text((10,10), "hello", font=font, fill=1)
draw.text((10,24), "world", fill=1)
# Check what happens when text exceeds width (clipped)
draw.text((0,0), "ABCabcDEFdefGHIghi", fill=1)
# Copy it to the display
put_image(im)
# clean up
del draw
del im
finish_time = time.time()
print 'PIL Drawing, total time = %.3f' % (
finish_time - start_time
)
print
time.sleep(1)
# Dim the LED...
#led(64)
# To loop continuously, remove the break
#break
if __name__ == '__main__':
main()
Maybe it will be of some use...
Enjoy!
Bill