Use of the BX24 SPI Port in Controlling Multiple SPI Devices

copyright, Peter H. Anderson, Baltimore, MD, Feb, '00


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.


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
   For Address = 0 to 255	' write data, byte by byte to EEPROM
     Dat = CByte((255 - Address))
     Call SPIEEPROMWrite(Address, Dat)

   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(" "))
     '   Call NewLine()
     'End If
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