News:

Let's find out together what makes a PIC Tick!

Main Menu

SPI BUFFERED

Started by Alex C., Feb 19, 2021, 09:04 AM

Previous topic - Next topic

Alex C.

Is there a procedure, like Buffered_Hrsin but for the SPI?
Thank you. Alex

keytapper

IIRC, there could be some example on the included files of the package.
Look at c:\\users/<your_user>/PDS/Samples/New Samples/Buffered_Hrsin/
Ignorance comes with a cost

TimB


SPI I think is not suitable for buffering

Normally you either request the data as a master so there is no point buffering.

If your a slave then its a different matter. You almost have to do it as a background interrupt

Can you elaborate what your doing?

Alex C.

Thank you for replay.
Yes the buffer is for the slave.
I am already using the buffer in the hrsin to communicate via serial with a pc, now I would need a new port to communicate with another micro. I need more micro because only one cannot manage it all. It is a control for a homemade amateur radio, which manages the radio, the cat, vfo, ect.
Alex

TimB

#4
Hi,

Some basics from what I learnt writing an SPI slave

1 You need to work with registers
2 The master is controlling the clock and expects the data to be there to clock in so you need to load the PicRxreg with the data before they do that. You are essentially exchanging data at exactly the same time
3 The first byte sent by the master needs to indicate the reg you want to address and if its a read or write request
4 You need to run a state machine to enable you to keep track of what is going on. When the SSline is released you reset the state machine.
5 The master needs to be patient. Write a command, wait a few us before expect being able to start reading the result or reg etc

Below is some code I stripped out of a project, The notes should be enough to help you through

If you think you can just insert this and use "other" interrupt code like that in the examples your not going to have any luck. You need to fully understand how interrupts work and the nuances of working with interrupts ref not screwing your variables up with no warnings.

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

   
    Symbol cFalse = 0
    Symbol cTrue = 1



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

; 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


       

   

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

     
    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 fRegUpdateRequired = cTrue Then                                       ; Check if we need to update the regs
            If pSS_Pin = 1 Then                                                  ; If we are not in the middle of a spi read/write
                fRegUpdateRequired = cFalse                                      ; clear the flag
                IntsOff
                ; Update the regs when you can be sure you will not be interrupted
                IntsOn
             EndIf
        EndIf
    Wend
 
   

             

Alex C.

Thanks for all the information, really very kind. Now I will try to understand something.
Alex

flosigud

16 bit PIC's have DMA that can buffer anything including SPI. Some PIC's have SPI with FIFO buffers.