texy
Forum Moderator
Forum Moderator
Posts: 5160
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Nokia Pi LCD

Sun Jan 27, 2013 3:44 pm

Glad you agree that it was a gotcha !
Easy enough to do, but it wood be better to have those commands run from within the python script. Then again you wouldn't normally mix the driving method.
T.
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Nokia Pi LCD

Sun Jan 27, 2013 5:36 pm

bgreat wrote: The spidev driver relies on the spi_bcm2708 driver which allocates and configures the SPI pin resources when it first loads. The spi_bcm2708 driver assumes it has complete ownership and no other software will modify the configuration of those resources. When the pin configuration is subsequently modified by an external application, the spidev driver will no longer function correctly as the spi_bcm2708 pin configuration is no longer valid.
That might explain an issue I had this week testing the rev 2 Gertboard. The py-spidev ADC and DAC programs didn't seem to work after having run other programs which had used those ports, but when I rebooted, it was fine.

It also worked if I ran the C ones first (clearly the C version sets the configuration of SPI at a different level or something).

Can we incorporate those configuration commands in a Python script to make it more bullet-proof?

Using something like subprocess perhaps?

Code: Select all

reload_spi = subprocess.Popen('sudo rmmod spi_bcm2708', shell=True, stdout=subprocess.PIPE)
start_spi = subprocess.Popen('sudo modprobe spi_bcm2708', shell=True, stdout=subprocess.PIPE)
I've used a similar approach with a DS18B20 sensor
Alex Eames RasPi.TV, RasP.iO

texy
Forum Moderator
Forum Moderator
Posts: 5160
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Nokia Pi LCD

Sun Jan 27, 2013 5:50 pm

...something like that was my feeling ;)

T.
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Nokia Pi LCD

Sun Jan 27, 2013 6:01 pm

Yep that did it. (Punching the air in a Eureka fashion.) Great catch guys. :D

I've just tried it with the dad.py program and it works (not only that but I could repeat the failure mode and now I understand why it failed AND how to fix it.) YAY :D :D
Alex Eames RasPi.TV, RasP.iO

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: Nokia Pi LCD

Mon Jan 28, 2013 12:07 am

The 'subprocess' solution works, but is not elegant. ;)

I am working on a Python solution now. It is working for me, but I want to do some more testing before I post the code.

Enjoy!
Bill

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: Nokia Pi LCD

Mon Jan 28, 2013 2:06 am

OK. Here is a Python solution without calling external applications to reload the driver. It basically tests that the SPI GPIO pins are configured for the proper operation. If not, it prints a warning and updates the configuration.

SPI configuration test/update:

Code: Select all

# For SPI configuration test
import os
import mmap

BCM2708_PERI_BASE=0x20000000
GPIO_BASE=(BCM2708_PERI_BASE + 0x00200000)
BLOCK_SIZE=4096

def _strto32bit_(str):
    return ((ord(str[3])<<24) + (ord(str[2])<<16) + (ord(str[1])<<8) + ord(str[0]))

def _32bittostr_(val):
    return chr(val&0xff) + chr((val>>8)&0xff) + chr((val>>16)&0xff) + chr((val>>24)&0xff)

def spiConfig():
    # Use /dev/mem to gain access to peripheral registers
    mf=os.open("/dev/mem", os.O_RDWR|os.O_SYNC)
    m = mmap.mmap(mf,BLOCK_SIZE, mmap.MAP_SHARED,
            mmap.PROT_READ|mmap.PROT_WRITE,offset=GPIO_BASE)
    # can close the file after we have mmap
    os.close(mf)
    # Read first two registers (have SPI pin function assignements)
    # GPFSEL0
    m.seek(0)
    reg0=_strto32bit_(m.read(4))
    # GPFSEL1
    m.seek(4)
    reg1=_strto32bit_(m.read(4))
    # print bin(reg0)[2:].zfill(32)[2:]
    # print bin(reg1)[2:].zfill(32)[2:]

    # GPFSEL0 bits --> x[2] SPI0_MISO[3] SPI0_CE0[3] SPI0_CE1[3] x[21]
    # We only use SPI0_CEx depending on setup, but make sure all are set up
    m0 = 0b00111111111000000000000000000000
    s0 = 0b00100100100000000000000000000000
    b0 = reg0 & m0
    if b0 <> s0:
        print "SPI reg0 configuration not correct. Updating."
        reg0 = (reg0 & ~m0) | s0
        m.seek(0)
        m.write(_32bittostr_(reg0))

    # GPFSEL1 bits --> x[26] SPI0_MOSI[3] SPI0_SCLK[3]
    m1 = 0b00000000000000000000000000111111
    s1 = 0b00000000000000000000000000100100
    b1 = reg1 & m1
    if b1 <> s1:
        print "SPI reg1 configuration not correct. Updating."
        reg1 = (reg1 & ~m1) | s1
        m.seek(4)
        m.write(_32bittostr_(reg1))

    # No longer need the mmap
    m.close()
After opening spidev, call "spiConfig()" to update the pin settings if needed.

Here is nokiaSPI.py updated to use spiConfig():

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
# 16-Jan-2013
# -- initial NokiaSPI class
# 27-Jan-2013
# -- SPI configuration reset

import time
import wiringpi
import spidev
from PIL import Image,ImageDraw,ImageFont

# White backlight
CONTRAST = 0xb8

# 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)

# #######
# For SPI configuration test
import os
import mmap

BCM2708_PERI_BASE=0x20000000
GPIO_BASE=(BCM2708_PERI_BASE + 0x00200000)
BLOCK_SIZE=4096

def _strto32bit_(str):
    return ((ord(str[3])<<24) + (ord(str[2])<<16) + (ord(str[1])<<8) + ord(str[0]))

def _32bittostr_(val):
    return chr(val&0xff) + chr((val>>8)&0xff) + chr((val>>16)&0xff) + chr((val>>24)&0xff)

def spiConfig():
    # Use /dev/mem to gain access to peripheral registers
    mf=os.open("/dev/mem", os.O_RDWR|os.O_SYNC)
    m = mmap.mmap(mf,BLOCK_SIZE, mmap.MAP_SHARED, 
            mmap.PROT_READ|mmap.PROT_WRITE,offset=GPIO_BASE)
    # can close the file after we have mmap
    os.close(mf)
    # Read first two registers (have SPI pin function assignements)
    # GPFSEL0
    m.seek(0)
    reg0=_strto32bit_(m.read(4))
    # GPFSEL1
    m.seek(4)
    reg1=_strto32bit_(m.read(4))
    # print bin(reg0)[2:].zfill(32)[2:]
    # print bin(reg1)[2:].zfill(32)[2:]

    # GPFSEL0 bits --> x[2] SPI0_MISO[3] SPI0_CE0[3] SPI0_CE1[3] x[21]
    # We only use SPI0_CEx depending on setup, but make sure all are set up
    m0 = 0b00111111111000000000000000000000 
    s0 = 0b00100100100000000000000000000000
    b0 = reg0 & m0
    if b0 <> s0:
        print "SPI reg0 configuration not correct. Updating."
        reg0 = (reg0 & ~m0) | s0
        m.seek(0)
        m.write(_32bittostr_(reg0))

    # GPFSEL1 bits --> x[26] SPI0_MOSI[3] SPI0_SCLK[3]
    m1 = 0b00000000000000000000000000111111 
    s1 = 0b00000000000000000000000000100100
    b1 = reg1 & m1
    if b1 <> s1:
        print "SPI reg1 configuration not correct. Updating."
        reg1 = (reg1 & ~m1) | s1
        m.seek(4)
        m.write(_32bittostr_(reg1))

    # No longer need the mmap
    m.close()



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))

class NokiaSPI:
    def __init__(self, dev=(0,0),speed=4000000, brightness=256, contrast=CONTRAST):
        self.spi = spidev.SpiDev()
        self.speed = speed
        self.dev = dev
        self.spi.open(self.dev[0],self.dev[1])
        self.spi.max_speed_hz=self.speed
        spiConfig()

        # Set pin directions.
        self.dc = DC
        self.rst = RST
        wiringpi.wiringPiSetup()
        for pin in [self.dc, self.rst]:
            wiringpi.pinMode(pin, 1)

        self.contrast=contrast
        self.brightness=brightness
        
        # Toggle RST low to reset.
        wiringpi.digitalWrite(self.rst, OFF)
        time.sleep(0.100)
        wiringpi.digitalWrite(self.rst, ON)
        # Extended mode, bias, vop, basic mode, non-inverted display.
        wiringpi.digitalWrite(self.dc, OFF)
        self.spi.writebytes([0x21, 0x14, self.contrast, 0x20, 0x0c])
        # cls()

        self.ledpin = LED
        if self.ledpin == 1:
            wiringpi.pinMode(self.ledpin, 2)
            wiringpi.pwmWrite(self.ledpin, self.brightness)
        else:
            wiringpi.pinMode(self.ledpin, 1)
            wiringpi.digitalWrite(self.ledpin, ON)


    def lcd_cmd(self,value):
        wiringpi.digitalWrite(self.dc, OFF)
        self.spi.writebytes([value])


    def lcd_data(self,value):
        wiringpi.digitalWrite(self.dc, ON)
        self.spi.writebytes([value])


    def gotoxy(self, x, y):
        wiringpi.digitalWrite(self.dc, OFF)
        self.spi.writebytes([x+128,y+64])


    def cls(self):
        self.gotoxy(0, 0)
        wiringpi.digitalWrite(self.dc, ON)
        self.spi.writebytes(CLSBUF)


    def fill(self,pattern=0xff):
        fillbuf=[pattern]*(ROWS * COLUMNS * PIXELS_PER_ROW)
        self.gotoxy(0, 0)
        wiringpi.digitalWrite(self.dc, ON)
        self.spi.writebytes(fillbuf)


    def led(self, led_value):
        if self.ledpin == 1:
            wiringpi.pwmWrite(self.ledpin,led_value)
        else:
            if led_value == 0:
                wiringpi.digitalWrite(self.ledpin, OFF)
            else:
                wiringpi.digitalWrite(self.ledpin, ON)


    def load_bitmap(self, filename, reverse=False):
        mask = 0xff if reverse else 0x00
        self.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)
                self.lcd_data(BITREVERSE[ord(bitmap_file.read(1))] ^ mask)


    def show_custom(self, font=FONT):
        self.display_char('\x7f', font)


    def define_custom(self, values):
        FONT['\x7f'] = values


    def restore_custom(self):
        self.define_custom(ORIGINAL_CUSTOM)


    def alt_custom(self):
        self.define_custom([0x00, 0x50, 0x3C, 0x52, 0x44])


    def pi_custom(self):
        self.define_custom([0x19, 0x25, 0x5A, 0x25, 0x19])


    def display_char(self, char, font=FONT):
        try:
            wiringpi.digitalWrite(self.dc, ON)
            self.spi.writebytes(font[char]+[0])

        except KeyError:
            pass # Ignore undefined characters.


    def text(self, string, font=FONT):
        for char in string:
            self.display_char(char, font)


    def gotorc(self, r, c):
        self.gotoxy(c*6,r)


    def centre_word(self, r, word):
        self.gotorc(r, max(0, (COLUMNS - len(word)) // 2))
        self.text(word)

    def show_image(self,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)
        self.spi.writebytes([0x22])

        # Start at upper left corner
        self.gotoxy(0, 0)
        # Put on display with reversed bit order
        wiringpi.digitalWrite(DC, ON)
        self.spi.writebytes( [ BITREVERSE[ord(x)] for x in list(rim.tostring()) ] )

        # Switch back to horizontal write mode for text
        wiringpi.digitalWrite(DC, OFF)
        self.spi.writebytes([0x20])

if __name__ == '__main__':
    start, end = 32, 116
    print 'LCD Display Test: ASCII %d to %d' % (start, end)
    # do not include init() in the timing tests
    ## init()
    noki = NokiaSPI()
    start_time = time.time()
    noki.cls()
    noki.led(768)
    for i in xrange(start, end):
        noki.display_char(chr(i))

    finish_time = time.time()
    print 'Cls, LED on, %d chars, total time = %.3f' % (
        end - start, finish_time - start_time
        )

    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 -
    # . . . - - - - -
    noki.define_custom([0x30,0x2c,0x66,0x6c,0x30])

    noki.cls()
    noki.text("\x7f \x7f \x7f \x7f \x7f \x7f \x7f ")
    noki.text("    Hello     ")
    noki.text(" Raspberry Pi")

    # Backlight PWM testing -- off -> 25% -> off
    #for i in range(0,255):
    #  noki.led(i)
    #  time.sleep(0.025)
    #for i in range(255,0,-1):
    #  noki.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
    noki.show_image(im)
    # clean up
    del draw
    del im

    finish_time = time.time()
    print 'PIL Drawing, total time = %.3f' % (finish_time - start_time)
If any code wants to make specific use of the unused SPI CE or SPI MISO pins, they can be reconfigured after calling spiConfig() or instatiating the nokiaSPI class without causing problems.

This was interesting to write. I had been wondering if the GPIO could be controlled via Python using mmap. The answer is yes, though it is not as clean as I would like. The handling of 32-bit I/O is cumbersome. It could probably be improved by using the struct module, but that is a future effort. As an additional experiment, I may write a class that implements the GPIO / WiringPi basic functionality using /dev/mem and mmap. I am curious to compare the performance.

Enjoy!
Bill

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Nokia Pi LCD

Mon Jan 28, 2013 8:26 am

bgreat wrote:OK. Here is a Python solution without calling external applications to reload the driver. It basically tests that the SPI GPIO pins are configured for the proper operation. If not, it prints a warning and updates the configuration.
Nice work Bill. That's a bit advanced :ugeek: for me to understand. If I put your configuration test in an external file and import it, will it work with generic spi stuff or is it just for the Nokia LCD?

Just as a matter of interest, why is the subprocess method inelegant? Is it a case of using a sledgehammer to crack a nut?
Alex Eames RasPi.TV, RasP.iO

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: Nokia Pi LCD

Mon Jan 28, 2013 12:28 pm

It is not specific to the LCD code, so you can use it any time you want to reset the SPI configuration. This is why I posted separately, grouped the code at the top of the file. It can be called any time before or after opening the spidev channel. I placed it after the open in the nokiaSPI code because I did not want to reconfigure the IO if spidev wasn't available. If I had given it some more thought, I probably would have made it an importable module with a standalone "if __name__ == '__main__':" section to allow independent use...

Something like this (as spiConfig.py):

Code: Select all

#!/usr/bin/env python

# For SPI configuration test
import os
import mmap

BCM2708_PERI_BASE=0x20000000
GPIO_BASE=(BCM2708_PERI_BASE + 0x00200000)
BLOCK_SIZE=4096

def _strto32bit_(str):
    return ((ord(str[3])<<24) + (ord(str[2])<<16) + (ord(str[1])<<8) + ord(str[0]))

def _32bittostr_(val):
    return chr(val&0xff) + chr((val>>8)&0xff) + chr((val>>16)&0xff) + chr((val>>24)&0xff)

def spiConfig():
    # Use /dev/mem to gain access to peripheral registers
    mf=os.open("/dev/mem", os.O_RDWR|os.O_SYNC)
    m = mmap.mmap(mf,BLOCK_SIZE, mmap.MAP_SHARED,
            mmap.PROT_READ|mmap.PROT_WRITE,offset=GPIO_BASE)
    # can close the file after we have mmap
    os.close(mf)
    # Read first two registers (have SPI pin function assignements)
    # GPFSEL0
    m.seek(0)
    reg0=_strto32bit_(m.read(4))
    # GPFSEL1
    m.seek(4)
    reg1=_strto32bit_(m.read(4))
    # print bin(reg0)[2:].zfill(32)[2:]
    # print bin(reg1)[2:].zfill(32)[2:]

    # GPFSEL0 bits --> x[2] SPI0_MISO[3] SPI0_CE0[3] SPI0_CE1[3] x[21]
    # We only use SPI0_CEx depending on setup, but make sure all are set up
    m0 = 0b00111111111000000000000000000000
    s0 = 0b00100100100000000000000000000000
    b0 = reg0 & m0
    if b0 <> s0:
        print "SPI reg0 configuration not correct. Updating."
        reg0 = (reg0 & ~m0) | s0
        m.seek(0)
        m.write(_32bittostr_(reg0))

    # GPFSEL1 bits --> x[26] SPI0_MOSI[3] SPI0_SCLK[3]
    m1 = 0b00000000000000000000000000111111
    s1 = 0b00000000000000000000000000100100
    b1 = reg1 & m1
    if b1 <> s1:
        print "SPI reg1 configuration not correct. Updating."
        reg1 = (reg1 & ~m1) | s1
        m.seek(4)
        m.write(_32bittostr_(reg1))

    # No longer need the mmap
    m.close()

if __name__ == '__main__':
    print "Testing SPI configuration"
    spiConfig()
Overall it is rather a simple piece of code. It uses /dev/mem to access the GPIO alternate function registers that have the SPI pins (code blatantly adapted from dom's C example). The registers have 3-bits of configuration information for each pin, 10 pins per register (2 unused upper bits). The SPI pins function is defined as a binary value of 100 in the bit position. I test for this value in the positions. If it is not set, I set it. I was surprised at how simple it is to do direct access to the registers. The only tricky bit is that the mmap does not have a 32-bit read/write, so I have to read the registers as a byte array, convert to 32-bit, make my tests/changes, convert back to a byte array, then update the registers. Simple. :geek: There is probably a simpler way, but I am still learning Python.

Enjoy!
Bill

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Nokia Pi LCD

Mon Jan 28, 2013 12:54 pm

bgreat wrote:Overall it is rather a simple piece of code.
Yeah I'm surprised I hadn't thought of it myself. :roll: :lol:

Thanks Bill :ugeek: :D
Alex Eames RasPi.TV, RasP.iO

MiloPi
Posts: 2
Joined: Mon Jan 28, 2013 1:36 pm
Location: Spain

Re: Nokia Pi LCD

Mon Jan 28, 2013 2:27 pm

Hi,

I trying to wire my raspberry to Lcd 3310, but I'm sure how wired raspberry, I don't want damage it. I dont understand wires? is emulated spi? why? Can you give me a schematic? I'dont find any.

I'm sorry for my English.
thanks a lot.

Sector7CSD
Posts: 2
Joined: Sun Jul 08, 2012 6:01 am

Re: Nokia Pi LCD

Fri Feb 08, 2013 6:12 pm

Hello guys,

I've converted the Python script to C++ - to fill the display with something - I obtain data from the mpd (music player daemon) about the current played song and display them.

Code: Select all

// main.cpp
// code by: Chris
// ---------------------------------------------------------------------

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <map>

// ---------------------------------------------------------------------

#include "libmpd/libmpd.h"
#include "wiringPi.h"

// ---------------------------------------------------------------------

using namespace std;

// ---------------------------------------------------------------------

#define RED "\x1b[31;01m"
#define DARKRED "\x1b[31;06m"
#define RESET "\x1b[0m"
#define GREEN "\x1b[32;06m"
#define YELLOW "\x1b[33;06m"

// ---------------------------------------------------------------------

MpdObj * 	obj  = NULL;
mpd_Song * 	song = NULL;
bool		songchanged = true;

// ---------------------------------------------------------------------

void error_callback(MpdObj *mi,int errorid, char *msg, void *userdata)
{
	printf(RED"Error "RESET""GREEN"%i:"RESET" '%s'\n", errorid, msg);
}

// ---------------------------------------------------------------------

void status_changed(MpdObj *mi, ChangedStatusType what)
{
	if(what&MPD_CST_SONGID)
    {
		song = mpd_playlist_get_current_song(mi);
		songchanged = true;
	}
}

// ---------------------------------------------------------------------

#define BYTE unsigned char

const int ROWS = 6;
const int COLUMNS = 14;
const int PIXELS_PER_ROW = 6;
const int ON = 1;
const int OFF = 0;
const int CONTRAST = 0xb6;

const int SCE  = 10; // gpio pin 13 = wiringpi no. 2
const int SCLK = 14; // gpio pin 18 = wiringpi no. 5
const int DIN  = 12; // gpio pin 16 = wiringpi no. 4
const int DC   = 3;  // gpio pin 15 = wiringpi no. 3
const int RST  = 0;  // gpio pin 11 = wiringpi no. 0
const int LED  = 1;  // gpio pin 12 = wiringpi no. 1
   
// ---------------------------------------------------------------------

struct pixeldata_s
{
	BYTE data [5];
	pixeldata_s(BYTE b1, BYTE b2, BYTE b3, BYTE b4, BYTE b5)
	{
		data[0] = b1;
		data[1] = b2;
		data[2] = b3;
		data[3] = b4;
		data[4] = b5;
	}
};

map<BYTE, pixeldata_s> fontmap;

// ---------------------------------------------------------------------

void SPI(BYTE value)
{
  // data = DIN
  // clock = SCLK
  // MSB first
  for(unsigned int i=0; i<8; i++)
  {
    digitalWrite(DIN, (value >> (7-i)) & 1);
    digitalWrite(SCLK, ON);    
    usleep(1);
    digitalWrite(SCLK, OFF);
    usleep(1);
   }
}
    
// ---------------------------------------------------------------------

void lcd_cmd(BYTE value)
{
  digitalWrite(DC, OFF);
  SPI(value);
}

// ---------------------------------------------------------------------

void lcd_data(BYTE value)
{
  digitalWrite(DC, ON);
  SPI(value);
}

// ---------------------------------------------------------------------

void gotoxy(BYTE x, BYTE y)
{
	lcd_cmd(x + 128);
	lcd_cmd(y + 64);
}

// ---------------------------------------------------------------------

void cls()
{
  gotoxy(0, 0);
  for(unsigned int i=0; i<ROWS * COLUMNS * PIXELS_PER_ROW; i++)
    lcd_data(0);
}

// ---------------------------------------------------------------------

void display_char(BYTE c)
{
	map<BYTE, pixeldata_s>::iterator it = fontmap.find(c);
	if(it != fontmap.end())
	{
		pixeldata_s pix = it->second;
	
		for(unsigned int i=0; i<5; i++)
		lcd_data(pix.data[i]);
 
		lcd_data(0); // Space inbetween characters.
	}
}

// ---------------------------------------------------------------------

void text(char * string)
{
  for(unsigned int i=0; i<strlen(string); i++)
    display_char(string[i]);
}
   
// ---------------------------------------------------------------------

int main()
{
	fontmap.insert(pair<BYTE, pixeldata_s>(' ', pixeldata_s(0x00, 0x00, 0x00, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('!', pixeldata_s(0x00, 0x07, 0x00, 0x07, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('"', pixeldata_s(0x14, 0x7f, 0x14, 0x7f, 0x14)));
	fontmap.insert(pair<BYTE, pixeldata_s>('$', pixeldata_s(0x24, 0x2a, 0x7f, 0x2a, 0x12)));
	fontmap.insert(pair<BYTE, pixeldata_s>('%', pixeldata_s(0x23, 0x13, 0x08, 0x64, 0x62)));
	fontmap.insert(pair<BYTE, pixeldata_s>('&', pixeldata_s(0x36, 0x49, 0x55, 0x22, 0x50)));
	fontmap.insert(pair<BYTE, pixeldata_s>('\'',pixeldata_s(0x00, 0x05, 0x03, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('(', pixeldata_s(0x00, 0x1c, 0x22, 0x41, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>(')', pixeldata_s(0x00, 0x41, 0x22, 0x1c, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('*', pixeldata_s(0x14, 0x08, 0x3e, 0x08, 0x14)));
	fontmap.insert(pair<BYTE, pixeldata_s>('+', pixeldata_s(0x08, 0x08, 0x3e, 0x08, 0x08)));
	fontmap.insert(pair<BYTE, pixeldata_s>(',', pixeldata_s(0x00, 0x50, 0x30, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('-', pixeldata_s(0x08, 0x08, 0x08, 0x08, 0x08)));
	fontmap.insert(pair<BYTE, pixeldata_s>('.', pixeldata_s(0x00, 0x60, 0x60, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('/', pixeldata_s(0x20, 0x10, 0x08, 0x04, 0x02)));
	fontmap.insert(pair<BYTE, pixeldata_s>('0', pixeldata_s(0x3e, 0x51, 0x49, 0x45, 0x3e)));
	fontmap.insert(pair<BYTE, pixeldata_s>('1', pixeldata_s(0x00, 0x42, 0x7f, 0x40, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('2', pixeldata_s(0x42, 0x61, 0x51, 0x49, 0x46)));
	fontmap.insert(pair<BYTE, pixeldata_s>('3', pixeldata_s(0x21, 0x41, 0x45, 0x4b, 0x31)));
	fontmap.insert(pair<BYTE, pixeldata_s>('4', pixeldata_s(0x18, 0x14, 0x12, 0x7f, 0x10)));
	fontmap.insert(pair<BYTE, pixeldata_s>('5', pixeldata_s(0x27, 0x45, 0x45, 0x45, 0x39)));
	fontmap.insert(pair<BYTE, pixeldata_s>('6', pixeldata_s(0x3c, 0x4a, 0x49, 0x49, 0x30)));
	fontmap.insert(pair<BYTE, pixeldata_s>('7', pixeldata_s(0x01, 0x71, 0x09, 0x05, 0x03)));
	fontmap.insert(pair<BYTE, pixeldata_s>('8', pixeldata_s(0x36, 0x49, 0x49, 0x49, 0x36)));
	fontmap.insert(pair<BYTE, pixeldata_s>('9', pixeldata_s(0x06, 0x49, 0x49, 0x29, 0x1e)));
	fontmap.insert(pair<BYTE, pixeldata_s>(':', pixeldata_s(0x00, 0x36, 0x36, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>(';', pixeldata_s(0x00, 0x56, 0x36, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('<', pixeldata_s(0x08, 0x14, 0x22, 0x41, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('=', pixeldata_s(0x14, 0x14, 0x14, 0x14, 0x14)));
	fontmap.insert(pair<BYTE, pixeldata_s>('>', pixeldata_s(0x00, 0x41, 0x22, 0x14, 0x08)));
	fontmap.insert(pair<BYTE, pixeldata_s>('?', pixeldata_s(0x02, 0x01, 0x51, 0x09, 0x06)));
	fontmap.insert(pair<BYTE, pixeldata_s>('@', pixeldata_s(0x32, 0x49, 0x79, 0x41, 0x3e)));
	fontmap.insert(pair<BYTE, pixeldata_s>('A', pixeldata_s(0x7e, 0x11, 0x11, 0x11, 0x7e)));
	fontmap.insert(pair<BYTE, pixeldata_s>('B', pixeldata_s(0x7f, 0x49, 0x49, 0x49, 0x36)));
	fontmap.insert(pair<BYTE, pixeldata_s>('C', pixeldata_s(0x3e, 0x41, 0x41, 0x41, 0x22)));
	fontmap.insert(pair<BYTE, pixeldata_s>('D', pixeldata_s(0x7f, 0x41, 0x41, 0x22, 0x1c)));
	fontmap.insert(pair<BYTE, pixeldata_s>('E', pixeldata_s(0x7f, 0x49, 0x49, 0x49, 0x41)));
	fontmap.insert(pair<BYTE, pixeldata_s>('F', pixeldata_s(0x7f, 0x09, 0x09, 0x09, 0x01)));
	fontmap.insert(pair<BYTE, pixeldata_s>('G', pixeldata_s(0x3e, 0x41, 0x49, 0x49, 0x7a)));
	fontmap.insert(pair<BYTE, pixeldata_s>('H', pixeldata_s(0x7f, 0x08, 0x08, 0x08, 0x7f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('I', pixeldata_s(0x00, 0x41, 0x7f, 0x41, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('J', pixeldata_s(0x20, 0x40, 0x41, 0x3f, 0x01))); 
	fontmap.insert(pair<BYTE, pixeldata_s>('K', pixeldata_s(0x7f, 0x08, 0x14, 0x22, 0x41)));
	fontmap.insert(pair<BYTE, pixeldata_s>('L', pixeldata_s(0x7f, 0x40, 0x40, 0x40, 0x40)));
	fontmap.insert(pair<BYTE, pixeldata_s>('M', pixeldata_s(0x7f, 0x02, 0x0c, 0x02, 0x7f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('N', pixeldata_s(0x7f, 0x04, 0x08, 0x10, 0x7f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('O', pixeldata_s(0x3e, 0x41, 0x41, 0x41, 0x3e)));
	fontmap.insert(pair<BYTE, pixeldata_s>('P', pixeldata_s(0x7f, 0x09, 0x09, 0x09, 0x06)));
	fontmap.insert(pair<BYTE, pixeldata_s>('Q', pixeldata_s(0x3e, 0x41, 0x51, 0x21, 0x5e)));
	fontmap.insert(pair<BYTE, pixeldata_s>('R', pixeldata_s(0x7f, 0x09, 0x19, 0x29, 0x46)));
	fontmap.insert(pair<BYTE, pixeldata_s>('S', pixeldata_s(0x46, 0x49, 0x49, 0x49, 0x31)));
	fontmap.insert(pair<BYTE, pixeldata_s>('T', pixeldata_s(0x01, 0x01, 0x7f, 0x01, 0x01)));
	fontmap.insert(pair<BYTE, pixeldata_s>('U', pixeldata_s(0x3f, 0x40, 0x40, 0x40, 0x3f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('V', pixeldata_s(0x1f, 0x20, 0x40, 0x20, 0x1f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('W', pixeldata_s(0x3f, 0x40, 0x38, 0x40, 0x3f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('X', pixeldata_s(0x63, 0x14, 0x08, 0x14, 0x63)));
	fontmap.insert(pair<BYTE, pixeldata_s>('Y', pixeldata_s(0x07, 0x08, 0x70, 0x08, 0x07)));
	fontmap.insert(pair<BYTE, pixeldata_s>('Z', pixeldata_s(0x61, 0x51, 0x49, 0x45, 0x43)));
	fontmap.insert(pair<BYTE, pixeldata_s>('[', pixeldata_s(0x00, 0x7f, 0x41, 0x41, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('\\',pixeldata_s(0x02, 0x04, 0x08, 0x10, 0x20)));
	fontmap.insert(pair<BYTE, pixeldata_s>(']', pixeldata_s(0x00, 0x41, 0x41, 0x7f, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('^', pixeldata_s(0x04, 0x02, 0x01, 0x02, 0x04)));
	fontmap.insert(pair<BYTE, pixeldata_s>('_', pixeldata_s(0x40, 0x40, 0x40, 0x40, 0x40)));
	fontmap.insert(pair<BYTE, pixeldata_s>('`', pixeldata_s(0x00, 0x01, 0x02, 0x04, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('a', pixeldata_s(0x20, 0x54, 0x54, 0x54, 0x78)));
	fontmap.insert(pair<BYTE, pixeldata_s>('b', pixeldata_s(0x7f, 0x48, 0x44, 0x44, 0x38)));
	fontmap.insert(pair<BYTE, pixeldata_s>('c', pixeldata_s(0x38, 0x44, 0x44, 0x44, 0x20)));
	fontmap.insert(pair<BYTE, pixeldata_s>('d', pixeldata_s(0x38, 0x44, 0x44, 0x48, 0x7f)));
	fontmap.insert(pair<BYTE, pixeldata_s>('e', pixeldata_s(0x38, 0x54, 0x54, 0x54, 0x18)));
	fontmap.insert(pair<BYTE, pixeldata_s>('f', pixeldata_s(0x08, 0x7e, 0x09, 0x01, 0x02)));
	fontmap.insert(pair<BYTE, pixeldata_s>('g', pixeldata_s(0x0c, 0x52, 0x52, 0x52, 0x3e)));
	fontmap.insert(pair<BYTE, pixeldata_s>('h', pixeldata_s(0x7f, 0x08, 0x04, 0x04, 0x78)));
	fontmap.insert(pair<BYTE, pixeldata_s>('i', pixeldata_s(0x00, 0x44, 0x7d, 0x40, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('j', pixeldata_s(0x20, 0x40, 0x44, 0x3d, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('k', pixeldata_s(0x7f, 0x10, 0x28, 0x44, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('l', pixeldata_s(0x00, 0x41, 0x7f, 0x40, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('m', pixeldata_s(0x7c, 0x04, 0x18, 0x04, 0x78)));
	fontmap.insert(pair<BYTE, pixeldata_s>('n', pixeldata_s(0x7c, 0x08, 0x04, 0x04, 0x78)));
	fontmap.insert(pair<BYTE, pixeldata_s>('o', pixeldata_s(0x38, 0x44, 0x44, 0x44, 0x38)));
	fontmap.insert(pair<BYTE, pixeldata_s>('p', pixeldata_s(0x7c, 0x14, 0x14, 0x14, 0x08)));
	fontmap.insert(pair<BYTE, pixeldata_s>('q', pixeldata_s(0x08, 0x14, 0x14, 0x18, 0x7c)));
	fontmap.insert(pair<BYTE, pixeldata_s>('r', pixeldata_s(0x7c, 0x08, 0x04, 0x04, 0x08)));
	fontmap.insert(pair<BYTE, pixeldata_s>('s', pixeldata_s(0x48, 0x54, 0x54, 0x54, 0x20)));
	fontmap.insert(pair<BYTE, pixeldata_s>('t', pixeldata_s(0x04, 0x3f, 0x44, 0x40, 0x20)));
	fontmap.insert(pair<BYTE, pixeldata_s>('u', pixeldata_s(0x3c, 0x40, 0x40, 0x20, 0x7c)));
	fontmap.insert(pair<BYTE, pixeldata_s>('v', pixeldata_s(0x1c, 0x20, 0x40, 0x20, 0x1c)));
	fontmap.insert(pair<BYTE, pixeldata_s>('w', pixeldata_s(0x3c, 0x40, 0x30, 0x40, 0x3c)));
	fontmap.insert(pair<BYTE, pixeldata_s>('x', pixeldata_s(0x44, 0x28, 0x10, 0x28, 0x44)));
	fontmap.insert(pair<BYTE, pixeldata_s>('y', pixeldata_s(0x0c, 0x50, 0x50, 0x50, 0x3c)));
	fontmap.insert(pair<BYTE, pixeldata_s>('z', pixeldata_s(0x44, 0x64, 0x54, 0x4c, 0x44)));
	fontmap.insert(pair<BYTE, pixeldata_s>('{', pixeldata_s(0x00, 0x08, 0x36, 0x41, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('|', pixeldata_s(0x00, 0x00, 0x7f, 0x00, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('}', pixeldata_s(0x00, 0x41, 0x36, 0x08, 0x00)));
	fontmap.insert(pair<BYTE, pixeldata_s>('~', pixeldata_s(0x10, 0x08, 0x08, 0x10, 0x08)));
	fontmap.insert(pair<BYTE, pixeldata_s>('\x7f', pixeldata_s(0x00, 0x7e, 0x42, 0x42, 0x7e)));
		
	// start wiring pi
	wiringPiSetup();

	// setup pins
	pinMode(DIN,  OUTPUT);
	pinMode(SCLK, OUTPUT);
	pinMode(DC,   OUTPUT);
	pinMode(RST,  OUTPUT);
	pinMode(SCE,  OUTPUT);

	pinMode(LED,  OUTPUT);
	
	// Toggle RST low to reset.	
	digitalWrite(SCE, OFF);
	digitalWrite(RST, OFF);
	digitalWrite(LED, ON);
	usleep(1000);
	digitalWrite(RST, ON);
	
	// Extended mode, bias, vop, basic mode, non-inverted display.
	BYTE initcmds[] = {0x21, 0x14, CONTRAST, 0x20, 0x0c };
	for(unsigned int i=0; i<5; i++)
		lcd_cmd(initcmds[i]);
		
	cls();

	// Init mpd connection
	obj = mpd_new("localhost", 6600, ""); 
	
	mpd_signal_connect_error(obj,(ErrorCallback)error_callback, NULL);
    mpd_signal_connect_status_changed(obj,(StatusChangedCallback)status_changed, NULL);
    
    mpd_set_connection_timeout(obj, 10); 
    
    int fdstdin = 0;
    fdstdin = open("/dev/stdin", O_NONBLOCK|O_RDONLY);
    
    bool run = true;
    
    if(!mpd_connect(obj))
    {
		mpd_send_password(obj);
		
		char buffer[20];
		
		do
		{
			memset(buffer, '\0', 20);
			
			if(read(fdstdin, buffer, 1) > 0)
			{
				switch(buffer[0])
				{
					case 'q':	run = false;
								break;
				}
			}
						
			if(song != NULL)
			{
				int posi 			= mpd_status_get_elapsed_song_time(obj);
								
				tm * ptmp		    = gmtime(&song->time);
				tm   length  		= *ptmp;
				
				ptmp				= gmtime(&posi);
				tm   pos	  		= *ptmp;
							
				char slength[20], spos[20];
				strftime(slength, 20, "%M:%S", &length);
				strftime(spos,    20, "%M:%S", &pos);			
				
				char lines[14*5];
				char display[6][15];
				
				if(songchanged)
				{
					songchanged = false;
					
					sprintf(lines, "%s\n%s", song->title, song->artist);
					unsigned int lang = strlen(lines);
					
					int row = 0, col = 0;
					
					memset(display, '\0', 6*15);
					
					for(unsigned int za=0; za<lang; za++)
					{
						if(lines[za] != '\n')
						{
							display[row][col] = lines[za];
							col++;
							
							if(col == 14)
							{
								col = 0;
								row++;
							}
						}
						else
						{
							row++;
							col=0;
						}
						
						if(row == 5) 
							break;
					}
				}
				
				sprintf(display[5], "%s / %s", spos, slength);
				
				// test output
				for(int row = 0; row<6; row++)
				{				
					gotoxy(0, row);
					text(display[row]);
                             
					for(int i=0; i<14-strlen(display[row]); i++)
						text(" ");
				}
			}
			
			int res = mpd_status_update(obj);
			if(res != 0)
				cout<<"mpd_status_update failed"<<endl;
									
			usleep(1000000);
		}
		while(run);
	}
	
	mpd_free(obj);
		
	return 0;
}

// ---------------------------------------------------------------------
Here the makefile which I use:

Code: Select all

CC=g++
CFLAGS=-c -Wall -I /usr/include/libmpd-1.0 -fpermissive
LDFLAGS=-L /usr/lib -l mpd -l wiringPi
SOURCES=main.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=mpc-test.exe

all: $(SOURCES) $(EXECUTABLE)
	
$(EXECUTABLE): $(OBJECTS) 
	$(CC) $(LDFLAGS) $(OBJECTS) -o [email protected]

.cpp.o:
	$(CC) $(CFLAGS) $< -o [email protected]
Here a photo of it in action:
Image

Much thanks to Texy for his support.

texy
Forum Moderator
Forum Moderator
Posts: 5160
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Nokia Pi LCD

Fri Feb 08, 2013 6:21 pm

That's cool!
I know very little of C++ - is it actually using hardware SPI ?

Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: Nokia Pi LCD

Fri Feb 08, 2013 6:55 pm

texy wrote:That's cool!
I know very little of C++ - is it actually using hardware SPI ?

Texy
It's banging the bits. :) It would be easy to convert to use hardware SPI though. ;) Maybe a weekend project for me...

Enjoy!
Bill

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: Nokia Pi LCD

Sat Feb 09, 2013 6:12 pm

Did a quick update to the C++ code posted above by Sector7CSD to use the spidev hardware interface. This is a quick hack and proof of concept and could use more/better error handling...

main.cpp:

Code: Select all

// main.cpp
// code by: Chris
// ---------------------------------------------------------------------

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <map>

// ---------------------------------------------------------------------

#include <sys/ioctl.h>
#include <stdint.h>
#include <linux/spi/spidev.h>

// ---------------------------------------------------------------------

#include "libmpd/libmpd.h"
#include "wiringPi.h"

// ---------------------------------------------------------------------

using namespace std;

// ---------------------------------------------------------------------

#define RED "\x1b[31;01m"
#define DARKRED "\x1b[31;06m"
#define RESET "\x1b[0m"
#define GREEN "\x1b[32;06m"
#define YELLOW "\x1b[33;06m"

// ---------------------------------------------------------------------

int spifd = -1;

MpdObj *    obj  = NULL;
mpd_Song *    song = NULL;
bool      songchanged = true;

// ---------------------------------------------------------------------

void error_callback(MpdObj *mi,int errorid, char *msg, void *userdata)
{
   printf(RED"Error "RESET""GREEN"%i:"RESET" '%s'\n", errorid, msg);
}

// ---------------------------------------------------------------------

void status_changed(MpdObj *mi, ChangedStatusType what)
{
   if(what&MPD_CST_SONGID)
    {
      song = mpd_playlist_get_current_song(mi);
      songchanged = true;
   }
}

// ---------------------------------------------------------------------

#define BYTE unsigned char

const int ROWS = 6;
const int COLUMNS = 14;
const int PIXELS_PER_ROW = 6;
const int ON = 1;
const int OFF = 0;
const int CONTRAST = 0xb6;

// SPI hardware pinout
#define SPI_CE0  10 // gpio pin 24 = wiringpi no. 10 (CE0 BCM 8)
#define SPI_CE1  11 // gpio pin 26 = wiringpi no. 11 (CE0 BCM 7)
#define SPI_SCLK 14 // gpio pin 23 = wiringpi no. 14 (SCLK BCM 11)
#define SPI_MOSI 12 // gpio pin 19 = wiringpi no. 12 (MOSI BCM 10)


// Using SPI hardware with CE0
const int SCE  = SPI_CE0;
const int SCLK = SPI_SCLK;
const int DIN  = SPI_MOSI;
const int DC   = 3;  // gpio pin 15 = wiringpi no. 3
const int RST  = 0;  // gpio pin 11 = wiringpi no. 0
const int LED  = 1;  // gpio pin 12 = wiringpi no. 1

   
// ---------------------------------------------------------------------

struct pixeldata_s
{
   BYTE data [6];
   pixeldata_s(BYTE b1, BYTE b2, BYTE b3, BYTE b4, BYTE b5)
   {
      data[0] = b1;
      data[1] = b2;
      data[2] = b3;
      data[3] = b4;
      data[4] = b5;
      data[5] = 0;  /* space between characters */
   }
};

map<BYTE, pixeldata_s> fontmap;

// ---------------------------------------------------------------------

void SPI(BYTE *data, int len)
{
  int c;

  if (spifd == -1) /* using software bit banging */
  {
    // data = DIN
    // clock = SCLK
    // MSB first
    for(c=0; c < len; c++)
    {
        for(unsigned int i=0; i<8; i++)
        {
          digitalWrite(DIN, (data[c] >> (7-i)) & 1);
          digitalWrite(SCLK, ON);    
          usleep(1);
          digitalWrite(SCLK, OFF);
          usleep(1);
        }
    }
  }
  else /* using hardware spidev */
  {
     struct spi_ioc_transfer tr;
     memset(&tr, 0, sizeof(tr));
     tr.tx_buf = (unsigned long)data;
     tr.rx_buf = 0;
     tr.len = len;

     ioctl(spifd, SPI_IOC_MESSAGE(1), &tr);
  }
}
    
// ---------------------------------------------------------------------

void lcd_cmd(BYTE *data, int len)
{
  digitalWrite(DC, OFF);
  SPI(data, len);
}

// ---------------------------------------------------------------------

void lcd_data(BYTE *data, int len)
{
  digitalWrite(DC, ON);
  SPI(data, len);
}

// ---------------------------------------------------------------------

void gotoxy(BYTE x, BYTE y)
{
   BYTE xy[] = {x+128, y+64};
   lcd_cmd(xy, 2);
}

// ---------------------------------------------------------------------

void cls()
{
  BYTE clrbuf[ROWS * COLUMNS * PIXELS_PER_ROW];
  memset(clrbuf, 0, ROWS * COLUMNS * PIXELS_PER_ROW);
  gotoxy(0, 0);
  lcd_data(clrbuf, ROWS * COLUMNS * PIXELS_PER_ROW);
}

// ---------------------------------------------------------------------

void display_char(BYTE c)
{
   map<BYTE, pixeldata_s>::iterator it = fontmap.find(c);
   if(it != fontmap.end())
   {
      pixeldata_s pix = it->second;
      lcd_data(pix.data, 6);
   }
}

// ---------------------------------------------------------------------

void text(char * string)
{
  for(unsigned int i=0; i<strlen(string); i++)
    display_char(string[i]);
}
   
static void init_fontmap()
{
   fontmap.insert(pair<BYTE, pixeldata_s>(' ', pixeldata_s(0x00, 0x00, 0x00, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('!', pixeldata_s(0x00, 0x07, 0x00, 0x07, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('"', pixeldata_s(0x14, 0x7f, 0x14, 0x7f, 0x14)));
   fontmap.insert(pair<BYTE, pixeldata_s>('$', pixeldata_s(0x24, 0x2a, 0x7f, 0x2a, 0x12)));
   fontmap.insert(pair<BYTE, pixeldata_s>('%', pixeldata_s(0x23, 0x13, 0x08, 0x64, 0x62)));
   fontmap.insert(pair<BYTE, pixeldata_s>('&', pixeldata_s(0x36, 0x49, 0x55, 0x22, 0x50)));
   fontmap.insert(pair<BYTE, pixeldata_s>('\'',pixeldata_s(0x00, 0x05, 0x03, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('(', pixeldata_s(0x00, 0x1c, 0x22, 0x41, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>(')', pixeldata_s(0x00, 0x41, 0x22, 0x1c, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('*', pixeldata_s(0x14, 0x08, 0x3e, 0x08, 0x14)));
   fontmap.insert(pair<BYTE, pixeldata_s>('+', pixeldata_s(0x08, 0x08, 0x3e, 0x08, 0x08)));
   fontmap.insert(pair<BYTE, pixeldata_s>(',', pixeldata_s(0x00, 0x50, 0x30, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('-', pixeldata_s(0x08, 0x08, 0x08, 0x08, 0x08)));
   fontmap.insert(pair<BYTE, pixeldata_s>('.', pixeldata_s(0x00, 0x60, 0x60, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('/', pixeldata_s(0x20, 0x10, 0x08, 0x04, 0x02)));
   fontmap.insert(pair<BYTE, pixeldata_s>('0', pixeldata_s(0x3e, 0x51, 0x49, 0x45, 0x3e)));
   fontmap.insert(pair<BYTE, pixeldata_s>('1', pixeldata_s(0x00, 0x42, 0x7f, 0x40, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('2', pixeldata_s(0x42, 0x61, 0x51, 0x49, 0x46)));
   fontmap.insert(pair<BYTE, pixeldata_s>('3', pixeldata_s(0x21, 0x41, 0x45, 0x4b, 0x31)));
   fontmap.insert(pair<BYTE, pixeldata_s>('4', pixeldata_s(0x18, 0x14, 0x12, 0x7f, 0x10)));
   fontmap.insert(pair<BYTE, pixeldata_s>('5', pixeldata_s(0x27, 0x45, 0x45, 0x45, 0x39)));
   fontmap.insert(pair<BYTE, pixeldata_s>('6', pixeldata_s(0x3c, 0x4a, 0x49, 0x49, 0x30)));
   fontmap.insert(pair<BYTE, pixeldata_s>('7', pixeldata_s(0x01, 0x71, 0x09, 0x05, 0x03)));
   fontmap.insert(pair<BYTE, pixeldata_s>('8', pixeldata_s(0x36, 0x49, 0x49, 0x49, 0x36)));
   fontmap.insert(pair<BYTE, pixeldata_s>('9', pixeldata_s(0x06, 0x49, 0x49, 0x29, 0x1e)));
   fontmap.insert(pair<BYTE, pixeldata_s>(':', pixeldata_s(0x00, 0x36, 0x36, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>(';', pixeldata_s(0x00, 0x56, 0x36, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('<', pixeldata_s(0x08, 0x14, 0x22, 0x41, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('=', pixeldata_s(0x14, 0x14, 0x14, 0x14, 0x14)));
   fontmap.insert(pair<BYTE, pixeldata_s>('>', pixeldata_s(0x00, 0x41, 0x22, 0x14, 0x08)));
   fontmap.insert(pair<BYTE, pixeldata_s>('?', pixeldata_s(0x02, 0x01, 0x51, 0x09, 0x06)));
   fontmap.insert(pair<BYTE, pixeldata_s>('@', pixeldata_s(0x32, 0x49, 0x79, 0x41, 0x3e)));
   fontmap.insert(pair<BYTE, pixeldata_s>('A', pixeldata_s(0x7e, 0x11, 0x11, 0x11, 0x7e)));
   fontmap.insert(pair<BYTE, pixeldata_s>('B', pixeldata_s(0x7f, 0x49, 0x49, 0x49, 0x36)));
   fontmap.insert(pair<BYTE, pixeldata_s>('C', pixeldata_s(0x3e, 0x41, 0x41, 0x41, 0x22)));
   fontmap.insert(pair<BYTE, pixeldata_s>('D', pixeldata_s(0x7f, 0x41, 0x41, 0x22, 0x1c)));
   fontmap.insert(pair<BYTE, pixeldata_s>('E', pixeldata_s(0x7f, 0x49, 0x49, 0x49, 0x41)));
   fontmap.insert(pair<BYTE, pixeldata_s>('F', pixeldata_s(0x7f, 0x09, 0x09, 0x09, 0x01)));
   fontmap.insert(pair<BYTE, pixeldata_s>('G', pixeldata_s(0x3e, 0x41, 0x49, 0x49, 0x7a)));
   fontmap.insert(pair<BYTE, pixeldata_s>('H', pixeldata_s(0x7f, 0x08, 0x08, 0x08, 0x7f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('I', pixeldata_s(0x00, 0x41, 0x7f, 0x41, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('J', pixeldata_s(0x20, 0x40, 0x41, 0x3f, 0x01))); 
   fontmap.insert(pair<BYTE, pixeldata_s>('K', pixeldata_s(0x7f, 0x08, 0x14, 0x22, 0x41)));
   fontmap.insert(pair<BYTE, pixeldata_s>('L', pixeldata_s(0x7f, 0x40, 0x40, 0x40, 0x40)));
   fontmap.insert(pair<BYTE, pixeldata_s>('M', pixeldata_s(0x7f, 0x02, 0x0c, 0x02, 0x7f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('N', pixeldata_s(0x7f, 0x04, 0x08, 0x10, 0x7f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('O', pixeldata_s(0x3e, 0x41, 0x41, 0x41, 0x3e)));
   fontmap.insert(pair<BYTE, pixeldata_s>('P', pixeldata_s(0x7f, 0x09, 0x09, 0x09, 0x06)));
   fontmap.insert(pair<BYTE, pixeldata_s>('Q', pixeldata_s(0x3e, 0x41, 0x51, 0x21, 0x5e)));
   fontmap.insert(pair<BYTE, pixeldata_s>('R', pixeldata_s(0x7f, 0x09, 0x19, 0x29, 0x46)));
   fontmap.insert(pair<BYTE, pixeldata_s>('S', pixeldata_s(0x46, 0x49, 0x49, 0x49, 0x31)));
   fontmap.insert(pair<BYTE, pixeldata_s>('T', pixeldata_s(0x01, 0x01, 0x7f, 0x01, 0x01)));
   fontmap.insert(pair<BYTE, pixeldata_s>('U', pixeldata_s(0x3f, 0x40, 0x40, 0x40, 0x3f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('V', pixeldata_s(0x1f, 0x20, 0x40, 0x20, 0x1f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('W', pixeldata_s(0x3f, 0x40, 0x38, 0x40, 0x3f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('X', pixeldata_s(0x63, 0x14, 0x08, 0x14, 0x63)));
   fontmap.insert(pair<BYTE, pixeldata_s>('Y', pixeldata_s(0x07, 0x08, 0x70, 0x08, 0x07)));
   fontmap.insert(pair<BYTE, pixeldata_s>('Z', pixeldata_s(0x61, 0x51, 0x49, 0x45, 0x43)));
   fontmap.insert(pair<BYTE, pixeldata_s>('[', pixeldata_s(0x00, 0x7f, 0x41, 0x41, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('\\',pixeldata_s(0x02, 0x04, 0x08, 0x10, 0x20)));
   fontmap.insert(pair<BYTE, pixeldata_s>(']', pixeldata_s(0x00, 0x41, 0x41, 0x7f, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('^', pixeldata_s(0x04, 0x02, 0x01, 0x02, 0x04)));
   fontmap.insert(pair<BYTE, pixeldata_s>('_', pixeldata_s(0x40, 0x40, 0x40, 0x40, 0x40)));
   fontmap.insert(pair<BYTE, pixeldata_s>('`', pixeldata_s(0x00, 0x01, 0x02, 0x04, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('a', pixeldata_s(0x20, 0x54, 0x54, 0x54, 0x78)));
   fontmap.insert(pair<BYTE, pixeldata_s>('b', pixeldata_s(0x7f, 0x48, 0x44, 0x44, 0x38)));
   fontmap.insert(pair<BYTE, pixeldata_s>('c', pixeldata_s(0x38, 0x44, 0x44, 0x44, 0x20)));
   fontmap.insert(pair<BYTE, pixeldata_s>('d', pixeldata_s(0x38, 0x44, 0x44, 0x48, 0x7f)));
   fontmap.insert(pair<BYTE, pixeldata_s>('e', pixeldata_s(0x38, 0x54, 0x54, 0x54, 0x18)));
   fontmap.insert(pair<BYTE, pixeldata_s>('f', pixeldata_s(0x08, 0x7e, 0x09, 0x01, 0x02)));
   fontmap.insert(pair<BYTE, pixeldata_s>('g', pixeldata_s(0x0c, 0x52, 0x52, 0x52, 0x3e)));
   fontmap.insert(pair<BYTE, pixeldata_s>('h', pixeldata_s(0x7f, 0x08, 0x04, 0x04, 0x78)));
   fontmap.insert(pair<BYTE, pixeldata_s>('i', pixeldata_s(0x00, 0x44, 0x7d, 0x40, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('j', pixeldata_s(0x20, 0x40, 0x44, 0x3d, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('k', pixeldata_s(0x7f, 0x10, 0x28, 0x44, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('l', pixeldata_s(0x00, 0x41, 0x7f, 0x40, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('m', pixeldata_s(0x7c, 0x04, 0x18, 0x04, 0x78)));
   fontmap.insert(pair<BYTE, pixeldata_s>('n', pixeldata_s(0x7c, 0x08, 0x04, 0x04, 0x78)));
   fontmap.insert(pair<BYTE, pixeldata_s>('o', pixeldata_s(0x38, 0x44, 0x44, 0x44, 0x38)));
   fontmap.insert(pair<BYTE, pixeldata_s>('p', pixeldata_s(0x7c, 0x14, 0x14, 0x14, 0x08)));
   fontmap.insert(pair<BYTE, pixeldata_s>('q', pixeldata_s(0x08, 0x14, 0x14, 0x18, 0x7c)));
   fontmap.insert(pair<BYTE, pixeldata_s>('r', pixeldata_s(0x7c, 0x08, 0x04, 0x04, 0x08)));
   fontmap.insert(pair<BYTE, pixeldata_s>('s', pixeldata_s(0x48, 0x54, 0x54, 0x54, 0x20)));
   fontmap.insert(pair<BYTE, pixeldata_s>('t', pixeldata_s(0x04, 0x3f, 0x44, 0x40, 0x20)));
   fontmap.insert(pair<BYTE, pixeldata_s>('u', pixeldata_s(0x3c, 0x40, 0x40, 0x20, 0x7c)));
   fontmap.insert(pair<BYTE, pixeldata_s>('v', pixeldata_s(0x1c, 0x20, 0x40, 0x20, 0x1c)));
   fontmap.insert(pair<BYTE, pixeldata_s>('w', pixeldata_s(0x3c, 0x40, 0x30, 0x40, 0x3c)));
   fontmap.insert(pair<BYTE, pixeldata_s>('x', pixeldata_s(0x44, 0x28, 0x10, 0x28, 0x44)));
   fontmap.insert(pair<BYTE, pixeldata_s>('y', pixeldata_s(0x0c, 0x50, 0x50, 0x50, 0x3c)));
   fontmap.insert(pair<BYTE, pixeldata_s>('z', pixeldata_s(0x44, 0x64, 0x54, 0x4c, 0x44)));
   fontmap.insert(pair<BYTE, pixeldata_s>('{', pixeldata_s(0x00, 0x08, 0x36, 0x41, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('|', pixeldata_s(0x00, 0x00, 0x7f, 0x00, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('}', pixeldata_s(0x00, 0x41, 0x36, 0x08, 0x00)));
   fontmap.insert(pair<BYTE, pixeldata_s>('~', pixeldata_s(0x10, 0x08, 0x08, 0x10, 0x08)));
   fontmap.insert(pair<BYTE, pixeldata_s>('\x7f', pixeldata_s(0x00, 0x7e, 0x42, 0x42, 0x7e)));
}

// ---------------------------------------------------------------------

int main()
{
    init_fontmap();

   // start wiring pi
   wiringPiSetup();

   // setup pins
   pinMode(DC,   OUTPUT);
   pinMode(RST,  OUTPUT);

   // If all of the pins are not assigned to hardware SPI, assume bit banged interface
   if (DIN != SPI_MOSI || SCLK != SPI_SCLK || (SCE != SPI_CE0 && SCE != SPI_CE1))
   {
       printf("Bit bang mode\n");
       pinMode(SCE,  OUTPUT);
       pinMode(DIN,  OUTPUT);
       pinMode(SCLK, OUTPUT);
   }
   else
   {
       char spipath[64];
       uint8_t mode = SPI_MODE_0;
       uint8_t bits = 8;
       uint32_t speed = 4000000;

       sprintf(spipath, "/dev/spidev0.%d", SCE==SPI_CE0?0:1);
       printf("spidev:%s\n", spipath);
       spifd = open(spipath, O_RDWR);
       if (spifd < 0)
       {
          perror(spipath);
          return(1);
       }
       ioctl(spifd, SPI_IOC_WR_MODE, &mode);
       ioctl(spifd, SPI_IOC_RD_MODE, &mode);
       ioctl(spifd, SPI_IOC_WR_BITS_PER_WORD, &bits);
       ioctl(spifd, SPI_IOC_RD_BITS_PER_WORD, &bits);
       ioctl(spifd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
       ioctl(spifd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
       printf("  mode: %d\n", mode);
       printf("  bits: %d\n", bits);
       printf(" speed: %d\n", speed);

   }

   pinMode(LED,  OUTPUT);
   
   // Toggle RST low to reset.   
   digitalWrite(SCE, OFF);
   digitalWrite(RST, OFF);
   digitalWrite(LED, ON);
   usleep(1000);
   digitalWrite(RST, ON);
   
   // Extended mode, bias, vop, basic mode, non-inverted display.
   BYTE initcmds[] = {0x21, 0x14, CONTRAST, 0x20, 0x0c };
   lcd_cmd(initcmds, 5);
      
   cls();

   // Init mpd connection
   obj = mpd_new((char*)"localhost", 6600, (char*)""); 
   
   mpd_signal_connect_error(obj,(ErrorCallback)error_callback, NULL);
    mpd_signal_connect_status_changed(obj,(StatusChangedCallback)status_changed, NULL);
    
    mpd_set_connection_timeout(obj, 10); 
    
    int fdstdin = 0;
    fdstdin = open("/dev/stdin", O_NONBLOCK|O_RDONLY);
    
    bool run = true;
    
    if(!mpd_connect(obj))
    {
      mpd_send_password(obj);
      
      char buffer[20];
      
      do
      {
         memset(buffer, '\0', 20);
         
         if(read(fdstdin, buffer, 1) > 0)
         {
            switch(buffer[0])
            {
               case 'q':   run = false;
                        break;
            }
         }
                  
         if(song != NULL)
         {
            time_t posi          = mpd_status_get_elapsed_song_time(obj);
                        
            tm * ptmp          = gmtime((time_t *)&song->time);
            tm   length        = *ptmp;
            
            ptmp            = gmtime(&posi);
            tm   pos           = *ptmp;
                     
            char slength[20], spos[20];
            strftime(slength, 20, "%M:%S", &length);
            strftime(spos,    20, "%M:%S", &pos);         
            
            char lines[14*5];
            char display[6][15];
            char *blankline=(char*)"              ";
            
            if(songchanged)
            {
               songchanged = false;
               
               sprintf(lines, "%s\n%s", song->title, song->artist);
               unsigned int lang = strlen(lines);
               
               int row = 0, col = 0;
               
               memset(display, '\0', 6*15);
               
               for(unsigned int za=0; za<lang; za++)
               {
                  if(lines[za] != '\n')
                  {
                     display[row][col] = lines[za];
                     col++;
                     
                     if(col == 14)
                     {
                        col = 0;
                        row++;
                     }
                  }
                  else
                  {
                     row++;
                     col=0;
                  }
                  
                  if(row == 5) 
                     break;
               }
            }
            
            sprintf(display[5], "%s / %s", spos, slength);
            
            // test output
            for(int row = 0; row<6; row++)
            {            
               gotoxy(0, row);
               text(display[row]);
                             
#if 0
               for(unsigned int i=0; i<14-strlen(display[row]); i++)
                  text((char*)" ");
#else
               text(&blankline[strlen(display[row])]);
#endif
            }
         }
         
         int res = mpd_status_update(obj);
         if(res != 0)
            cout<<"mpd_status_update failed"<<endl;
                           
         usleep(500000);
      }
      while(run);
   }

   mpd_free(obj);
      
   if (spifd >= 0)
      close(spifd);

   return 0;
}

// ---------------------------------------------------------------------
If the display pin assignments are on the Raspberry Pi SPI pins, the code will use the hardware SPI. If not, it reverts to the bit-bang SPI mode. There are also some minor code changes to make the interface with the hardware SPI simpler.

Enjoy!
Bill

User avatar
davef21370
Posts: 897
Joined: Fri Sep 21, 2012 4:13 pm
Location: Earth But Not Grounded

Re: Nokia Pi LCD

Sat Feb 09, 2013 6:57 pm

Sector7CSD, nice pic but don't power the Pi up on an anti-static bag, they're slightly conductive and can cause obvious problems.

Dave.
Apple say... Monkey do !!

videobuff
Posts: 7
Joined: Sun Feb 10, 2013 4:05 pm
Location: Hengelo - Netherlands
Contact: Website

Re: Nokia Pi LCD

Sun Feb 10, 2013 4:11 pm

I"d love to order one, but can't get hang of how to send a pm to you...

texy
Forum Moderator
Forum Moderator
Posts: 5160
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Nokia Pi LCD

Sun Feb 10, 2013 6:12 pm

Hi, and welcome to the forum.
Your first post needs moderator approval, and you can't send a pm until this has happened. You are all set now, and should be able to pm.
Rgds,
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
MartP
Posts: 12
Joined: Sat Jan 26, 2013 10:39 pm
Location: Hertfordshire, UK

Re: Nokia Pi LCD

Tue Feb 12, 2013 12:09 pm

Hi,
Used texy's great little LCD display plus totally plagerised, horribly "noob" mangled (by me) code from the forum, mostly bgreat's NokiaSPI class, and now the little beaut shows Eth / Wifi IPs, CPU speed / temp, freespace, up-time and temperature from two external Dallas DS18B20 sensors, plus a couple of bitmaps for good measure. I'm well pleased, and the Grandchildren are suitably impressed with Granddad's efforts :roll:
Thanks guys.
Martin

PS: onward and upward to the next project......... ;)

User avatar
bgreat
Posts: 235
Joined: Mon Jan 23, 2012 2:09 pm

Re: Nokia Pi LCD

Tue Feb 12, 2013 1:52 pm

Grandpa's Rule! :D

Enjoy!
Bill

User avatar
MartP
Posts: 12
Joined: Sat Jan 26, 2013 10:39 pm
Location: Hertfordshire, UK

Re: Nokia Pi LCD

Tue Feb 12, 2013 3:00 pm

Bill,
Thanks :)
Here's a pic -
Image

Note to texy - warranty voided :shock:

Martin

texy
Forum Moderator
Forum Moderator
Posts: 5160
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Nokia Pi LCD

Tue Feb 12, 2013 8:52 pm

Martin I think that deserves a thread in its own. If you could show everything step by step, or at least the software, that'll be cool.
Cheers Texy.
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
MartP
Posts: 12
Joined: Sat Jan 26, 2013 10:39 pm
Location: Hertfordshire, UK

Re: Nokia Pi LCD

Thu Feb 14, 2013 8:37 pm

texy wrote:Martin I think that deserves a thread in its own. If you could show everything step by step, or at least the software, that'll be cool.
Cheers Texy.
Ooooo! Now that wouldn't be pretty - the code is, I feel sure, horrible. Plagerised and mangled as it is by me. But I'll have a go; we have some building work starting on the house imminently, but I'll see what I can do :oops:
Martin

sportsnapper
Posts: 69
Joined: Wed Sep 05, 2012 11:27 am

Re: Nokia Pi LCD

Fri Feb 15, 2013 10:26 am

Well, success, I've got this working using the nokia_spi code. Thanks to Bill.

Pic attached - I used the Quick2wire interface board, and hooked up their spi interface to the Nokia, as well as using the gpio pins, which handily have the same pin assignment as Gordon's wiringPi library.

A question though - I've uncommented the PWN backlight part of the code, and run it - but can't see anything happen. I think I need a transistor in there somewhere, but not exactly sure where - and can it be any type. Any advice much appreciated.
Attachments
photo 2.jpg
Quick2wire interface board with Nokia LCD
photo 2.jpg (62.14 KiB) Viewed 5024 times

texy
Forum Moderator
Forum Moderator
Posts: 5160
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: Nokia Pi LCD

Fri Feb 15, 2013 11:01 am

Hi,
I use 2N7000 MOSFET , the line needs to be pulled low. To prove it you could just wire it to GND temporarily.
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

sportsnapper
Posts: 69
Joined: Wed Sep 05, 2012 11:27 am

Re: Nokia Pi LCD

Fri Feb 15, 2013 11:18 am

Mmm, tried wiring it to ground, nothing happened, then can't get the original config to work.

Now I've realised I tied it to 3.3v rather than ground - so assume I've fried the LCD? :roll:

update - even worse I think. In my haste (not good for electronics) I actually put 3.3 v through the CE line - so now though I can get the backlight to work (tied to ground, properly) The LCD won't display anything. Opps.

Return to “Python”