Attribute VB_Name = "SPIUtils" Option Explicit ' The following routines provide a software interface to simplify SPI use. ' ' The hardware provides an expandable number of digital inputs and outputs based on ' 74HC589 and 74HC595 SPI compatible shift registers, an 8-channel/12-bit A/D ' converter based around the MAX147, and a 2-channel/4-preset voltage output based on a ' 74HC595 & 4051. ' ' A 74HC4066 analogue switch is used to prevent bus collisions with the onboard BX-24 EEPROM. ' The bus collision protection is totally transparent to the system and requires no software. ' ' The hardware schematics will be uploaded separately. '------------------------------------------------------------------------------- ' BX-24 pin definitions ' CS0 - CS3 are the chip select signals for the SPI devices. Change the pin ' assignments as required. ' ' LD is used to load external data to the input latches. Change pin assignment as ' required Public Const CS0 As Byte = 7 Public Const CS1 As Byte = 8 Public Const CS2 As Byte = 9 Public Const CS3 As Byte = 10 Public Const LD As Byte = 13 '------------------------------------------------------------------------------- ' Hardware configuration Public Const SPIOutputPorts As Byte = 4 '32-bits output Public Const SPIInputPorts As Byte = 4 '32-bits input '------------------------------------------------------------------------------- ' SPI Specific Declarations Const SPI_LSB As Byte = &H20 'lsb transmitted first Const SPI_CPOL As Byte = &H8 'sck is mostly high Const SPI_CPHA As Byte = &H4 'clock phase, see atmel docs for timing Const SPI_SCK4 As Byte = &H0 'clock speed f/4 Const SPI_SCK16 As Byte = &H1 'clock speed f/16 Const SPI_SCK64 As Byte = &H2 'clock speed f/64 Const SPI_SCK128 As Byte = &H3 'clock speed f/128 ' 'SPI Channel Declarations ' Public Const DigitalInput As Byte = 1 Public Const DigitalOutput As Byte = 2 Public Const AnalogueInput As Byte = 3 Public Const AnalogueOutput As Byte = 4 ' Public OutputBuffer(1 To SPIOutputPorts) As Byte 'Digital Output data storage Public InputBuffer(1 To SPIInputPorts) As Byte 'Digital Input data storage Dim ADInputBuffer(1 To 2) As Byte 'Analogue Input data buffer Dim DAOutputBuffer As Byte 'Analogue Output data buffer '------------------------------------------------------------------------------- 'Initalize SPI Channels Public Sub SPIInit() Dim intPort As Integer ' 'Open Digital output channel Call OpenSPI(DigitalOutput, SPI_SCK4 + SPI_LSB, CS1) 'Zero all outputs For intPort = 0 To (CInt(SPIOutputPorts - 1)) Call SPIPutByte(CByte(intPort), 0) Next ' 'Open Analogue output channel Call OpenSPI(AnalogueOutput, SPI_SCK4 , CS3) 'Zero both channels Call SPIPresetVoltage(3, 0) ' 'Open Digital input channel Call OpenSPI(DigitalInput, SPI_SCK4 , CS0) ' 'Open Analogue input channel Call OpenSPI(AnalogueInput, SPI_SCK4 , CS2) End Sub '------------------------------------------------------------------------------- 'Output byte bytData to port specified by bytPortID Public Sub SPIPutByte(ByVal bytPortID As Byte, ByVal bytData As Byte) If bytPortID < SPIOutputPorts Then 'Calculate port bytPortID = SPIOutputPorts - (bytPortID - 1) '**** next command commented out, was only necessary to recify PCB layout problem '**** Flip bits, to make LSB first '**** OutputBuffer(CInt(bytPortID + 1)) = FlipBits(bytData) 'Send to SPI bus Call SPICmd(DigitalOutput, SPIOutputPorts, OutputBuffer(1), 0, InputBuffer(1)) Else Debug.Print "SPIPutByte Invalid Port" End If End Sub '------------------------------------------------------------------------------- 'Set bit specified by bytBitID Public Sub SPISetBit(ByVal bytBitID As Byte) Dim intCount As Integer If bytBitID < (SPIOutputPorts * 8) Then 'Set bit Call PutBit(OutputBuffer, bytBitID, 1) 'SPI Output Call SPICmd(DigitalOutput, SPIOutputPorts, OutputBuffer(1), 0, InputBuffer(1)) Else Debug.Print "SPISetBit Invalid Bit" End If End Sub '------------------------------------------------------------------------------- 'Reset bit specified by bytBitID Public Sub SPIResetBit(ByVal bytBitID As Byte) If bytBitID < (SPIOutputPorts * 8) Then 'Reset Bit Call PutBit(OutputBuffer, bytBitID, 0) 'SPI Output Call SPICmd(DigitalOutput, SPIOutputPorts, OutputBuffer(1), 0, InputBuffer(1)) Else Debug.Print "SPIResetBit Invalid Bit" End If End Sub '------------------------------------------------------------------------------- 'Output bit value blnBitState to bit specified by bytBitID Public Sub SPIPutBit(ByVal bytBitID As Byte, ByVal blnBitState As Boolean) If bytBitID < (SPIOutputPorts * 8) Then 'Set bit value in buffer If blnBitState Then Call PutBit(OutputBuffer, bytBitID, 1) Else Call PutBit(OutputBuffer, bytBitID, 0) End If 'SPI Output Call SPICmd(DigitalOutput, SPIOutputPorts, OutputBuffer(1), 0, InputBuffer(1)) Else Debug.Print "SPIPutBit Invalid Bit" End If End Sub '------------------------------------------------------------------------------- 'Return byte value according to status of port bytPortID Public Function SPIReadByte(ByVal bytPortID As Byte) As Byte If bytPortID < SPIInputPorts Then 'Load 75HC589 Latch Call PutPin(LD, bxOutputHigh) Call PutPin(LD, bxOutputLow) 'SPI Input Call SPICmd(DigitalInput, 0, OutputBuffer(1), SPIInputPorts, InputBuffer(1)) SPIReadByte = InputBuffer(CInt(bytPortID + 1)) Else Debug.Print "SPIReadByte Invalid Port" End If End Function '------------------------------------------------------------------------------- ' Return boolean value according to status of input bit bytBitID Public Function SPIReadBit(ByVal bytBitID As Byte) As Boolean If bytBitID < (SPIInputPorts * 8) Then 'Load 74HC589 Latch Call PutPin(LD, bxOutputHigh) Call PutPin(LD, bxOutputLow) 'Read Port Data Call SPICmd(DigitalInput, 0, OutputBuffer(1), SPIInputPorts, InputBuffer(1)) If GetBit(InputBuffer, bytBitID) = 1 Then SPIReadBit = True Else SPIReadBit = False End If Else Debug.Print "SPIReadBit Invalid Bit" End If End Function '------------------------------------------------------------------------------- ' Return a value of 0 to 4095 (equivalent to 0.0v - 10.0v) as read from channel ' bytChannel. Public Function SPIGetADC(ByVal bytChannel As Byte) As Integer Dim ADCommand As Byte Select Case bytChannel ' ' Set MAX186 command byte according to channel. Please refer to MAX186 data ' sheet. Note unconventional channel selection pattern for bits 6, 5, 4. ' Case 0 ADCommand = bx10001110 Case 1 ADCommand = bx11001110 Case 2 ADCommand = bx10011110 Case 3 ADCommand = bx11011110 Case 4 ADCommand = bx10101110 Case 5 ADCommand = bx11101110 Case 6 ADCommand = bx10111110 Case 7 ADCommand = bx11111110 Case Else Debug.Print "SPIReadVoltage Invalid Ch" SPIGetADC = 0 Exit Function End Select 'Send Command & Get 2 conversion bytes Call SPICmd(AnalogueInput, 1, ADCommand, 2, ADInputBuffer(1)) SPIGetADC = CInt(ADInputBuffer(1)) * 32 + (CInt(ADInputBuffer(2) \ 8)) End Function '------------------------------------------------------------------------------- 'Apply preset voltage specfied by bytPreset to output channel bytChannel Sub SPIPresetVoltage(ByVal bytChannel As Byte, ByVal bytPreset As Byte) Select Case bytChannel Case 0 DAOutputBuffer = DAOutputBuffer And bx11110000 'Clear Channel 0 Nibble If (bytPreset <> 0) Then DAOutputBuffer = DAOutputBuffer Or (bytPreset - 1) 'Mask data for preset voltage Else DAOutputBuffer = DAOutputBuffer Or bx00001000 End If Case 1 DAOutputBuffer = DAOutputBuffer And bx00001111 'Clear Channel 1 Nibble If (bytPreset <> 0) Then DAOutputBuffer = ((bytPreset-1) * 16) Or DAOutputBuffer 'Shift data for preset voltage & mask to outputbyte Else DAOutputBuffer = DAOutputBuffer Or bx10000000 End If Case 3 DAOutputBuffer = bx10001000 'Clear both channels Case Else Debug.Print "SPIPresetVoltage Ch Error" End Select Call SPICmd(AnalogueOutput, 1, DAOutputBuffer, 0, InputBuffer(1)) End Sub '------------------------------------------------------------------------------- 'Test calls for compile verification - uncomment for testing purposes only. 'Otherwise may safely be deleted 'Sub Main() ' ' Dim blnDummy As Boolean ' Dim bytDummy As Byte ' Dim intDummy As Integer ' ' Call SPIInit ' Call SPIPutByte(0,0) ' Call SPISetBit(0) ' Call SPIResetBit(0) ' Call SPIPutBit(1,True) ' ' blnDummy = SPIReadBit(0) ' bytDummy = SPIReadByte(0) ' intDummy = SPIGetADC(0) ' ' Call SPIPresetVoltage (0,0) 'End sub