Today's little project was driving a Nokia 5110 LCD with the Black Pill board. The 5110 phone was introduced in 1998. The display is monochrome and resolution is 84 x 48 pixels. Pretty savage by today's standards. But they're cheap and easy to drive. Good for microcontroller projects.

I had some old bitbang code from the PyBoard that worked fine after changing the pin definitions. Way too easy - hardly a project at all. But it was quite slow and I wasn't happy.

So I rewired for hardware SPI, made some changes in the code and tested. No go. Look carefully and find I have SCK and MOSI reversed. Try again. Nothing. Check everything. I had forgotten to change my pin definitions. Try again. Nothing. SPI polarity is 1 - should be 0 for this device. Try again. Success! Still not terribly fast. I bump baud rate up from 400000 to 4000000. Try again. That's more like it. Still not speedy, but not too bad. Now that's a project!

Hardware SPI source code. Nothin fancy - just a simple demo. (Scroll way down for software SPI source)
# ghmicro.com
# Nokia 5110 LCD - hardware SPI

from pyb import SPI, Pin

spi = SPI(1, SPI.MASTER, baudrate=4000000, polarity=0, phase=0)
RST = Pin('A2',Pin.OUT_PP)
SCE = Pin('A1',Pin.OUT_PP)
DC = Pin('A3',Pin.OUT_PP)

#ascii font - Space 32 ($20) thru DEL 127 ($7f)
Alpha1 = [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,0x3e,0x51,0x49,0x45,0x3e,0x00,0x42,0x7f,0x40,0x00,0x42,0x61,0x51,0x49,0x46,0x21,0x41,0x45,0x4b,0x31,0x18,0x14,0x12,0x7f,0x10,0x27,0x45,0x45,0x45,0x39,0x3c,0x4a,0x49,0x49,0x30,0x01,0x71,0x09,0x05,0x03,0x36,0x49,0x49,0x49,0x36,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,0x7e,0x11,0x11,0x11,0x7e,0x7f,0x49,0x49,0x49,0x36,0x3e,0x41,0x41,0x41,0x22,0x7f,0x41,0x41,0x22,0x1c,0x7f,0x49,0x49,0x49,0x41,0x7f,0x09,0x09,0x09,0x01,0x3e,0x41,0x49,0x49,0x7a,0x7f,0x08,0x08,0x08,0x7f,0x00,0x41,0x7f,0x41,0x00,0x20,0x40,0x41,0x3f,0x01,0x7f,0x08,0x14,0x22,0x41,0x7f,0x40,0x40,0x40,0x40,0x7f,0x02,0x0c,0x02,0x7f,0x7f,0x04,0x08,0x10,0x7f,0x3e,0x41,0x41,0x41,0x3e,0x7f,0x09,0x09,0x09,0x06,0x3e,0x41,0x51,0x21,0x5e,0x7f,0x09,0x19,0x29,0x46,0x46,0x49,0x49,0x49,0x31,0x01,0x01,0x7f,0x01,0x01,0x3f,0x40,0x40,0x40,0x3f,0x1f,0x20,0x40,0x20,0x1f,0x3f,0x40,0x38,0x40,0x3f,0x63,0x14,0x08,0x14,0x63,0x07,0x08,0x70,0x08,0x07,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,0x20,0x54,0x54,0x54,0x78,0x7f,0x48,0x44,0x44,0x38,0x38,0x44,0x44,0x44,0x20,0x38,0x44,0x44,0x48,0x7f,0x38,0x54,0x54,0x54,0x18,0x08,0x7e,0x09,0x01,0x02,0x0c,0x52,0x52,0x52,0x3e,0x7f,0x08,0x04,0x04,0x78,0x00,0x44,0x7d,0x40,0x00,0x20,0x40,0x44,0x3d,0x00,0x7f,0x10,0x28,0x44,0x00,0x00,0x41,0x7f,0x40,0x00,0x7c,0x04,0x18,0x04,0x78,0x7c,0x08,0x04,0x04,0x78,0x38,0x44,0x44,0x44,0x38,0x7c,0x14,0x14,0x14,0x08,0x08,0x14,0x14,0x18,0x7c,0x7c,0x08,0x04,0x04,0x08,0x48,0x54,0x54,0x54,0x20,0x04,0x3f,0x44,0x40,0x20,0x3c,0x40,0x40,0x20,0x7c,0x1c,0x20,0x40,0x20,0x1c,0x3c,0x40,0x30,0x40,0x3c,0x44,0x28,0x10,0x28,0x44,0x0c,0x50,0x50,0x50,0x3c,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,0x78,0x46,0x41,0x46,0x78]

buff = [0] * 505

def update():
    lcd_send(0x40,0)    #y address
    lcd_send(0x80,0)    #x address
    for i in range(504):
        lcd_send(buff[i],1)

def box(x1,y1,x2,y2,color):
    for y in range(y1,y2):
        for x in range(x1,x2):
            pixel(x,y,color)
    update()

def pixel(x,y,color):
    mbit = 1
    offset = ((y >> 3) * 84) + x
    mbit = mbit << (y - ((y >> 3) << 3))
    temp = buff[offset]
    if color == 0:
        mask = mbit ^ 0xff
        buff[offset] = temp & mask
    else:
        buff[offset] = temp | mbit

def lcd_string(str,row):    #row must be 0-5
    lcd_send(0x40 + row,0)  #y address
    lcd_send(0x80,0)        #x address
    for x in range(len(str)):
        letter = ord(str[x]) - 0x20
        for col in range(5):
            lcd_send(Alpha1[(letter*5)+col],1)
        lcd_send(0,1)

def lcd_send(cmd,type):
    if type:
        DC.high()
    else:
        DC.low()
    SCE.low()
    spi.send(cmd)
    SCE.high()

def lcd_cls(patt):
    for i in range(504):
        buff[i] = patt
    update()

def lcd_init():
    pyb.delay(15)
    RST.low()
    pyb.delay(20)
    RST.high()
    lcd_send(0x21,0)        #extended instructions enabled
    lcd_send(0xb0,0)        #set vop (contrast) 0-127
    lcd_send(0x04,0)        #set temp coefficient
    lcd_send(0x13,0)        #lcd bias mode 1:48 (try 0x13)
    lcd_send(0x20,0)
    lcd_send(0x0c,0)        #display control - normal mode
    lcd_cls(0)

#------------------------------------------------------
# Begin here
#------------------------------------------------------

SCE.high()
RST.high()
lcd_init()
x = 0; y = 0; px = 0; py = 0
dx = 1;dy = 1

lcd_string("Nokia 5110",0)
lcd_string("Coded by futz",1)
lcd_string("             ",2)
lcd_string("Powered by   ",3)
lcd_string("MicroPython  ",4)
lcd_string("0123456789   ",5)
pyb.delay(5000)

while True:
    update()
    box(x,y,x + 4,y + 3,1)
    box(px,py,px + 4,py + 3,0)
    px = x; py = y
    x += dx; y += dy
    if x < 0 or x > 79:
        dx = -dx
        x = px
        x += dx
    if y < 0 or y > 44:
        dy = -dy
        y = py
        y += dy
Software SPI source code. Nothin fancy - just a simple demo.
# ghmicro.com
# Nokia 5110 LCD - software SPI

from pyb import Pin

RST = Pin('A4',Pin.OUT_PP)
SCE = Pin('A3',Pin.OUT_PP)
DC = Pin('A5',Pin.OUT_PP)
DATA = Pin('A6',Pin.OUT_PP)
SCLK = Pin('A7',Pin.OUT_PP)

#ascii font - Space 32 ($20) thru DEL 127 ($7f)
Alpha1 = [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,0x3e,0x51,0x49,0x45,0x3e,0x00,0x42,0x7f,0x40,0x00,0x42,0x61,0x51,0x49,0x46,0x21,0x41,0x45,0x4b,0x31,0x18,0x14,0x12,0x7f,0x10,0x27,0x45,0x45,0x45,0x39,0x3c,0x4a,0x49,0x49,0x30,0x01,0x71,0x09,0x05,0x03,0x36,0x49,0x49,0x49,0x36,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,0x7e,0x11,0x11,0x11,0x7e,0x7f,0x49,0x49,0x49,0x36,0x3e,0x41,0x41,0x41,0x22,0x7f,0x41,0x41,0x22,0x1c,0x7f,0x49,0x49,0x49,0x41,0x7f,0x09,0x09,0x09,0x01,0x3e,0x41,0x49,0x49,0x7a,0x7f,0x08,0x08,0x08,0x7f,0x00,0x41,0x7f,0x41,0x00,0x20,0x40,0x41,0x3f,0x01,0x7f,0x08,0x14,0x22,0x41,0x7f,0x40,0x40,0x40,0x40,0x7f,0x02,0x0c,0x02,0x7f,0x7f,0x04,0x08,0x10,0x7f,0x3e,0x41,0x41,0x41,0x3e,0x7f,0x09,0x09,0x09,0x06,0x3e,0x41,0x51,0x21,0x5e,0x7f,0x09,0x19,0x29,0x46,0x46,0x49,0x49,0x49,0x31,0x01,0x01,0x7f,0x01,0x01,0x3f,0x40,0x40,0x40,0x3f,0x1f,0x20,0x40,0x20,0x1f,0x3f,0x40,0x38,0x40,0x3f,0x63,0x14,0x08,0x14,0x63,0x07,0x08,0x70,0x08,0x07,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,0x20,0x54,0x54,0x54,0x78,0x7f,0x48,0x44,0x44,0x38,0x38,0x44,0x44,0x44,0x20,0x38,0x44,0x44,0x48,0x7f,0x38,0x54,0x54,0x54,0x18,0x08,0x7e,0x09,0x01,0x02,0x0c,0x52,0x52,0x52,0x3e,0x7f,0x08,0x04,0x04,0x78,0x00,0x44,0x7d,0x40,0x00,0x20,0x40,0x44,0x3d,0x00,0x7f,0x10,0x28,0x44,0x00,0x00,0x41,0x7f,0x40,0x00,0x7c,0x04,0x18,0x04,0x78,0x7c,0x08,0x04,0x04,0x78,0x38,0x44,0x44,0x44,0x38,0x7c,0x14,0x14,0x14,0x08,0x08,0x14,0x14,0x18,0x7c,0x7c,0x08,0x04,0x04,0x08,0x48,0x54,0x54,0x54,0x20,0x04,0x3f,0x44,0x40,0x20,0x3c,0x40,0x40,0x20,0x7c,0x1c,0x20,0x40,0x20,0x1c,0x3c,0x40,0x30,0x40,0x3c,0x44,0x28,0x10,0x28,0x44,0x0c,0x50,0x50,0x50,0x3c,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,0x78,0x46,0x41,0x46,0x78]

buff = [0] * 505

def update():
    lcd_send(0x40,0)    #y address
    lcd_send(0x80,0)    #x address
    for i in range(504):
        lcd_send(buff[i],1)

def box(x1,y1,x2,y2,color):
    for y in range(y1,y2):
        for x in range(x1,x2):
            pixel(x,y,color)
    update()

def pixel(x,y,color):
    mbit = 1
    offset = ((y >> 3) * 84) + x
    mbit = mbit << (y - ((y >> 3) << 3))
    temp = buff[offset]
    if color == 0:
        mask = mbit ^ 0xff
        buff[offset] = temp & mask
    else:
        buff[offset] = temp | mbit

def lcd_string(str,row):    #row must be 0-5
    lcd_send(0x40 + row,0)  #y address
    lcd_send(0x80,0)        #x address
    for x in range(len(str)):
        letter = ord(str[x]) - 0x20
        for col in range(5):
            lcd_send(Alpha1[(letter*5)+col],1)
        lcd_send(0,1)

def lcd_send(cmd,type):
    if type:
        DC.high()
    else:
        DC.low()
    SCE.low()
    for x in range(8):
        SCLK.low()
        DATA.low()
        if cmd & 0x80:
            DATA.high()
        SCLK.high()
        cmd = cmd << 1
    SCE.high()

def lcd_cls(patt):
    for i in range(504):
        buff[i] = patt
    update()

def lcd_init():
    pyb.delay(15)
    RST.low()
    pyb.delay(20)
    RST.high()
    lcd_send(0x21,0)        #extended instructions enabled
    lcd_send(0xb0,0)        #set vop (contrast) 0-127
    lcd_send(0x04,0)        #set temp coefficient
    lcd_send(0x13,0)        #lcd bias mode 1:48 (try 0x13)
    lcd_send(0x20,0)
    lcd_send(0x0c,0)        #display control - normal mode
    lcd_cls(0)

#------------------------------------------------------
# Begin here
#------------------------------------------------------

SCE.high()
SCLK.low()
RST.high()
lcd_init()
x = 0; y = 0; px = 0; py = 0
dx = 1;dy = 1

lcd_string("Nokia 5110",0)
lcd_string("Coded by futz",1)
lcd_string("             ",2)
lcd_string("Powered by   ",3)
lcd_string("MicroPython  ",4)
lcd_string("0123456789   ",5)
pyb.delay(5000)

while True:
    update()
#    pixel(px,py,0)
    pixel(x,y,1)
#    box(px,py,px + 4,py + 3,0)
#    box(x,y,x + 4,y + 3,1)
    px = x; py = y
    x += dx; y += dy
    if x < 0 or x > 83:
        dx = -dx
        x = px
        x += dx
    if y < 0 or y > 47:
        dy = -dy
        y = py
        y += dy

Next Post Previous Post