'Rabbit_4.Bas
'
'Interface with Z-World SF1010 serial flash expansion card (4MB).
'
'This program provides a virtually continuous write operation
'using both buffers of the Atmel AT45DB321 to program 14 pages.
'
'8-bit serial output on MOSI and 8-bit serial input on MISO uses
'ShiftIn() and ShiftOut() commands.
'
'SPI Modes 0 and 3 are used (data clocked in on rising edge of CLK,
'data clocked out on falling edge of CLK).
'
'copyright, Lisa P. Mickens, Morgan State University, Nov. 2001

Const SPI_CS as Byte = 13				'Definition of BX24 pins
Const SPI_CLK as Byte = 14
Const MOSI as Byte = 15
Const MISO as Byte = 16

Const B1_Write as Byte = bx10000100		'Definition of AT45DB321 commands
Const B2_Write as Byte = bx10000111
Const B1ToMemWrite as Byte = bx10000011
Const B2ToMemWrite as Byte = bx10000110
Const Mem_Read as Byte = bx11010010

Sub Main()
  Dim BAddress as Integer, PAddress as Integer, N as Integer
  Dim Data as Byte

  Call OpenSerialPort (1, 19200)

  For N = 1 to 7
    Debug.print "Writing B1..."
    For BAddress = 0 to 527				'Write data to Buffer 1
      Data = CByte((BAddress MOD 10) + N)
      Call WriteBuffer (B1_Write,BAddress, Data)
    Next

    Call CheckStatus()				'Monitor RDY/BUSY
    PAddress = 2 * (N - 1)  			'pages 0, 2, 4, etc
    Call BufferToMem(B1ToMemWrite,PAddress)	'Transfer data from Buffer 1 to Memory

    Debug.print "Writing B2..."
    For BAddress = 0 to 527				'Write data to Buffer 2
      Data = CByte((BAddress MOD 5) + N)
      Call WriteBuffer (B2_Write,BAddress, Data)
    Next

    Call CheckStatus()				'Monitor RDY/BUSY
    PAddress = 2 * (N-1) + 1			'pages 1, 3, 5, etc
    Call BufferToMem(B2ToMemWrite,PAddress)	'Transfer data from Buffer 2

  Next

  For PAddress = 0 to 13				'Read data from Main Memory
    For BAddress = 0 to 527
      Data = ReadMemPage (PAddress, BAddress)
      Call PutB(Data)
      If (((BAddress+1) MOD 10) <> 0) Then	'Put 10 values to a line
        Call PutByte (Asc(" "))
      Else
        Call NewLine()
      End If
    Next
    Call NewLine()
  Next
End Sub

Sub WriteBuffer (byVal Opcode as byte, byVal Address as Integer, ByVal Data as Byte)
  Dim DCare as Byte, Addr_Hi as byte, Addr_Lo as byte

  DCare = bx00000000						'Don't Care byte
  Addr_Hi = CByte((CByte(Address\256) AND bx00000011))	'Set up address bytes
  Addr_Lo = CByte (Address MOD 256)

  Call PutPin (SPI_CS, 1)				'Bring CS High
  Call PutPin (SPI_CLK, 0)				'Make sure CLK is low
  Call PutPin (MOSI, 0)				'Bring MOSI low
  Call PutPin (SPI_CS,0)				'Bring CS Low to initiate

  Call ShiftOut (MOSI, SPI_CLK, 8, Opcode)	'Send Buffer 1 Write opcode
  Call ShiftOut (MOSI, SPI_CLK, 8, DCare)		'8 Don't care bits
  Call ShiftOut (MOSI, SPI_CLK, 8, Addr_Hi)	'6 Don't care bits and 2 Address bits
  Call ShiftOut (MOSI, SPI_CLK, 8, Addr_Lo)	'8 Address bits
  Call ShiftOut (MOSI, SPI_CLK, 8, Data)		'Send data byte

  Call PutPin (SPI_CS, 1)				'End session
End Sub

Sub BufferToMem (ByVal Opcode as Byte, ByRef PAddress as Integer)
  Dim DCare as Byte, Addr_Hi as byte, Addr_Lo as byte, Temp as byte
  Dim N as integer

  Temp = CByte(CByte(PAddress\256) AND bx00011111)	'Set up address bytes
  For N = 1 to 3
    Temp = Temp * 2
  Next
  Addr_Hi = Temp
  Addr_Lo = Cbyte (PAddress MOD 256)
  DCare = bx00000000					'Don't Care byte

  Call PutPin (SPI_CS, 1)				'Bring CS High
  Call PutPin (SPI_CLK, 0)				'Make sure CLK is low
  Call PutPin (MOSI, 0)				'Bring MOSI low
  Call PutPin (SPI_CS,0)				'Bring CS Low to initiate

  Call ShiftOut (MOSI, SPI_CLK, 8, Opcode)	'Send Buffer to Main Memory opcode
  Call ShiftOut (MOSI, SPI_CLK, 1, DCare)		'Reserved Bit
  Call ShiftOut (MOSI, SPI_CLK, 5, Addr_Hi)	'5 Page address bits
  Call ShiftOut (MOSI, SPI_CLK, 8, Addr_Lo)	'8 Page address bits
  Call ShiftOut (MOSI, SPI_CLK, 2, DCare)		'2 Don't care bits
  Call ShiftOut (MOSI, SPI_CLK, 8, DCare)		'Don't Care byte

  Call PutPin (SPI_CS, 1)				'End session
  Call Sleep (20)					'Time (20 ms) for page erase and programming
  PAddress = PAddress + 1				'Increment Page Address
End Sub

Sub CheckStatus ()
  Const StatusRegOC as byte = bx11010111
  Dim Val as Byte, Status as Byte, Data as Byte

  Call PutPin (SPI_CS, 1)				'Bring CS High
  Call PutPin (SPI_CLK, 0)				'Make sure CLK is low
  Call PutPin (MOSI, 0)				'Bring MOSI low
  Call PutPin (SPI_CS,0)				'Bring CS Low to initiate

  Call ShiftOut (MOSI, SPI_CLK, 8, StatusRegOC)
  Do
    Val = ShiftIn (MISO, SPI_CLK, 8)		'Read status register byte
    Data = (Val XOR bx11111111)			'Invert data byte (Rabbit Semi Board does this)
    Status = Data AND bx10000000			'Check RDY/Busy Bit
    Debug.print "Checking status"
  Loop Until Status >= 128

  Call PutPin (SPI_CS, 1)				'Bring CS High
End Sub

Function ReadMemPage (ByVal PAddr as Integer, ByVal BAddr as Integer) as Byte
  Dim DCare as byte, BAddr_Hi as Byte, BAddr_Lo as Byte, Temp as Byte
  Dim PAddr_Hi as byte, PAddr_Lo as Byte, Val as Byte
  Dim N as Integer

  DCare = bx00000000						'Don't Care byte
  Temp = CByte (CByte(BAddr\256) AND bx00000011)	'Set up address bytes
  For N = 1 to 6
     Temp = Temp * 2
  Next
  BAddr_Hi = Temp
  BAddr_Lo = CByte (BAddr MOD 256)
  Temp = CByte (CByte(PAddr\256) AND bx00011111)
  For N = 1 to 3
   Temp = Temp * 2
  Next
  PAddr_Hi = Temp
  PAddr_Lo = CByte (PAddr MOD 256)

  Call PutPin (SPI_CS, 1)				'Bring CS High
  Call PutPin (SPI_CLK, 0)				'Make sure CLK is low
  Call PutPin (MOSI, 0)				'Bring MOSI low
  Call PutPin (SPI_CS,0)				'Bring CS Low to initiate

  Call ShiftOut (MOSI, SPI_CLK, 8, Mem_Read)	'Send Main Memory Page Read opcode
  Call ShiftOut (MOSI, SPI_CLK, 1, DCare)		'Reserved Bit
  Call ShiftOut (MOSI, SPI_CLK, 5, PAddr_Hi)	'5 Page address bits
  Call ShiftOut (MOSI, SPI_CLK, 8, PAddr_Lo)	'8 Page address bits
  Call ShiftOut (MOSI, SPI_CLK, 2, BAddr_Hi)	'2 Byte address bits
  Call ShiftOut (MOSI, SPI_CLK, 8, BAddr_Lo)	'8 Byte address bits

  For N = 1 to 4					'32 don't care bits
    Call ShiftOut (MOSI, SPI_CLK, 8, DCare)
  Next

  Val = ShiftIn (MISO, SPI_CLK, 8)			'Read data byte
  ReadMemPage = (Val XOR bx11111111)		'Invert data byte (Rabbit Semi Board does this)

  Call PutPin (SPI_CS, 1) 				'Bring CS High to end session
End Function