Introduction.
This discussion illustrates how multiple SPI devices may be interfaced with the BX24's SPI Interface.
The BX24 provides the capability for acommodating up to four SPI devices, each sharing the SCK (Clk), MISO (Master In - Slave Out) and MOSI (Master Out - Slave In) leads which are located holes 3, 4 and 5 respectively, at the top of the BX24. A general purpose IO terminal is required for the /CS for each SPI device.
Discussion.
In this example a Microchip 25LC640 EEPROM and a Maxim MAX7219 Eight Digit 7-seg Display Driver are interfaced with the BX24. One advantage in using the SPI port is that this design is realized using only two of the BX24's 16 general purpose IO pins.
BX24 25LC640 MAX7219
MOSI (Hole 5) ----------> SI (term 5) -----------> DIn (term 1)
MISO (Hole 4) <--------- SO (Term 2)
SCK (Hole 3) -----------> SCK (term 6) ----------> CLK (term 13)
(Term 12) ---------------------------------------> LOAD (term 12)
(Term 13) -----PU-------> /CS (term 1)
Note that an external pullup resistor to +5 VDC (denoted as PU) is required on the /CS associated with the 25LC640 as all SPI devices, including the BX24's EEPROM share the MOSI, MISO and SCK leads and only one MISO can be active at a time. If the /CS on the LC640 is left floating the LC640 may be active which will "glare" with the MISO lead on the internal EEPROM. In this case, no pullup resistor is required on the /CS (LOAD) on the MAX7219 as the MAX7219 is not a "talker". That is, it sends no data to the master.
In program DispEEPROM.Bas, data is written to the first 256 locations in the LC640 and each byte is then read back byte by byte and the address (lower byte) and the data which is read are displayed on the four 7-segment LEDs associated with the MAX7219.
Discussions of the 25LC640 EEPROM and MAX7219 Display Driver are presented elsewhere on the web ite. DispEEPROM.Bas is simply a "splice" of these routines.
Note that in Sub Main(), two SPI channels (1 and 2) are opened, one for the EEPROM defining term 13 as the /CS and a second for the MAX7219 defining term 12 as the /CS. In all subsequent calls to SPICmd(), the appropriate channel is referenced. For the LC640, calls to SPICmd() appear in SPIEEPROMWrite() and SPIEEPROMRead(). For the MAX7219, the SPICmd() is called only in Max7219Out16().
' DispEEPROM.Bas
'
' Illustrates an interface with the Microchip 25LC640 SPI and MAX7219
' Eight Digit 7-seg Display Driver. Illustrates how to use multiple SPI
' channels.
'
' Writes 256 bytes to EEPROM and then reads them byte by byte and displays
' low byte of EEPROM address and data on four displays associated with the
' MAX7219.
'
' copyright, Peter H. Anderson, Baltimore, MD, Feb, '00
Const SPI_WREN as Byte = bx00000110 ' define EEPROM commands
Const SPI_WRDI as Byte = bx00000100
Const SPI_WRITE as Byte = bx00000010
Const SPI_READ as Byte = bx00000011
Const DecodeModeCode as Integer = &H900 ' define MAX7219 registers
Const IntensityCode as Integer = &Ha00
Const ScanLimitCode as Integer = &Hb00
Const TurnOnCode as Integer = &Hc00
Const DisplayTestCode as Integer = &Hf00
Const BLANK as Integer = &H00 ' define patterns for characters
Const MINUS as Integer = &H01
Const HVal as Byte = bx00110111 ' "H" ' these are not used in this program
Const EVal as Byte = bx01001111 ' "E"
Const LVal as Byte = bx00001110 ' "L"
Const PVal as Byte = bx01100111 ' "P"
' define SPI Setup Bits
Const SPI_LSB as Byte = &H20 'lsb transmitted first
Const SPI_CPOL as Byte = &H08 'sck is mostly high
Const SPI_CPHA as Byte = &H04 'clock phase, see atmel docs for timing
Const SPI_SCK4 as Byte = &H00 'clock speed f/4
Const SPI_SCK16 as Byte = &H01 'clock speed f/16
Const SPI_SCK64 as Byte = &H02 'clock speed f/64
Const SPI_SCK128 as Byte = &H03 'clock speed f/128
Const EEPROM_CS as Byte = 13 ' define the BX24 pins
' Note. Pull up this lead to +5 VDC to assure the external EEPROM is not
' active at the same time as the BX24 on-board SPI EEPROM
Const MAX7219_CS as Byte = 12
' No pullup is required on this as there is no MISO from the MAX7219
Sub Main()
Dim Address as Integer, Dat as Byte, SPISetupByte as Byte
Dim N as Integer
Call OpenSerialPort(1, 19200)
SPISetupByte = 0 ' most sig bit first, sck normally low, etc
Call OpenSPI(1, SPISetupByte, EEPROM_CS) ' Ch 1 for EEPROM
' note that the SPISetupByte may be different for each channel
' in this application, it is the same value
SPISetupByte = 0 ' most sig bit first, sck normally low, etc
Call OpenSPI(2, SPISetupByte, MAX7219_CS) ' Ch 2 for MAX7219
Call MAX7219Init() ' initialize display
' Not Code B decoding, 15/32 intensity,
' Digits 0, 1, 2, 3, On
For N = 1 to 4
Call MAX7219Out16(N*256 + CInt(BLANK)) ' blank the Displays
Next
For Address = 0 to 255 ' write data, byte by byte to EEPROM
Dat = CByte((255 - Address))
Call SPIEEPROMWrite(Address, Dat)
Next
For Address = 0 to 255 ' read it back and display it on terminal
Dat = SPIEEPROMRead(Address)
Call MAX7219PutHexI(Address * 256 + CInt(Dat))
' Address is high byte, Dat is low byte
Call Sleep(0.5)
'Call PutB(Dat) ' used for debugging
'If (((Address+1) MOD 8) <>0) Then ' 8 values to a line
' Call PutByte(Asc(" "))
'Else
' Call NewLine()
'End If
Next
End Sub
Sub SPIEEPROMWrite(ByVal Address as Integer, ByVal Dat as Byte)
Dim PutData(1 to 3) as Byte, GetData as Byte, H as Byte, L as Byte
PutData(1) = SPI_WREN
Call SPICmd(1, 1, PutData(1), 0, GetData) ' enable the write latch
PutData(1) = SPI_WRITE
' split the address into high and low bytes
H = CByte(Address\256) ' high byte
L = CByte(Address - (CInt(H)*256))
PutData(2) = H
PutData(3) = L
PutData(4) = Dat
Call SPICmd(1, 4, PutData(1), 0, GetData)
' output write command, two address bytes followed by the data
Call Sleep(0.005) ' allow time for the EEPROM to burn
End Sub
Function SPIEEPROMRead(ByVal Address as Integer) as Byte
Dim PutData(1 to 3) as Byte, GetData as Byte, H as Byte, L as Byte
PutData(1) = SPI_READ
' split the address into high and low bytes
H = CByte(Address\256)
L = CByte(Address - (CInt(H)*256))
PutData(2) = H
PutData(3) = L
Call SPICmd(1, 3, PutData(1), 1, GetData) ' send command plus address
' and then fetch the data
SPIEEPROMRead = GetData
End Function
Sub Max7219Init() ' initialize, Normal Operation
' Not Code B, 15/32 intensity,
' Digits 0, 1, 2, 3, Display On
Call Max7219Out16 (DisplayTestCode) ' Normal Operation vs Test
Call Max7219Out16 (DecodeModeCode OR &H00) 'Sets Decode Mode as No Code B
Call Max7219Out16 (IntensityCode OR &H07) 'Sets Intensity
Call Max7219Out16 (ScanLimitCode OR &H03) 'Sets Scan Limit
Call Max7219Out16 (TurnOnCode OR &H01) ' Turn it on
End Sub
Sub Max7219PutHexI(ByVal Q as Integer)
' Display integer Q in 4-digit Hex on displays
Dim H as Byte, L as Byte, HexVals(1 to 16) as Byte
Dim Index as Integer
' Patterns for digits. Note that the digit "0" is in element 1
HexVals(1) = bx01111110 ' 0
HexVals(2) = bx00110000 ' 1
HexVals(3) = bx01101101 ' 2
HexVals(4) = bx01111001 ' 3
HexVals(5) = bx00110011 ' 4
HexVals(6) = bx01011011 ' 5
HexVals(7) = bx01011111 ' 6
HexVals(8) = bx01110000 ' 7
HexVals(9) = bx01111111 ' 8
HexVals(10) = bx01111011 ' 9
HexVals(11) = bx01110111 ' a
HexVals(12) = bx00011111 ' b
HexVals(13) = bx01001110 ' c
HexVals(14) = bx00111101 ' d
HexVals(15) = bx01001111 ' e
HexVals(16) = bx01000111 ' f
' split the integer into two bytes
H = CByte(Q\256)
L = CByte(Q - (CInt(H)*256))
Index = CInt(H\16 + 1) ' high nibble of H + 1
Call Max7219Out16(4*256 + CInt(HexVals(Index)))
Index = CInt((H AND &H0f) + 1) ' low nibble of H + 1
Call Max7219Out16(3*256 + CInt(HexVals(Index)))
Index = CInt(L\16 + 1)
Call Max7219Out16(2*256 + CInt(HexVals(Index)))
Index = CInt((L AND &H0f) + 1)
Call Max7219Out16(1*256 + CInt(HexVals(Index)))
End Sub
Sub Max7219Out16(ByVal X as Integer)
' shifts out 16-bit quantity, most sig bit first
Dim PutData(1 to 2) as Byte, H as Byte, L as Byte
Dim GetData as Byte
H = CByte(X\256) ' Split into high and low bytes
L = CByte(X - (CInt(H)*256))
PutData(1) = H ' and put into contiguous addresses
PutData(2) = L
' Call PutB(H) ' used for debugging
' Call PutByte(Asc(" "))
' Call PutB(L)
' Call NewLine()
Call SPICmd(2, 2, PutData(1), 0, GetData) ' Output two bytes beginning at
' location of PutData(1)
End Sub