0
It's one small step for (a) man.....
....one giant leap for Nokia 6610 colour LCD display boards!
Armed with little more than a Phillips PCF8833 datasheet and some Arduino code libraries, excitement reigned around Nerd Towers today, as this little colour LCD Arduino shield flickered into life.
The screen uses SPI to send byte commands to the screen.
After initialising the screen, data is written using the following format:
First a "window" is defined, by providing start-x, end-x, start-y and end-y co-ordinates (0-131). Then, a stream of data is sent, with (in 8-bit mode) each byte representing a pixel colour.
You can define how the screen behaves after each pixel-byte is received. I set my display up to draw pixels from top-to-bottom. When the current pixel reaches the bottom of the defined window size, it increases the column counter and returns to the top of the window
Unlike most serially-driven devices, the Nokia 6610 display uses 9-bits NOT 8 to transfer data to the screen. The first bit tells the display whether the following byte is a command (first bit is zero) or some data (first bit is set).
Although Oshonsoft includes built-in software driven SPI routines, I decided to write my own (using the ones in the Arduino library as a base) which send 9-bits in a continuous stream. Because Oshonsoft Basic is so simple to understand, this implementation could be easily ported to a compiler of your choice. The full code listing follows. Below is a summary of how to use the device:
Creating a window:
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2A (command to set the column/x co-ord)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send the x-start value as a byte (0-131)
Send the x-end value as a byte (0-131, must be greater than x-start)
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2B (command to set the column/y co-ord)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send the y-start value as a byte (0-131)
Send the y-end value as a byte (0-131, must be greater than y-start)
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2C (command to start writing pixel data)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send each pixel colour as a byte (assuming 8-bit colour mode)
Repeat for each pixel in the window
Here's the full code for a working PIC project:
Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x3e
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x83
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40
UsbSetVendorId 0x1221
UsbSetProductId 0x1003
UsbSetVersionNumber 0x1122
UsbSetManufacturerString "www.nerdclub.co.uk"
UsbSetProductString "Usb-to-SPI device"
UsbSetSerialNumberString "1111111111"
UsbOnIoInGosub usbonioin
UsbOnIoOutGosub usbonioout
UsbOnFtInGosub usbonftin
UsbOnFtOutGosub usbonftout
AllDigital
Symbol glcd_bl = PORTB.5
Symbol glcd_rst = PORTB.4
Symbol glcd_cs = PORTB.3
Symbol glcd_sda = PORTB.2
Symbol glcd_miso = PORTB.1
Symbol glcd_sck = PORTB.0
Symbol led = PORTA.0
Define SPI_SCK_REG = PORTB 'defines the port where sck line is connected To
Define SPI_SCK_BIT = 0 'defines the pin where sck line is connected To
Define SPI_SDO_REG = PORTB 'defines the port where sdo line is connected To
Define SPI_SDO_BIT = 1 'defines the pin where sdo line is connected To
Define SPI_SDI_REG = PORTB 'defines the port where sdi line is connected To
Define SPI_SDI_BIT = 2 'defines the pin where sdi line is connected To
Define SPI_CS_REG = PORTB 'defines the port where cs line is connected To
Define SPI_CS_BIT = 3 'defines the pin where cs line is connected To
'SDO is not used - but is mapped to MISO on the display
'(serial data out on the MCU to serial data out on the lcd)
Dim spibyte As Byte 'a byte to send to the lcd
Dim spibit As Bit 'first bit is 0=command, 1=data
Dim spiclockdelay As Byte 'how long to wait between spi clock pulses
Dim spiclockus As Bit 'whether clock pulse delay is us or ms
Dim xs As Byte 'x co-ord to start bitmap from
Dim ys As Byte 'y co-ord to start bitmap from
Dim xe As Byte 'x co-ord to draw up to
Dim ye As Byte 'y co-ord to draw up to
Dim i As Byte '}
Dim j As Byte '} general variables
Dim k As Byte '}
init:
spiclockus = 1
spiclockdelay = 4
'drive an LED high so we can see what's going on
High led
Gosub lcdinitialise
'drive the led low
Low led
UsbStart
UsbService
loop:
UsbService
Goto loop
End
sendspi9bits:
'--------------------------------------------------------
'FROM THE NOKIA DATASHEET
'the serial interface is
'initialized when SCE is High. In this state, SCLK pulses
'have no effect And no power is consumed by the serial
'interface. A falling edge On pin sce enables the serial
'interface And indicates the start of data transmission.
'--------------------------------------------------------
'flash the led high
High led
Low glcd_sda
'drive the cs low
Low glcd_cs
Gosub spidelay
'first send the init bit, for either command or data
If spibit = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
'now clock 8 bits from the spibyte value starting with bit 7
If spibyte.7 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.6 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.5 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.4 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.3 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.2 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.1 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.0 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
'bring cs high to indicate end of transmission
High glcd_cs
Gosub spidelay
'flash the led off
Low led
Return
toggleclockpin:
'take the clock pin high, wait a second, drive it low
Gosub spidelay
Low glcd_sck
Gosub spidelay
High glcd_sck
Return
spidelay:
If spiclockus = 1 Then
WaitUs spiclockdelay
Else
WaitMs spiclockdelay
Endif
Return
lcdinitialise:
'this is taken from teh pcf8833.c file: Arduino library
'turn on the backlight
High glcd_bl
WaitMs 1
'send a dummy data byte
spibyte = 0 'all zeros is interpreted as NOP in the display chip
Gosub sendcommand
'send software reset command
spibyte = 0x01
Gosub sendcommand
WaitMs 10
spibyte = 0x11 'sleepout
Gosub sendcommand
spibyte = 0x36 'memory access control
Gosub sendcommand
'when a bitmap is drawn to screen, you give a start x, start y
'and end x and end y co-ordinate. Then drawing can go from left-to-right,
'up-and-down, or up-and-down, wrapping round to move the pixel left-to-right.
'For our fonts and so on, we draw each pixel top to bottom, then
'when we get to the bottom of the column of data, move left to right
'This is called vertical addressing mode.
spibyte = 0xe0 'memory access options:
'1 - my mx v lao rgb x x x
'my=mirror in Y, mx=mirror in x, V=vertical addressing,
'lao=line address order, rgb= colour order rgb/bgr
'e0 came from the Arduino library and is 11100000b
Gosub senddata 'note: data, not command
spibyte = 0x25 'set contrast
Gosub sendcommand
spibyte = 0x40 'contrast value
Gosub senddata 'note: data=contrast value, not a command!
WaitMs 10 'allow things to stablise
spibyte = 0x3a 'set colour mode
Gosub sendcommand
spibyte = 0x02 'xxxxx010 = 8-bit colour
Gosub senddata 'note: data=colour mode value, not a command
spibyte = 0x00 'dummy command - dunno why, but it's in the C library!
Gosub sendcommand
Gosub clearscreen
Return
createwindow:
spibyte = 0x2a 'set x start and end co-ordinates
Gosub sendcommand
spibyte = xs
Gosub senddata
spibyte = xe
Gosub senddata
spibyte = 0x2b 'set y start and end co-ordinates
Gosub sendcommand
spibyte = ys
Gosub senddata
spibyte = ye
Gosub senddata
Return
clearscreen:
'turn off the display while the screen is cleared
spibyte = 0x28
Gosub sendcommand
'create a rectangle area the size of the window
xs = 0
xe = 131
ys = 0
ye = 131
Gosub createwindow
'put the display into "write mode"
spibyte = 0x2c
Gosub sendcommand
'fill the rectangle with black pixels
spibyte = 0x00
For i = 0 To 131
For j = 0 To 131
Gosub senddata
Next j
Next i
spibyte = 0x29 'display on?
Gosub sendcommand
Return
sendcommand:
spibit = 0
Gosub sendspi9bits
Return
senddata:
spibit = 1
Gosub sendspi9bits
Return
usbonftin:
Return
usbonftout:
Return
usbonioout:
'we've received some data on the data i/o (from PC to device)
i = UsbIoBuffer(0)
Select Case i
Case 1 'this is the token to say "send byte"
If UsbIoBuffer(1) = 1 Then spibit = 1 Else spibit = 0
spibyte = UsbIoBuffer(2)
Gosub sendspi9bits
Case 2 'this is the token to say "set delay time/length"
If UsbIoBuffer(1) = 1 Then spiclockus = 1 Else spiclockus = 0
spiclockdelay = UsbIoBuffer(2)
Case 3 'this is the token to say "run the init sequence"
Gosub lcdinitialise
Case 4 'this is the token to say "draw a window"
xs = 10
xe = 60
ys = 10
ys = 60
Gosub createwindow
For i = 0 To 20
For j = 0 To 20
spibyte = 0
spibit = 1 '1=data, 0=command
Gosub sendspi9bits
Next j
Next i
Case 5 'this is the backlight token
If UsbIoBuffer(1) = 1 Then High glcd_bl Else Low glcd_bl
EndSelect
Return
usbonioin:
'we've received an io/data request from the PC (usbioin = send to PC)
'for some data from the device.
Return
Once again, a big thanks to Robot Steve for lending me his Arduino kit while I try to source one of my own!
Armed with little more than a Phillips PCF8833 datasheet and some Arduino code libraries, excitement reigned around Nerd Towers today, as this little colour LCD Arduino shield flickered into life.
The screen uses SPI to send byte commands to the screen.
After initialising the screen, data is written using the following format:
First a "window" is defined, by providing start-x, end-x, start-y and end-y co-ordinates (0-131). Then, a stream of data is sent, with (in 8-bit mode) each byte representing a pixel colour.
You can define how the screen behaves after each pixel-byte is received. I set my display up to draw pixels from top-to-bottom. When the current pixel reaches the bottom of the defined window size, it increases the column counter and returns to the top of the window
Unlike most serially-driven devices, the Nokia 6610 display uses 9-bits NOT 8 to transfer data to the screen. The first bit tells the display whether the following byte is a command (first bit is zero) or some data (first bit is set).
Although Oshonsoft includes built-in software driven SPI routines, I decided to write my own (using the ones in the Arduino library as a base) which send 9-bits in a continuous stream. Because Oshonsoft Basic is so simple to understand, this implementation could be easily ported to a compiler of your choice. The full code listing follows. Below is a summary of how to use the device:
Creating a window:
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2A (command to set the column/x co-ord)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send the x-start value as a byte (0-131)
Send the x-end value as a byte (0-131, must be greater than x-start)
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2B (command to set the column/y co-ord)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send the y-start value as a byte (0-131)
Send the y-end value as a byte (0-131, must be greater than y-start)
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2C (command to start writing pixel data)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send each pixel colour as a byte (assuming 8-bit colour mode)
Repeat for each pixel in the window
Here's the full code for a working PIC project:
Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x3e
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x83
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40
UsbSetVendorId 0x1221
UsbSetProductId 0x1003
UsbSetVersionNumber 0x1122
UsbSetManufacturerString "www.nerdclub.co.uk"
UsbSetProductString "Usb-to-SPI device"
UsbSetSerialNumberString "1111111111"
UsbOnIoInGosub usbonioin
UsbOnIoOutGosub usbonioout
UsbOnFtInGosub usbonftin
UsbOnFtOutGosub usbonftout
AllDigital
Symbol glcd_bl = PORTB.5
Symbol glcd_rst = PORTB.4
Symbol glcd_cs = PORTB.3
Symbol glcd_sda = PORTB.2
Symbol glcd_miso = PORTB.1
Symbol glcd_sck = PORTB.0
Symbol led = PORTA.0
Define SPI_SCK_REG = PORTB 'defines the port where sck line is connected To
Define SPI_SCK_BIT = 0 'defines the pin where sck line is connected To
Define SPI_SDO_REG = PORTB 'defines the port where sdo line is connected To
Define SPI_SDO_BIT = 1 'defines the pin where sdo line is connected To
Define SPI_SDI_REG = PORTB 'defines the port where sdi line is connected To
Define SPI_SDI_BIT = 2 'defines the pin where sdi line is connected To
Define SPI_CS_REG = PORTB 'defines the port where cs line is connected To
Define SPI_CS_BIT = 3 'defines the pin where cs line is connected To
'SDO is not used - but is mapped to MISO on the display
'(serial data out on the MCU to serial data out on the lcd)
Dim spibyte As Byte 'a byte to send to the lcd
Dim spibit As Bit 'first bit is 0=command, 1=data
Dim spiclockdelay As Byte 'how long to wait between spi clock pulses
Dim spiclockus As Bit 'whether clock pulse delay is us or ms
Dim xs As Byte 'x co-ord to start bitmap from
Dim ys As Byte 'y co-ord to start bitmap from
Dim xe As Byte 'x co-ord to draw up to
Dim ye As Byte 'y co-ord to draw up to
Dim i As Byte '}
Dim j As Byte '} general variables
Dim k As Byte '}
init:
spiclockus = 1
spiclockdelay = 4
'drive an LED high so we can see what's going on
High led
Gosub lcdinitialise
'drive the led low
Low led
UsbStart
UsbService
loop:
UsbService
Goto loop
End
sendspi9bits:
'--------------------------------------------------------
'FROM THE NOKIA DATASHEET
'the serial interface is
'initialized when SCE is High. In this state, SCLK pulses
'have no effect And no power is consumed by the serial
'interface. A falling edge On pin sce enables the serial
'interface And indicates the start of data transmission.
'--------------------------------------------------------
'flash the led high
High led
Low glcd_sda
'drive the cs low
Low glcd_cs
Gosub spidelay
'first send the init bit, for either command or data
If spibit = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
'now clock 8 bits from the spibyte value starting with bit 7
If spibyte.7 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.6 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.5 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.4 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.3 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.2 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.1 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
If spibyte.0 = 1 Then High glcd_sda Else Low glcd_sda
Gosub toggleclockpin
'bring cs high to indicate end of transmission
High glcd_cs
Gosub spidelay
'flash the led off
Low led
Return
toggleclockpin:
'take the clock pin high, wait a second, drive it low
Gosub spidelay
Low glcd_sck
Gosub spidelay
High glcd_sck
Return
spidelay:
If spiclockus = 1 Then
WaitUs spiclockdelay
Else
WaitMs spiclockdelay
Endif
Return
lcdinitialise:
'this is taken from teh pcf8833.c file: Arduino library
'turn on the backlight
High glcd_bl
WaitMs 1
'send a dummy data byte
spibyte = 0 'all zeros is interpreted as NOP in the display chip
Gosub sendcommand
'send software reset command
spibyte = 0x01
Gosub sendcommand
WaitMs 10
spibyte = 0x11 'sleepout
Gosub sendcommand
spibyte = 0x36 'memory access control
Gosub sendcommand
'when a bitmap is drawn to screen, you give a start x, start y
'and end x and end y co-ordinate. Then drawing can go from left-to-right,
'up-and-down, or up-and-down, wrapping round to move the pixel left-to-right.
'For our fonts and so on, we draw each pixel top to bottom, then
'when we get to the bottom of the column of data, move left to right
'This is called vertical addressing mode.
spibyte = 0xe0 'memory access options:
'1 - my mx v lao rgb x x x
'my=mirror in Y, mx=mirror in x, V=vertical addressing,
'lao=line address order, rgb= colour order rgb/bgr
'e0 came from the Arduino library and is 11100000b
Gosub senddata 'note: data, not command
spibyte = 0x25 'set contrast
Gosub sendcommand
spibyte = 0x40 'contrast value
Gosub senddata 'note: data=contrast value, not a command!
WaitMs 10 'allow things to stablise
spibyte = 0x3a 'set colour mode
Gosub sendcommand
spibyte = 0x02 'xxxxx010 = 8-bit colour
Gosub senddata 'note: data=colour mode value, not a command
spibyte = 0x00 'dummy command - dunno why, but it's in the C library!
Gosub sendcommand
Gosub clearscreen
Return
createwindow:
spibyte = 0x2a 'set x start and end co-ordinates
Gosub sendcommand
spibyte = xs
Gosub senddata
spibyte = xe
Gosub senddata
spibyte = 0x2b 'set y start and end co-ordinates
Gosub sendcommand
spibyte = ys
Gosub senddata
spibyte = ye
Gosub senddata
Return
clearscreen:
'turn off the display while the screen is cleared
spibyte = 0x28
Gosub sendcommand
'create a rectangle area the size of the window
xs = 0
xe = 131
ys = 0
ye = 131
Gosub createwindow
'put the display into "write mode"
spibyte = 0x2c
Gosub sendcommand
'fill the rectangle with black pixels
spibyte = 0x00
For i = 0 To 131
For j = 0 To 131
Gosub senddata
Next j
Next i
spibyte = 0x29 'display on?
Gosub sendcommand
Return
sendcommand:
spibit = 0
Gosub sendspi9bits
Return
senddata:
spibit = 1
Gosub sendspi9bits
Return
usbonftin:
Return
usbonftout:
Return
usbonioout:
'we've received some data on the data i/o (from PC to device)
i = UsbIoBuffer(0)
Select Case i
Case 1 'this is the token to say "send byte"
If UsbIoBuffer(1) = 1 Then spibit = 1 Else spibit = 0
spibyte = UsbIoBuffer(2)
Gosub sendspi9bits
Case 2 'this is the token to say "set delay time/length"
If UsbIoBuffer(1) = 1 Then spiclockus = 1 Else spiclockus = 0
spiclockdelay = UsbIoBuffer(2)
Case 3 'this is the token to say "run the init sequence"
Gosub lcdinitialise
Case 4 'this is the token to say "draw a window"
xs = 10
xe = 60
ys = 10
ys = 60
Gosub createwindow
For i = 0 To 20
For j = 0 To 20
spibyte = 0
spibit = 1 '1=data, 0=command
Gosub sendspi9bits
Next j
Next i
Case 5 'this is the backlight token
If UsbIoBuffer(1) = 1 Then High glcd_bl Else Low glcd_bl
EndSelect
Return
usbonioin:
'we've received an io/data request from the PC (usbioin = send to PC)
'for some data from the device.
Return
Once again, a big thanks to Robot Steve for lending me his Arduino kit while I try to source one of my own!
Post a Comment