Showing posts with label AT45DB041D. Show all posts
Showing posts with label AT45DB041D. Show all posts

Wednesday, 14 December 2011

Serial character LCD driver with Flash eeprom

No sooner had we got our serial character LCD display working than we were moving on to the next stage of the project - reading text from an Atmel AT45DB041D Flash eeprom chip to decide what to display on the screen.

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


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  


Tuesday, 3 May 2011

USB servo board eeprom

The little eeprom chips arrived today. I forgot that they were SMT when I designed the USB servo board for PCB manufacture, so the board has an 8-pin DIP socket, and the eeprom chip is SMT. Bugger!

To get around this, I created a simple SMT-to-DIP converter for 8-pin chips:



The SMT chip goes to the left of the 8-pin DIP connectors. I'll put two rows of 4 x 0.1" header pins where the DIP chip would normally go, effectively turning the SMT chip into an 8-pin DIP.

SMT_to_DIP_8PINPrint at 100% no scaling in landscape orientation to create your own press-n-peel transfer to make this SMT-to-DIP converter

If you're making one of these yourself, note that the PCB design has been mirrored (normally we don't bother mirroring designs, as they are reversed on the bottom of any through-hole mounted board anyway). With this design, however, the copper part of the board will be face up, with the SMT chip soldered onto the copper side (rather than the through-hole components being mounted on the top and soldered underneath).
Because of this, the design is mirrored (but when you use press-n-peel/toner transfer to get the image onto the copper board, it'll end up the right way around).



Dont forget to mount the pin headers on the bottom (non-copper) side of the board, with the shorter legs soldered to the top (copper-side) of the board.

The usb servo board was designed to accommodate either a regular 8-pin DIP or our modified SMT-to-DIP board

Sunday, 1 May 2011

Servo board PCB layout update



Just a quick update on the 20-channel USB servo board with eeprom playback:
this new PCB layout includes the eeprom chip (Atmel's AT45DB041D). Another slight change to the earlier design is that the USB 5v/power supply now goes to the 5V output pin of the regulator rather than the input. This allows the user to connect 4xAA (or 4xAAA) batteries to create a 6V supply or even use a single PP3 (9V) battery to run the device, but safely connect the USB cable at the same time. The original design required the user to disconnect the batteries before connecting the USB cable to download more data to the device. With this new layout, the batteries can safely remain connected and the board still be connected to a PC to download more data.
(a future board with 3.7V rechargeable lipo is in the planning stages but is still some way off!)


Note in this silkscreen and current version of firmware, the servo pin numbering is a little peculiar. This will be addressed in the final version of the firmware!