0

Interfacing with Flash memory

Posted by Chris on Wednesday, November 04, 2009
Ok, here it is. Some Oshonsoft PIC Basic code for reading and writing data to a Flash memory device.
This example writes data through the Flash internal buffer(s) and reads/writes data one entire page (256 bytes) at a time. Because of the limitations of the USB implementation, the PIC keeps a mirror copy of the Flash buffer in memory and when called for, sends a group of 8 bytes to the USB host device.
This code example works with a PIC and Flash memory connected according to the schematic from this post, with the Flash memory connected to pins PORTA.0-3


Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x3e
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x05 '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

'SPI setup
Define SPI_CS_REG = PORTA
Define SPI_CS_BIT = 1
Define SPI_SCK_REG = PORTA
Define SPI_SCK_BIT = 2
Define SPI_SDI_REG = PORTA
Define SPI_SDI_BIT = 3
Define SPI_SDO_REG = PORTA
Define SPI_SDO_BIT = 0
SPIPrepare

'USB setup
UsbSetVendorId 0x099
UsbSetProductId 0x004
UsbSetVersionNumber 0x1001
UsbSetManufacturerString "ScoreSure"
UsbSetProductString "ScoreSure Template Device"
UsbSetSerialNumberString "0123456789"
UsbOnIoInGosub usbonioin
UsbOnIoOutGosub usbonioout
UsbOnFtInGosub usbonftin
UsbOnFtOutGosub usbonftout
AllDigital

'general declarations
Dim i As Byte
Dim j As Byte
Dim state As Byte
Dim iusb As Byte

'memory access variables
Dim addri As Byte
Dim addrj As Byte
Dim addrk As Byte
Dim ai As Byte
Dim bi As Byte
Dim ci As Byte
Dim useusb As Bit
Dim pageaddr As Word
Dim byteaddr As Byte
Dim bytecount As Word
Dim picbuffer(256) As Byte
Dim picbufferpointer As Byte
Dim flashstatus As Byte

'initialisation
init:
  useusb = 1
  picbufferpointer = 0

'startup
start:
  If useusb = 1 Then UsbStart


'main loop
loop:
  If useusb = 1 Then
    UsbService
  Else
    Select Case state

    EndSelect
  Endif

Goto loop
End

usbonftout:
  'feature reports.
Return

usbonftin:
  'don't do anything on feature.
Return

usbonioout:

  'received data from host into PIC
  'Here we put a single command byte into buffer(7) to tell the PIC
  'what we want it to do.

  Select Case UsbIoBuffer(7)

    '---------200+ are memory control commands --------

    '-----------------------------------------------------------
    Case 200 'set page address 0-2048 (byte 2= MSB, byte 1=LSB)
    '-----------------------------------------------------------
    iusb = UsbIoBuffer(2)
    pageaddr = iusb * 256
    iusb = UsbIoBuffer(1)
    pageaddr = pageaddr + iusb

    '-----------------------------------------------------------
    Case 201 'set byte address within a page (1 page=256 bytes)
    '-----------------------------------------------------------
    byteaddr = UsbIoBuffer(2)

    '---------------------------------------------------------
    Case 202 'load flash memory page into flash memory buffer
    '---------------------------------------------------------
    Gosub flashmemorytoflashbuffer

    '--------------------------------------------------------------
    Case 203 'load flash memory buffer (256 bytes) into PIC buffer
    '--------------------------------------------------------------
    Gosub flashbuffertopicbuffer

    '-------------------------------------------
    Case 204 'write PIC buffer to memory buffer
    '-------------------------------------------
    Gosub picbuffertoflashbuffer

    '-------------------------------------------
    Case 205 'flash buffer to flash page memory
    '-------------------------------------------
    Gosub flashbuffertoflashmemory

    '---------------------------------------
    Case 206 'set picbuffer pointer (0-255)
    '---------------------------------------
    picbufferpointer = UsbIoBuffer(6)

    '------------------------------------------------
    Case 207 'load 4 bytes from host into pic buffer
    '------------------------------------------------
    For iusb = 0 To 3
      picbuffer(picbufferpointer) = UsbIoBuffer(iusb)
      picbufferpointer = picbufferpointer + 1
    Next iusb

    '---------------------------
    Case 208 'start stream read
    '---------------------------
    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

    '-------------------------
    Case 209 'end stream read
    '-------------------------
    SPICSOff

    '--------------------------
    Case 210 'empty PIC buffer
    '--------------------------
    Gosub emptypicbuffer
    picbufferpointer = 0

    '-------------------------------------------------
    Case 240 'clear entire memory (use with caution!)
    '-------------------------------------------------

    '-------------------------------------------
    Case 253 'flash memory status register read
    '-------------------------------------------
    Gosub getflashstatus
    Gosub emptypicbuffer
    picbuffer(0) = flashstatus

    '-------------------------------------------------------------------
    Case 254 'blow the fuse on the flash memory to set to 256-byte mode
    '-------------------------------------------------------------------
    SPICSOn
    SPISend 0x3d
    SPISend 0x2a
    SPISend 0x80
    SPISend 0xa6
    SPICSOff

  EndSelect
Return

usbonioin:
  'send data from PIC to host
  'if you use a loop in here, garbage gets sent back!

  If streamread = 1 Then
    'load the data from flash memory (direct access, legacy mode)
    'straight into the usbiobuffer
    SPIReceive UsbIoBuffer(0)
    SPIReceive UsbIoBuffer(1)
    SPIReceive UsbIoBuffer(2)
    SPIReceive UsbIoBuffer(3)
    SPIReceive UsbIoBuffer(4)
    SPIReceive UsbIoBuffer(5)
    SPIReceive UsbIoBuffer(6)
    SPIReceive UsbIoBuffer(7)

  Else
    iusb = picbufferpointer
    UsbIoBuffer(0) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(1) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(2) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(3) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(4) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(5) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(6) = picbuffer(iusb)
    iusb = iusb + 1
    UsbIoBuffer(7) = picbuffer(iusb)

  Endif
Return

setflashdeepsleep:
  'when we're not using the flash memory, set it to deep sleep which causes it to
  'use minimum amount of power (it's basically on super-standby) opcode B9H
  SPICSOn
  SPISend 0xb9
  SPICSOff
Return

setflashwakeup:
  'when we've put the flash memory into deep sleep, it ignores all commands sent to
  'it until it's been woken up by sending opcode ABH
  SPICSOn
  SPISend 0x0ab
  SPICSOff
Return

flashmemorytoflashbuffer:
  SPICSOn
  SPISend 0x53 'transfer memory page to buffer1 command
  SPISend pageaddr.HB 'send the page address to read data
  SPISend pageaddr.LB 'from into buffer number one
  SPISend 0x00 'don't care 8-bits
  SPICSOff
Return

flashbuffertoflashmemory:
  SPICSOn
  SPISend 0x83 'transfer buffer1 to flash page (with built-in erase) command
  SPISend pageaddr.HB 'send the page address to read data
  SPISend pageaddr.LB 'from into buffer number one
  SPISend 0x00 'don't care 8-bits
  SPICSOff
Return

flashbuffertopicbuffer:
  SPICSOn
  SPISend 0xd4 'buffer1 read command
  SPISend 0x00 'start off with 16
  SPISend 0x00 'don't care bits
  SPISend 0x00 'then buffer byte to start reading from (always zero)

  For picbufferpointer = 0 To 255
    SPIReceive picbuffer(picbufferpointer)
  Next picbufferpointer
  picbufferpointer = 0
  SPICSOff
Return

picbuffertoflashbuffer:
  SPICSOn
  SPISend 0x84 'buffer1 write command
  SPISend 0x00 'start with 16
  SPISend 0x00 'don't care bits
  SPISend 0x00 'then buffer byte to start reading to (always zero)

  For picbufferpointer = 0 To 255
    SPISend picbuffer(picbufferpointer)
  Next picbufferpointer
  picbufferpointer = 0
  SPICSOff
Return

emptypicbuffer:
  For i = 0 To 255
    picbuffer(i) = 0
  Next i
Return

getflashstatus:
  SPICSOn
  SPISend 0xd7 'status register command
  SPIReceive flashstatus
  SPICSOff
Return


The first thing to do, once connected and the USB device recognised, is to set the page size to 256 bytes. This is done by sending the byte command (from PC to PIC)
number 254. Before doing this, we checked the Flash memory status register:
Send (from PC to PIC) byte command 253. This is done by clearing the entire USB buffer - setting all values to zero - on the PC then setting USB byte(7) to 253 using the VB command:
data(0)=0
data(1)=0
data(2)=0
data(3)=0
data(4)=0
data(5)=0
data(6)=0
data(7)=253
HIDTerminal1.HIDSendReport(data(0), data(1), data(2), data(3), data(4), data(5), data(6), data(7))

(see Oshonsoft PIC18 USB section for details about communicating with your PIC-based USB device from your PC and the HIDTerminal Activex control which encapsulates USB functionality.

After the byte command 253 has been sent to the USB device, the internal PIC memory buffer should be blank (all zeros) except for byte(0) which contains the Flash Status Register value. We read this back to the PC by issuing the VB command:
HIDTerminal1.HIDReadReport(data(0), data(1), data(2), data(3), data(4), data(5), data(6), data(7))

Displaying the values for data(0-7) on screen (we use a few text boxes, but you could use Debug.Print or any other method to view the values) we see that the Flash Status Register value is 156 or, in binary:
10011100

Checking the AT45DB041D datasheet we can see that the last bit of the status register (bit zero) tells us whether each page size is 264 (default) or 256.
In this case, we can see - because it's a brand new device - bit zero is cleared, which signifies that a page size is set to the default of size 264 bytes.
We issued the "change page size" command from PC to PIC (which in turn sent the byte sequence 0x3D, 0x2A, 0x80, 0xA6 to the Flash memory) to blow the fuse holding the page size value - effectively turning it to a 256-byte page size. This is a one-time operation and cannot be undone.
After repeating the "read Flash Status Register" routine as outlined above, we now got a status value of 157. This tells us that bit zero of the Flash Status Register is now set, which - according to the datasheet - signifies that the Flash unit is now working with a 256-byte page size. Just the result we were after!

Using a combination of send and read commands, we are now able to read and write data to and from the Flash memory device.
Result!

0 Comments

Post a Comment

whos.amung.us

Copyright © 2009 .Nerd Club All rights reserved. Theme by Laptop Geek. | Bloggerized by FalconHive Supported by Blogger Templates.