Bit bash SPI master and slave.


Today 08:45
Forum: The Lounge
Starter: normnet
Views: 0
Replies: 2
Yesterday 15:38
Forum: Proton Plus Compiler v3
Starter: gdesantis
Views: 0
Replies: 4
+ Reply to Thread
Results 1 to 10 of 10

Thread: Bit bash SPI master and slave.25 days old

  1. #1
    Prolific Poster towlerg's Avatar
    Join Date
    Mar 2012
    Posts
    1,857
    Thumbs Up
    Received: 163
    Given: 162
    Total Downloaded
    3.24 GB

    0 Not allowed!

    Default Bit bash SPI master and slave.

    Save me reinventing the wheel, does anybody have a example of master slave (2 PIC devices back to back) which allows 2 way comms?
    George

  2. #2
    Member teo's Avatar
    Join Date
    Sep 2010
    Posts
    266
    Thumbs Up
    Received: 9
    Given: 1
    Total Downloaded
    3.76 GB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Hi everyone,
    I also need to communicate between 18F46F22 (master) and 18F25K22 (slave).
    Wonderful would be if you can hardware SPI (speed is higher).
    Thanks in advance,
    Teo

  3. #3
    Prolific Poster towlerg's Avatar
    Join Date
    Mar 2012
    Posts
    1,857
    Thumbs Up
    Received: 163
    Given: 162
    Total Downloaded
    3.24 GB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Seach for SPI master slave, Les has an example.
    George

  4. #4
    Member teo's Avatar
    Join Date
    Sep 2010
    Posts
    266
    Thumbs Up
    Received: 9
    Given: 1
    Total Downloaded
    3.76 GB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Thanks a lot,
    Teo

  5. #5
    Fanatical Contributor Tim's Avatar
    Join Date
    Jan 2003
    Posts
    7,564
    Thumbs Up
    Received: 65
    Given: 91
    Total Downloaded
    895.24 MB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Hi George

    I have code, Its interrupt driven on the SPI slave side, tested working... I will post it tomorrow.
    Tim

  6. #6
    Fanatical Contributor Tim's Avatar
    Join Date
    Jan 2003
    Posts
    7,564
    Thumbs Up
    Received: 65
    Given: 91
    Total Downloaded
    895.24 MB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Hi George

    A taster of the code,

    The way it works is you allocate a set of regs and the master reads or writes to them. In my I have the first reg as a command byte so the main code can get flagged it needs to read or what ever when something is changed. Comments explain it.

    Some of the master code is later below



    Code:
        SPI_INTERRUPT:    If SSPIF = cTrue Then                                                        ; Do we have the right interrupt?            bSPIData= SSPBUF                                                         ; Read in the data from the buffer                     Select bSPI_State	                                                    ; Now handle were we are in our state machine                     Case cSPI_ReadCommand                                                    ; First byte in this session so read in the command                          If fSPI_Write_Bit = cTrue Then                                        ; We have a write command                bSPI_Address = bSPIData & 0x0F                                    ; Mask it so we have our address                bSPI_State = cSPI_Write                                           ; Change State to Writing                Else                                                                 ; We have a read command                bSPI_Address = bSPIData & 0x0F                                    ; Mask it so we have our address                bSPI_State = cSPI_Read                                            ; Change State read                 SSPBUF = aSPI_RegBuffer[bSPI_Address]                             ; Write the data from the regs to the buffer so next read is ready                Inc bSPI_Address              EndIf                Case cSPI_Write            aSPI_RegBuffer[bSPI_Address] = bSPIData            If bSPI_Address = 0 Then                fConFigRegUpdated = cTrue            EndIf            If bSPI_Address < cSPI_MaxRegs Then                                   ; Incrument our address if its not going to go past our max                Inc bSPI_Address            EndIf          Case cSPI_Read                        SSPBUF = aSPI_RegBuffer[bSPI_Address]                                 ; Write the data from the regs to the buffer            If bSPI_Address < cSPI_MaxRegs Then                                   ; Incrument our address if its not going to go past our max                Inc bSPI_Address            EndIf                         EndSelect            EndIf        SSPIF = 0             Retfie Fast



    Code:
    '-----------------------------------------------------------------------------
    ' Transmit and receive one byte using SPI mode 3 protocol' Input     : WREG = 8-bit value to send'           : SCLK_Pin holds the Port.bit of the SPI Clock pin'           : MISO_Pin holds the Port.bit of the SPI Data out Pin' Output    : WREG = 8-Bit value received' Notes     : SCLK is idle-high, and bits are latched on SCLK rising'    $define SPI_RWrite(pByteout) _SPI_Out3 pByteout        _SPI_Out3 Macro pByteout \Byte        #if(Prm_Count >= 1)            #if((Prm_1 == Num8) || (Prm_1 == Num16) || (Prm_1 == Num32))                Num_Wreg pByteout            #else                Byte_Wreg pByteout            #endif        #else            WREG = 0        #endif        GoSub __SPI_Out3        #if(_SPI_Out3_Return == 1)            #if(Return_Type == Byte)                Wreg_Byte Return_Var            #endif            #if(Return_Type == Word)                Wreg_Word Return_Var            #endif            #if(Return_Type == Dword)                Wreg_Dword Return_Var            #endif        #endif    Endm        #ifMacro- _SPI_Out3    __SPI_Out3:        SPITemp = WREG                              ' Transfer the WREG into bSPI_Data        For SpiIndex = 7 To 0 Step -1               ' Single byte SPI loop            Low SCLK_Pin                            ' Set SCLK low            SPIDelay            MOSI_Pin = SPITemp.7                    ' Put current outgoing bit on MISO_Pin            SPITemp = SPITemp << 1                  ' Shift next bit into MSB            SPIDelay            High SCLK_Pin                           ' let SCLK float high            bSPIBit = MISO_Pin            SPITemp = SPITemp | MISO_Pin            ' Capture current bit on MOSI_Pin        Next                PostSPI_Delay        WREG = SPITemp                              ' Transfer bSPI_Data into WREG        Return    #endIfMacro-

    Making contact with the slave is simple


    Code:
                Select_BubbleBoard 
                SPI_RWrite(cR_AreaOfTubeValueReg | $80)            SPI_RWrite(wAdjustValue.Byte0)            SPI_RWrite(wAdjustValue.Byte1)             DeSelect_BubbleBoard 
    Tim

  7. #7
    Fanatical Contributor Tim's Avatar
    Join Date
    Jan 2003
    Posts
    7,564
    Thumbs Up
    Received: 65
    Given: 91
    Total Downloaded
    895.24 MB

    1 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Code display is not working I will try another way


    Code:
    SPI_INTERRUPT:
    
    
        If SSPIF = cTrue Then                                                        ; Do we have the right interrupt?
        
            bSPIData= SSPBUF                                                         ; Read in the data from the buffer
                 
            Select bSPI_State                                                        ; Now handle were we are in our state machine
                 
            Case cSPI_ReadCommand                                                    ; First byte in this session so read in the command 
                 
                If fSPI_Write_Bit = cTrue Then                                        ; We have a write command
                    bSPI_Address = bSPIData & 0x0F                                    ; Mask it so we have our address
                    bSPI_State = cSPI_Write                                           ; Change State to Writing    
                Else                                                                 ; We have a read command
                    bSPI_Address = bSPIData & 0x0F                                    ; Mask it so we have our address
                    bSPI_State = cSPI_Read                                            ; Change State read 
                    SSPBUF = aSPI_RegBuffer[bSPI_Address]                             ; Write the data from the regs to the buffer so next read is ready
                    Inc bSPI_Address  
                EndIf
            
            Case cSPI_Write
                aSPI_RegBuffer[bSPI_Address] = bSPIData
                If bSPI_Address = 0 Then
                    fConFigRegUpdated = cTrue
                EndIf
                If bSPI_Address < cSPI_MaxRegs Then                                   ; Incrument our address if its not going to go past our max
                    Inc bSPI_Address
                EndIf  
            Case cSPI_Read
                
                SSPBUF = aSPI_RegBuffer[bSPI_Address]                                 ; Write the data from the regs to the buffer
                If bSPI_Address < cSPI_MaxRegs Then                                   ; Incrument our address if its not going to go past our max
                    Inc bSPI_Address
                EndIf         
            
            EndSelect
            
        EndIf
        
        SSPIF = 0        
    
    
        Retfie Fast


    Code:
    '-----------------------------------------------------------------------------' Transmit and receive one byte using SPI mode 3 protocol
    ' Input     : WREG = 8-bit value to send
    '           : SCLK_Pin holds the Port.bit of the SPI Clock pin
    '           : MISO_Pin holds the Port.bit of the SPI Data out Pin
    ' Output    : WREG = 8-Bit value received
    ' Notes     : SCLK is idle-high, and bits are latched on SCLK rising
    '
        $define SPI_RWrite(pByteout) _SPI_Out3 pByteout
        
        _SPI_Out3 Macro pByteout \Byte
            #if(Prm_Count >= 1)
                #if((Prm_1 == Num8) || (Prm_1 == Num16) || (Prm_1 == Num32))
                    Num_Wreg pByteout
                #else
                    Byte_Wreg pByteout
                #endif
            #else
                WREG = 0
            #endif
            GoSub __SPI_Out3
            #if(_SPI_Out3_Return == 1)
                #if(Return_Type == Byte)
                    Wreg_Byte Return_Var
                #endif
                #if(Return_Type == Word)
                    Wreg_Word Return_Var
                #endif
                #if(Return_Type == Dword)
                    Wreg_Dword Return_Var
                #endif
            #endif
        Endm
        
        #ifMacro- _SPI_Out3
        __SPI_Out3:
            SPITemp = WREG                              ' Transfer the WREG into bSPI_Data
            For SpiIndex = 7 To 0 Step -1               ' Single byte SPI loop
                Low SCLK_Pin                            ' Set SCLK low
                SPIDelay
                MOSI_Pin = SPITemp.7                    ' Put current outgoing bit on MISO_Pin
                SPITemp = SPITemp << 1                  ' Shift next bit into MSB
                SPIDelay
                High SCLK_Pin                           ' let SCLK float high
                bSPIBit = MISO_Pin
                SPITemp = SPITemp | MISO_Pin            ' Capture current bit on MOSI_Pin
            Next        
            PostSPI_Delay
            WREG = SPITemp                              ' Transfer bSPI_Data into WREG
            Return
        #endIfMacro-

    Code:
    Select_BubbleBoard 
    SPI_RWrite(cR_NCUnitConfig)  
    SPI_RWrite(cUpdateAoTV)
    DeSelect_BubbleBoard
    Tim

  8. #8
    Fanatical Contributor Tim's Avatar
    Join Date
    Jan 2003
    Posts
    7,564
    Thumbs Up
    Received: 65
    Given: 91
    Total Downloaded
    895.24 MB

    1 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Here is the SPI slave code There is more than needed but I tried to remove the chaff

    Code:
        
    ;-------------------------------------------------------------------------------
    ;**** Added by Fuse Configurator ****
    ; Use the Fuse Configurator plug-in to change these settings
    
    
    Device = 18F13K22
    
    
    Config_Start
      FOSC = HS	;HS oscillator
      PLLEN = On	;Oscillator multiplied by 4
      PCLKEN = On	;Primary clock enabled
      FCMEN = OFF	;Fail-Safe Clock Monitor disabled
      IESO = OFF	;Oscillator Switchover mode disabled
      PWRTEN = On	;PWRT enabled
      BOREN = SBORDIS	;Brown-out Reset enabled in hardware only (SBOREN is disabled)
      BORV = 19	;VBOR set to 1.9 V nominal
      WDTEN = OFF	;WDT is controlled by SWDTEN bit of the WDTCON register
      WDTPS = 32768	;1:32768
      HFOFST = On	;HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.
      MCLRE = On	;MCLR pin enabled, RA3 input pin disabled
      STVREN = On	;Stack full/underflow will cause Reset
      LVP = OFF	;Single-Supply ICSP disabled
      BBSIZ = OFF	;512W boot block size
      XINST = OFF	;Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
      Debug = OFF	;Background debugger disabled, RA0 and RA1 configured as general purpose I/O pins
      Cp0 = OFF	;Block 0 not code-protected
      CP1 = OFF	;Block 1 not code-protected
      CPB = OFF	;Boot block not code-protected
      CPD = OFF	;Data EEPROM not code-protected
      WRT0 = OFF	;Block 0 not write-protected
      WRT1 = OFF	;Block 1 not write-protected
      WRTC = OFF	;Configuration registers not write-protected
      WRTB = OFF	;Boot block not write-protected
      WRTD = OFF	;Data EEPROM not write-protected
      EBTR0 = OFF	;Block 0 not protected from table reads executed in other blocks
      EBTR1 = OFF	;Block 1 not protected from table reads executed in other blocks
      EBTRB = OFF	;Boot block not protected from table reads executed in other blocks
    Config_End
    
    
    ;**** End of Fuse Configurator Settings ****
    ;-------------------------------------------------------------------------------
    
    
    
    
        
        Declare Create_Coff = On
                                      
        Xtal = 48
    	
        Declare Dead_Code_Remove = On  
        Declare Optimiser_Level = 3 
        Declare Unsigned_Dwords = 1
    
    
    ; Jump over all routines etc
    
    
        GoTo Start
        
        
    ;=== interrupt based defines ===============================
    
    
        On_Interrupt     GoTo SPI_INTERRUPT   ; RE-MAP INT VECTORS
        On_Low_Interrupt GoTo TMR_INTERRUPT    ; RE-MAP INT VECTORS
        
        Symbol C1CH0 = CM1CON0.0 ' Comparator C1 Channel Select bit
        Symbol C1CH1 = CM1CON0.1 ' Comparator C1 Channel Select bit
        Symbol C1R = CM1CON0.2   ' Comparator C1 Reference Select bit
        Symbol C1SP = CM1CON0.3  ' Comparator C1 Speed/Power Select bit
        Symbol C1POL = CM1CON0.4 ' Comparator C1 Output Polarity Select bit
        Symbol C1OE = CM1CON0.5  ' Comparator C1 Output Enable bit
        Symbol C1OUT = CM1CON0.6 ' Comparator C1 Output bit
        Symbol C1ON = CM1CON0.7  ' Comparator C1 Enable bit
    
    
        Symbol C2SYNC = CM2CON1.0
        Symbol C1SYNC = CM2CON1.1
        Symbol C2HYS = CM2CON1.2
        Symbol C1HYS = CM2CON1.3
        Symbol C2RSEL = CM2CON1.4
        Symbol C1RSEL = CM2CON1.5
        Symbol MC2OUT = CM2CON1.6
        Symbol MC1OUT = CM2CON1.7
    
    
        Symbol C2CH0 = CM2CON0.0 ' Comparator C2 Channel Select bits
        Symbol C2CH1 = CM2CON0.1 ' Comparator C2 Channel Select bits
        Symbol C2R = CM2CON0.2   ' Comparator C2 Reference Select bits
        Symbol C2SP = CM2CON0.3  ' Comparator C2 Speed/Power Select bit
        Symbol C2POL = CM2CON0.4 ' Comparator C2 Output Polarity Select bit
        Symbol C2OE = CM2CON0.5  ' Comparator C2 Output Enable bit
        Symbol C2OUT = CM2CON0.6 ' Comparator C2 Output bit
        Symbol C2ON = CM2CON0.7  ' Comparator C2 Enable bit
        
        Symbol TMR1ON = T1CON.0     ' Timer1 On bit
        Symbol TMR1CS = T1CON.1     ' Timer1 Clock Source Select bit
        Symbol NOT_T1SYNC = T1CON.2 ' Timer1 External Clock Input Synchronization Select bit
        Symbol T1SYNC = T1CON.2     ' Timer1 External Clock Input Synchronization Select bit
        Symbol T1OSCEN = T1CON.3    ' Timer1 Oscillator Enable bit
        Symbol T1CKPS0 = T1CON.4    ' Timer1 Input Clock Prescale Select bits
        Symbol T1CKPS1 = T1CON.5    ' Timer1 Input Clock Prescale Select bits
        Symbol T1RUN = T1CON.6      ' Timer1 System Clock Status bit
        Symbol RD16 = T1CON.7       ' 16-bit Read/Write Mode Enable bit
    
    
        Symbol TMR1IE = PIE1.0 ' TMR1 Overflow Interrupt Enable bit
        Symbol TMR2IE = PIE1.1 ' TMR2 to PR2 Match Interrupt Enable bit
        Symbol CCP1IE = PIE1.2 ' CCP1 Interrupt Enable bit
        Symbol SSPIE = PIE1.3  ' Master Synchronous Serial Port Interrupt Enable bit
        Symbol TXIE = PIE1.4   ' EUSART Transmit Interrupt Enable bit
        Symbol RCIE = PIE1.5   ' EUSART Receive Interrupt Enable bit
        Symbol ADIE = PIE1.6   ' A/D Converter Interrupt Enable bit
    
    
        Symbol TMR1IF = PIR1.0 ' TMR1 Overflow Interrupt Flag bit
        Symbol TMR2IF = PIR1.1 ' TMR2 to PR2 Match Interrupt Flag bit
        Symbol CCP1IF = PIR1.2 ' CCP1 Interrupt Flag bit
        Symbol SSPIF = PIR1.3  ' Master Synchronous Serial Port Interrupt Flag bit
        Symbol TXIF = PIR1.4   ' EUSART Transmit Interrupt Flag bit
        Symbol RCIF = PIR1.5   ' EUSART Receive Interrupt Flag bit
        Symbol ADIF = PIR1.6   ' A/D Converter Interrupt Flag bit
    
    
        Symbol BOR = RCON.0     ' Brown-out Reset Status bit
        Symbol NOT_BOR = RCON.0 ' Brown-out Reset Status bit
        Symbol NOT_POR = RCON.1 ' Power-on Reset Status bit
        Symbol POR = RCON.1     ' Power-on Reset Status bit
        Symbol NOT_PD = RCON.2  ' Power-down Detection Flag bit
        Symbol PD = RCON.2      ' Power-down Detection Flag bit
        Symbol NOT_TO = RCON.3  ' Watchdog Time-out Flag bit
    ;    Symbol To = RCON.3      ' Watchdog Time-out Flag bit
        Symbol NOT_RI = RCON.4  ' RESET Instruction Flag bit
        Symbol RI = RCON.4      ' RESET Instruction Flag bit
        Symbol SBOREN = RCON.6  ' BOR Software Enable bit
        Symbol IPEN = RCON.7    ' Interrupt Priority Enable bit
    
    
        Symbol TMR1IP = IPR1.0 ' TMR1 Overflow Interrupt Priority bit
        Symbol TMR2IP = IPR1.1 ' TMR2 to PR2 Match Interrupt Priority bit
        Symbol CCP1IP = IPR1.2 ' CCP1 Interrupt Priority bit
        Symbol SSPIP = IPR1.3  ' Master Synchronous Serial Port Interrupt Priority bit
        Symbol TXIP = IPR1.4   ' EUSART Transmit Interrupt Priority bit
        Symbol RCIP = IPR1.5   ' EUSART Receive Interrupt Priority bit
        Symbol ADIP = IPR1.6   ' A/D Converter Interrupt Priority bit
    
    
        Symbol RABIF = INTCON.0     ' RA and RB Port Change Interrupt Flag bit
        Symbol RBIF = INTCON.0      ' RA and RB Port Change Interrupt Flag bit
        Symbol INT0F = INTCON.1     ' INT0 External Interrupt Flag bit
        Symbol INT0IF = INTCON.1    ' INT0 External Interrupt Flag bit
        Symbol T0IF = INTCON.2      ' TMR0 Overflow Interrupt Flag bit
        Symbol TMR0IF = INTCON.2    ' TMR0 Overflow Interrupt Flag bit
        Symbol RABIE = INTCON.3     ' RA and RB Port Change Interrupt Enable bit
        Symbol RBIE = INTCON.3      ' RA and RB Port Change Interrupt Enable bit
        Symbol INT0E = INTCON.4     ' INT0 External Interrupt Enable bit
        Symbol INT0IE = INTCON.4    ' INT0 External Interrupt Enable bit
        Symbol T0IE = INTCON.5      ' TMR0 Overflow Interrupt Enable bit
        Symbol TMR0IE = INTCON.5    ' TMR0 Overflow Interrupt Enable bit
        Symbol GIEL = INTCON.6      ' Peripheral Interrupt Enable bit
        Symbol PEIE = INTCON.6      ' Peripheral Interrupt Enable bit
        Symbol PEIE_GIEL = INTCON.6 ' Peripheral Interrupt Enable bit
        Symbol PIE = INTCON.6       ' Peripheral Interrupt Enable bit
        Symbol GIE = INTCON.7       ' Global Interrupt Enable bit
        Symbol GIE_GIEH = INTCON.7  ' Global Interrupt Enable bit
        Symbol GIEH = INTCON.7      ' Global Interrupt Enable bit
    
    
        Symbol ADON = ADCON0.0        ' ADC Enable bit
        Symbol DONE = ADCON0.1        ' A/D Conversion Status bit
        Symbol GO = ADCON0.1          ' A/D Conversion Status bit
        Symbol GO_DONE = ADCON0.1     ' A/D Conversion Status bit
        Symbol GO_NOT_DONE = ADCON0.1 ' A/D Conversion Status bit
        Symbol NOT_DONE = ADCON0.1    ' A/D Conversion Status bit
        Symbol CHS0 = ADCON0.2        ' Analog Channel Select bits
        Symbol CHS1 = ADCON0.3        ' Analog Channel Select bits
        Symbol CHS2 = ADCON0.4        ' Analog Channel Select bits
        Symbol CHS3 = ADCON0.5        ' Analog Channel Select bits
    
    
        Symbol NVCFG0 = ADCON1.0 ' Negative Voltage Reference select bit
        Symbol NVCFG1 = ADCON1.1 ' Negative Voltage Reference select bit
        Symbol PVCFG0 = ADCON1.2 ' Positive Voltage Reference select bit
        Symbol PVCFG1 = ADCON1.3 ' Positive Voltage Reference select bit
        
        Symbol ADCS0 = ADCON2.0 ' A/D Conversion Clock Select bits
        Symbol ADCS1 = ADCON2.1 ' A/D Conversion Clock Select bits
        Symbol ADCS2 = ADCON2.2 ' A/D Conversion Clock Select bits
        Symbol ACQT0 = ADCON2.3 ' A/D Acquisition Time Select bits. Acquisition time is the duration that the A/D charge
        Symbol ACQT1 = ADCON2.4 ' A/D Acquisition Time Select bits. Acquisition time is the duration that the A/D charge
        Symbol ACQT2 = ADCON2.5 ' A/D Acquisition Time Select bits. Acquisition time is the duration that the A/D charge
        Symbol ADFM = ADCON2.7  ' A/D Conversion Result Format Select bit
    
    
    
    
    ; IO Pins
    
    
        Dim pSDO_Pin As PORTC.7
        Dim pSS_Pin As  PORTC.6
                
    ; Variables etc
    
    
        Dim rwADCResult As ADRESL.Word                                    ; Alias for the AD converter vars
        Dim rwFSR_0 As FSR0L.Word
        Dim rwFSR_1 As FSR1L.Word
        Dim rwFSR_2 As FSR2L.Word
        
        Dim rwTIMER1REG As TMR1L.Word
        
        Symbol cFalse = 0
        Symbol cTrue = 1
    
    
    
    
        Symbol cTMR1_VAL = $FDAD;                                                    ; Interrupt at 20,000 hz
    
    
    
    
    
    
    
    
        
        Dim wSTempWord1 As Word    
        Dim wSTempWord2 As Word    
        Dim dSTempDWord1 As Dword
        Dim dSTempDWord2 As Dword
        
        Dim bTempByte1 As Byte
        Dim wTempWord1 As Word
        Dim wTempWord2 As Word
        Dim dTempDword1 As Dword
        Dim dTempDword2 As Dword
        
        Dim cSPIRegs As 10                                                           ; 10 Regs in the buffer
        Dim cSPI_MaxRegs As cSPIRegs 
        Dim aSPI_RegBuffer[cSPIRegs] As Byte At 200
        Dim bR_NCUnitConfig As Byte At 200
        Dim wR_CurrentBubbleVolume As Word At 201 
        Dim wR_CurrentBubbleLength As Word At 203
        Dim bR_FaultReg As Byte At 205
        Dim wR_AreaOfTubeValue As Word At 206
        Dim bR_DAC_Value As Byte At 208
        
        Dim fGetReadToShutDown As bR_NCUnitConfig.7                                   ; Set this bit to perform an EEwrite on associated regs
        Dim fUpdateDAC As bR_NCUnitConfig.6                                           ; Update System with New DAC value
        Dim fUpdateAoTV As bR_NCUnitConfig.5                                          ; Update Area of Tube Value 
        Dim fResetCount As bR_NCUnitConfig.4                                          ; Clear the tally so results are zeroed. This is done at the start of the fill
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    
        
        Dim bHz100Cntr As Byte                                                       ; 100 hz counter
        Dim cHz100CntrValue As 199
        Dim fHz100Flag As Bit
        Dim fRegUpdateRequired As Bit                                                ; 
        Dim wHalfSecCounter As Word                                                  ; Half sec counter
        Dim cHz10000 As 9999                                                         ; Number of counts of our interrupt to get 1/2 second
        Dim cHalfSecFlag As Bit                                                      ; Half second Flag
                                                                
        Dim wOneSecCntr As Word                                                      ; 1 second Counter                        
        Dim cOneSecCntrValue  As 19999
        Dim fOneSecFlag As Bit
        Dim fADCToggle As Bit
        
                                                                         
    
    
    ; Define the regs the unit will use to talk to the outside world
        
        Dim bSPIData As Byte
        Dim fSPI_Write_Bit As bSPIData.7
        Dim bSPI_State As Byte
        Dim bSPI_Address As Byte
        Dim cSPI_ReadCommand As 0
        Dim cSPI_Read As 1
        Dim cSPI_Write As 2
        
        Dim fConFigRegUpdated As Bit
            
    
    
    
    
        Dim bSpiIntTemp As Byte    
        
        
        
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    
    
        $define IntsOff GIE = 0
    
    
        $define IntsOn GIE = 1
    
    
     
    
    
    TMR_INTERRUPT:
        Context Save
    
    
        If TMR1IF = cTrue Then
        ;Reaload the timer
            TMR1ON = 0                                                              ; STOP THE TIMER
            rwTIMER1REG = rwTIMER1REG + cTMR1_VAL                                        ' LOAD TMR1
            Set TMR1ON                                                              ' START THE TIMER AGAIN 
    
    
            If wHalfSecCounter = cHz10000 Then
                wHalfSecCounter = 0
                cHalfSecFlag = cTrue
            Else
                Inc wHalfSecCounter
            EndIf
    
    
            ;1 Hz counter    
            If wOneSecCntr > 0  Then
                Dec wOneSecCntr
            Else
                fOneSecFlag = cTrue                
                wOneSecCntr = cOneSecCntrValue
            EndIf 
            
            ; 100 hz timer
            If bHz100Cntr > 0 Then
                Dec bHz100Cntr
            Else
                fHz100Flag = cTrue
                bHz100Cntr = cHz100CntrValue
            EndIf 
            
            TMR1IF = 0                                                                  ; Clear TMR1 interrupt flag 
            
    LowIntExit:    
        Context Restore
        
        
        
    
    
    SPI_INTERRUPT:
    
    
        If SSPIF = cTrue Then                                                        ; Do we have the right interrupt?
        
            bSPIData= SSPBUF                                                         ; Read in the data from the buffer
                 
            Select bSPI_State	                                                    ; Now handle were we are in our state machine
                 
            Case cSPI_ReadCommand                                                    ; First byte in this session so read in the command 
                 
                If fSPI_Write_Bit = cTrue Then                                        ; We have a write command
                    bSPI_Address = bSPIData & 0x0F                                    ; Mask it so we have our address
                    bSPI_State = cSPI_Write                                           ; Change State to Writing    
                Else                                                                 ; We have a read command
                    bSPI_Address = bSPIData & 0x0F                                    ; Mask it so we have our address
                    bSPI_State = cSPI_Read                                            ; Change State read 
                    SSPBUF = aSPI_RegBuffer[bSPI_Address]                             ; Write the data from the regs to the buffer so next read is ready
                    Inc bSPI_Address  
                EndIf
            
            Case cSPI_Write
                aSPI_RegBuffer[bSPI_Address] = bSPIData
                If bSPI_Address = 0 Then
                    fConFigRegUpdated = cTrue
                EndIf
                If bSPI_Address < cSPI_MaxRegs Then                                   ; Incrument our address if its not going to go past our max
                    Inc bSPI_Address
                EndIf  
            Case cSPI_Read
                
                SSPBUF = aSPI_RegBuffer[bSPI_Address]                                 ; Write the data from the regs to the buffer
                If bSPI_Address < cSPI_MaxRegs Then                                   ; Incrument our address if its not going to go past our max
                    Inc bSPI_Address
                EndIf         
            
            EndSelect
            
        EndIf
        
        SSPIF = 0        
    
    
        Retfie Fast
        
            
            
                
        
    Initialise:
        
        Clear                                                                       ; Clear all ram to 0
        
        
        '----- SET UP TIMER 1 INTERRUPT ----------------------------
    
    
        IPEN = 1                                                        ' Enable priority interrupts.
        
        
        TMR1IP = 0                                                      ' Timer1 has low priority
        rwTIMER1REG = cTMR1_VAL
        T1CON = %00000000                                               ' Set up Tmr1 to have 1:1 prescaler and act as a timer
        TMR1IF = 0                                                      ' Clear Tmr1 interrupt flag
    
    
        TMR1IE = 1                                                      ' Enable Tmr1 as peripheral interrupt source
        TMR1ON = 1
        PEIE = 1                             
       ' GIE = 1                                                         ; Global and Peripheral interrupts o
    
    
     
    
    
    ; Set up the SPI slave in SPI mode 3 with SS active
    
    
        SSPADD = 0x3
        
        SSPBUF = 0X0
        
        SSPCON1 = 0x34; 0B00110100
    '    CKP = Idle High Active Low
    '    SSPEN Enabled
    '    SSPM SCKx_nSSxEnabled
    '    SSPOV No_Overflow
    '    WCOL no_Collision
        
        SSPCON2 = 0x0
        
        SSPMSK = 0xFF
        
        SSPSTAT = 0x0
        
        Output pSDO_Pin   ; SDO line
        
    	
    	SSPIP = 1 ; High Priority interrupt for SPI
    	SSPIE = 1 ; Enable the interrupt
    	  
    
    
    
    
                                                                    ; Start a conversion
           
        Return
    
    
        
    Start:
    
    
    
    
        DelayMS 500
        
        GoSub Initialise
        
    
    
        
        IntsOn
     
        
        While 1 = 1
        
            If pSS_Pin = 1 Then
                bSPI_State = cSPI_ReadCommand	                                    ; Reset our state machine when SS pin is released
            EndIf 
            
            If fConFigRegUpdated = cTrue Then
                fConFigRegUpdated = cFalse
                ; Update regs if need be, Remember to disable ints
            EndIf
            
        Wend

    Code:
        $define Select_BubbleBoard Clear BbCS_Pin
        $define DeSelect_BubbleBoard Set BbCS_Pin
    
    
    ;*******************************************************************************
    ; Delay routine
    ;
    ;*******************************************************************************
    
    
        $define SPIDelay DelayUS 5
        $define PostSPI_Delay DelayUS 15
    
    
        
    '-----------------------------------------------------------------------------
    ' Transmit and receive one byte using SPI mode 3 protocol
    ' Input     : WREG = 8-bit value to send
    '           : SCLK_Pin holds the Port.bit of the SPI Clock pin
    '           : MISO_Pin holds the Port.bit of the SPI Data out Pin
    ' Output    : WREG = 8-Bit value received
    ' Notes     : SCLK is idle-high, and bits are latched on SCLK rising
    '
        $define SPI_RWrite(pByteout) _SPI_Out3 pByteout
        
        _SPI_Out3 Macro pByteout \Byte
            #if(Prm_Count >= 1)
                #if((Prm_1 == Num8) || (Prm_1 == Num16) || (Prm_1 == Num32))
                    Num_Wreg pByteout
                #else
                    Byte_Wreg pByteout
                #endif
            #else
                WREG = 0
            #endif
            GoSub __SPI_Out3
            #if(_SPI_Out3_Return == 1)
                #if(Return_Type == Byte)
                    Wreg_Byte Return_Var
                #endif
                #if(Return_Type == Word)
                    Wreg_Word Return_Var
                #endif
                #if(Return_Type == Dword)
                    Wreg_Dword Return_Var
                #endif
            #endif
        Endm
        
        #ifMacro- _SPI_Out3
        __SPI_Out3:
            SPITemp = WREG                              ' Transfer the WREG into bSPI_Data
            For SpiIndex = 7 To 0 Step -1               ' Single byte SPI loop
                Low SCLK_Pin                            ' Set SCLK low
                SPIDelay
                MOSI_Pin = SPITemp.7                    ' Put current outgoing bit on MISO_Pin
                SPITemp = SPITemp << 1                  ' Shift next bit into MSB
                SPIDelay
                High SCLK_Pin                           ' let SCLK float high
                bSPIBit = MISO_Pin
                SPITemp = SPITemp | MISO_Pin            ' Capture current bit on MOSI_Pin
            Next        
            PostSPI_Delay
            WREG = SPITemp                              ' Transfer bSPI_Data into WREG
            Return
        #endIfMacro-
        
                                          ;MOSI MISO 
    
    
        $define InterSPIDelay DelayUS 3
    Start:
    
    
        DelayMS 1000
        
        High BbCS_Pin
        High MOSI_Pin
        Input MISO_Pin
        High SCLK_Pin
    
    
        While 1 = 1
            
            Select_BubbleBoard
             
            SPI_RWrite (cControlReg)
            bControlReg = SPI_RWrite(0)
            bBubbleVolume.Byte0 = SPI_RWrite(0)        
            DeSelect_BubbleBoard       
            DelayMS 10
            
        Wend
    Tim

  9. #9
    Fanatical Contributor Tim's Avatar
    Join Date
    Jan 2003
    Posts
    7,564
    Thumbs Up
    Received: 65
    Given: 91
    Total Downloaded
    895.24 MB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

    Some info on how you use it.

    The slave once set up sits with its state machine in wait for first byte state.
    When the SPI line is pulled low the pic then clocks in the data from the master. Once 8 bits have been read it will generate an interrupt and you can then look at the byte. You are supposed to supply the address in the first byte with read or write bit set.
    If it is a read it uses the address tpoint to an array element and pre loads the data into the SPI buffer so just clocking the SPI line transfers the data
    Write is much the same but since there is no data just the address it set the statemachine to take next byte and write it into the array.

    In the main code once the line goes low the statemachine is reset. You maybe able to use an interrupt somewhere to prevent looking in the main loop.

    In my code every time the config byte was written to I would set a flag to say so. So for instance if I wanted to write a word to the slave. You would do the following
    Select the slave
    Send the address in the array with write bit set
    write LSB
    write MSB
    Deselect Slave
    Small delay
    Select slave
    Address the Config byte
    write to config with flag to say new data sent
    deselect slave

    Slave now gets notified that there is new data and can process it.
    Note Its better to make copies of the data and not use the slave array. When you need to update it disable interrupts and write the data in then enable ints. Do it ASAP.

    Hope that help

    Tim
    Last edited by Tim; 23rd November 2018 at 10:02. Reason: Corrected txt
    Tim

  10. #10
    Prolific Poster towlerg's Avatar
    Join Date
    Mar 2012
    Posts
    1,857
    Thumbs Up
    Received: 163
    Given: 162
    Total Downloaded
    3.24 GB

    0 Not allowed!

    Default Re: Bit bash SPI master and slave.

  11. Cheers Tim, I shall read and digest, maybe come back with a question or two if thats OK.
    George

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

     

Similar Threads

  1. Master and Slave SPI Interrupt
    By ayhampic in forum Serial / Ethernet
    Replies: 15
    Last Post: 20th January 2014, 10:15
  2. Soft SPI Slave & Master
    By crankshaft in forum Proton Plus Compiler v3
    Replies: 0
    Last Post: 24th September 2012, 12:53
  3. Bit bashed SPI slave mode
    By david in forum The Lounge
    Replies: 0
    Last Post: 27th September 2008, 11:32
  4. Master to slave
    By jaygoldie in forum The Lounge
    Replies: 17
    Last Post: 29th May 2008, 15:51
  5. I2C Master / Slave
    By davroski in forum Proton Plus Compiler v3
    Replies: 2
    Last Post: 11th May 2005, 07:34

Members who have read this thread since 18th December 2018, 03:12 : 0

Actions :  (Set Date)  (Clear Date)

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts