We're already familiar with these chips, from our multiple servo controller board from back in May.
The idea is to store strings of text in these chips, then simply set a pointer (to tell the PIC where to start reading from) and get the microcontroller to read the text back and display it on the LCD.
We did look at I2C and other serial eeprom alternatives (at £1.20 each these Atmel chips are quite expensive for eeprom and at 4Mbit, are much bigger than we're ever going to need!) but most other (non-Flash) chips run at 100kz, or 400khz at best (yes, that's kilohertz, not Mhz). This will obviously make drawing text on the LCD run really slowly which is something we're keen to avoid.
These little Atmels can work up to 20Mhz. Which by happy coincidence is how fast the master chip will be running anyway, so hopefully we won't lose too much time reading and displaying text to the screen.
We wired our Flash eeprom chip up to PORTD on an 18F4550 (using RD.0-RD.3) and hacked some code together to read and write data to/from the chip. Amazingly, it worked first time!
AllDigital
Config PORTC = Output
Config PORTD = Output
Config PORTD.2 = Input
configuration:
Symbol enablepin = PORTC.0
Symbol clockpin = PORTC.1
Symbol datapin = PORTC.2
declarations:
Dim tmp As Byte
Dim i As Byte
Dim lcdi As Byte
Dim lcdbyte As Byte
Dim lcdbytetosend As Byte
Dim rs As Bit
Dim flag As Byte
Dim mask As Byte
Dim pageaddr As Word
Dim byteaddr As Byte
Dim byteswritten As Word
Dim bytesread As Word
Dim streamwrite As Bit
Dim streamread As Bit
init:
WaitMs 200
Define SPI_CS_REG = PORTD
Define SPI_CS_BIT = 0
Define SPI_SCK_REG = PORTD
Define SPI_SCK_BIT = 1
Define SPI_SDI_REG = PORTD
Define SPI_SDI_BIT = 2
Define SPI_SDO_REG = PORTD
Define SPI_SDO_BIT = 3
SPIPrepare
Gosub initialiselcd
Gosub initialiseeeprom
pageaddr = 1
byteaddr = 0
Gosub readanddisplaydata
loop:
pageaddr = 1
Gosub readanddisplaydata
WaitMs 4000
lcdbytetosend = 0x01 'clear screen
Gosub writelcdcommand
byteaddr = byteaddr + 16
If byteaddr > 60 Then byteaddr = 0
WaitMs 1000
Goto loop
End
writelcdnibble:
Low enablepin
Low clockpin
If rs = 1 Then High datapin Else Low datapin
Gosub toggleclockpin
'shift in 4 bits
mask = 8
For lcdi = 1 To 4
flag = lcdbyte And mask
If flag = 0 Then Low datapin Else High datapin
Gosub toggleclockpin
mask = ShiftRight(mask, 1)
Next lcdi
'now strobe the clock one more time because ST+SC are tied
Gosub toggleclockpin
'toggle the enable pin to "flush" the data into the lcd
Low datapin
High enablepin
Low enablepin
Return
toggleclockpin:
'toggle the clock pin
High clockpin
Low clockpin
Return
writelcddata:
rs = 1
Gosub senddatatolcd
Return
writelcdcommand:
rs = 0
Gosub senddatatolcd
Return
senddatatolcd:
lcdbyte = ShiftRight(lcdbytetosend, 4)
Gosub writelcdnibble
lcdbyte = lcdbytetosend And 15
Gosub writelcdnibble
Return
initialiselcd:
For i = 1 To 3
WaitMs 50
lcdbytetosend = 0x20
Gosub writelcdcommand
Next i
WaitMs 50
lcdbytetosend = 0x28 '4 bits, 2 lines, 5x7 font
Gosub writelcdcommand
WaitMs 50
lcdbytetosend = 0x0c 'display on, no cursors
Gosub writelcdcommand
WaitMs 50
lcdbytetosend = 0x06 'entry mode auto-increment
Gosub writelcdcommand
WaitMs 50
lcdbytetosend = 0x01 'clear screen
Gosub writelcdcommand
'send a space character to the display to test
WaitMs 50
lcdbytetosend = 32
Gosub writelcddata
Return
initialiseeeprom:
Gosub set256pagesize
Gosub chiperase
pageaddr = 1
byteaddr = 0
WaitMs 100
Gosub startstreamwrite
For i = 0 To 63
tmp = LookUp("Blood Bowl Griff Oberwald Varag Ghoulchew The Mighty Zug "), i
SPISend tmp
Next i
Gosub endstreamwrite
Return
startstreamread:
streamread = 1
SPICSOn
SPISend 0xe8 'stream read (legacy mode)
SPISend pageaddr.HB
SPISend pageaddr.LB
SPISend byteaddr
SPISend 0x00 'four don't care bytes
SPISend 0x00
SPISend 0x00
SPISend 0x00
bytesread = 0
Return
endstreamread:
SPICSOff
streamread = 0
Return
startstreamwrite:
SPICSOff
SPICSOn
SPISend 0x82 '0x82 'write THROUGH buffer1 command
SPISend pageaddr.HB '5 don't care bits + 11 address bits
SPISend pageaddr.LB 'is the same as sending page address as hb/lb
SPISend byteaddr 'last eight bits are buffer start byte
byteswritten = 0
streamwrite = 1
WaitMs 5
Return
endstreamwrite:
SPICSOff 'this causes the flash buffer to automatically get written to memory
WaitMs 5
streamwrite = 0
Return
set256pagesize:
SPICSOn
SPISend 0x3d
SPISend 0x2a
SPISend 0x80
SPISend 0xa6
SPICSOff
Return
chiperase:
SPICSOn
SPISend 0xc7
SPISend 0x94
SPISend 0x80
SPISend 0x9a
SPICSOff
WaitMs 100
Return
readanddisplaydata:
lcdbytetosend = 0x01 'clear screen
Gosub writelcdcommand
Gosub startstreamread
For i = 1 To 16
SPIReceive lcdbytetosend
'for testing
tmp = byteaddr + i
Write tmp, lcdbytetosend
Gosub writelcddata
Next i
Gosub endstreamread
Return
Note that in the initialiseeeprom routine we actually blank the Flash chip and write some data to it. In the final version of this code, we'll transfer data to Flash eeprom via a USB connection, but read it back just the same. Although this is just a basic test, it proves the idea of us storing character/player information in eeprom and calling it up and displaying it on a character-based LCD. All with just a few extra wires from the master microcontroller.
[photo or video goes here]
Note that in this example we're using a rather tiny 2x16 character LCD (because we had some hanging around). We've got our fingers crossed that Santa will bring some larger 4x20 displays, like the one below which uses the same Hitachi 44780 controller chip, so the code should work for both.
With four lines of twenty characters, we can split player names over two lines (to allow really long forenames/surnames) and write player stats (MA, ST, AG, AV) on a single line - each stat (0-9) would take up four characters (XX-digit-space) so the output could look something like
GRIFF
OBERWALD
MA4 ST5 AG8 AV9
OBERWALD
MA4 ST5 AG8 AV9
Or, if we can get the player's name on a single line, something like:
GRIFF OBERWALD
MA ST AG AV
4 5 8 9
MA ST AG AV
4 5 8 9
How can i remove the lcd and place rs232 on it and using terminal to displat the data and save it to a text file.
ReplyDeleteplease mail me conrayvb@gmail.com
You're after removing the LCD altogether, then capturing the data being sent to the LCD to pass an ascii character back to a PC? It's possible, but will take a bit of effort. First up you'll need to understand how the LCD works - the four data lines hold four bits of an ascii character, then the enable pin is taken from low to high, then another 4 bits are put onto the lines, and the enable bit toggled again.
ReplyDeleteYou'll probably need to use a microcontroller (PIC/AVR/Arduino) in place of the LCD with either serial comms (and perhaps an FTDI serial-to-usb if your PC doesn't have a serial port) or with native USB support.
You can then monitor the enable line, when it goes from low to high, read the 4 parallel data pins and put this value into a variable. Bitshift left four times, then wait for the enable line to go low to high again, read the 4 input pins and add these to the variable. This should give you the ascii code that was sent to the LCD. Pass this onto your PC through the serial (or usb) connection.
Don't forget that you'll have no idea how fast the LCD display is being controlled - I use a 20Mhz crystal on my devices, so the lcd is probably running around 4mhz-5mhz. Someone using a slower crystal might only be sending data to an LCD at around 1mhz (a lot of PICs have built-in 4Mhz resonators, Arduino/AVR sometimes has 8Mhz internal clocks and so on).
It'd be a nice project to work on - I understood how LCDs work because I had to write my first pic program in assembly; that way I got to know exactly the pin sequence used to operate them, so de-coding the data is quite straight-forward. In fact, if you can create your own program to send data to a character LCD display using only pin high/low commands (instead of any pre-built libraries) this will give you the level of understanding needed to achieve what you want - and will also form the basis for your decoding device.
If you can't you're facing an uphill struggle!!