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 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