SSPINT

SSP_INT...... Master Synchronous Serial Port Interrupt

SSP_INT Uses PIR1,SSP1IF, PIE1,SSP1IE





INCLUDE "DT_INTS-18.bas"    '  Thanks Darrel!
INCLUDE "ReEnterPBP-18.bas"     ' 

ASM
INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
        INT_Handler    SSP_INT,  _I2C_Int,   PBP,  yes
        INT_Handler    TMR0_INT,  MainTimer, ASM, yes
    endm
    INT_CREATE               ; Creates the interrupt processor
endasm    





Charles Linquist
Post of 12-Feb-2011

Here is a fairly full-featured interrupt-driven I2C slave. The master part is easy. This slave relies on the work of many others, but I have added some bug fixes and extra features. For example, you can write 0xAA,0X55,0x00,**your new address here**,0x00 and you can change the address of the slave.

Like my other stuff, it ONLY works on 18F chips.

Code:
ASM
    ifndef __18F2321
        error "18F2321 not selected"
    endif
ENDASM 

ASM
       movlw 0x62                              ; %0110 0010  = 4 Mhz, internal osc block
       movwf OSCCON
       movlw 0x80                              ; %1000 0000  = PLL disabled
       movwf OSCTUNE
ENDASM       

        DATA @0,$38      ; Default I2C address if not determined in HW

        DEFINE OSC 4                                                          
        Define USE_LFSR 1

;---------------- Alias the bits ------------------------------------

    SSPIF               VAR PIR1.3    ' SSP (I2C) interrupt flag
    SSPIE               VAR PIE1.3    ' Int Enable

    SSPUA               VAR SSPSTAT.1
    SSPS                VAR SSPSTAT.3
    SSPP                VAR SSPSTAT.4
    SSPSMP              VAR SSPSTAT.7

    BF                  VAR SSPSTAT.0 ' SSP (I2C) Buffer Full
    R_W                 VAR SSPSTAT.2 ' SSP (I2C) Read/Write
    D_A                 VAR SSPSTAT.5 ' SSP (I2C) Data/Address
    CKP                 VAR SSPCON1.4  ' SSP (I2C) SCK Release Control
    SSPEN               VAR SSPCON1.5  ' SSP (I2C) Enable
    SSPOV               VAR SSPCON1.6  ' SSP (I2C) Receive Overflow Indicator
    WCOL                VAR SSPCON1.7  ' SSP (I2C) Write Collision Detect



     MasterClock VAR WORD BANKA SYSTEM  


'------------------- Buffer defintion --------------------
    RxBufferLEN         con 10         
    RxBuffer            var BYTE[Rxbufferlen + 1]    
    TxBufferLEN         CON 10
    TXBuffer            VAR BYTE[TxBufferLEN + 1]

    GeneralCall         VAR BIT
    RXBufferOverFlow    VAR BIT
    TxBufferUnderFlow   VAR BIT
    HWAddress           VAR BIT
    RXBufferPointer     VAR Byte
    TXBufferPointer     VAR Byte
    address             VAR BYTE
    x                   VAR BYTE
    dummy               var byte
    I2CAddress          VAR BYTE
    WCOLCounter         VAR BYTE
    I2CDeviceAddress     VAR BYTE
    Holdoff             VAR WORD ; retry timer

    HWAddress = 0       ; Get address from EEPROM, not pins

    TestArray   VAR BYTE [200]

    IF !HWAddress THEN
;----------- Get our Address from EEPROM --------------    
         READ 0,I2CAddress  
;-----------------------------------------------------     
    ELSE
;----------------OR Get our address from PORT B0..2-----------
        I2CDeviceAddress = PORTB & %00000111
        I2CMajorAddress     CON $3     ; upper 4 bits
        I2CAddress = (I2CMajorAddress <<4) | I2CDeviceAddress <<1 ; bit 0 is R/W
;---------------------------------------------------------------       
    Endif

    SSPADD = I2Caddress ' Move our address into the proper reg
    SSPCON2.0 = 1      ; Allow clock stretching
    SSPCON2.1 = 0      ; Set to 1 to enable masking of address 1 ; 0 is R/W bit
    SSPCON2.2 = 0      ; Set to 1 to enable masking of address bit 2
    SSPCON2.3 = 0      ; Set to 1 to enable masking of address bit 3
    SSPCON2.4 = 0      ; Set to 1 to enable masking of address bit 4
    SSPCON2.5 = 0      ; Set to 1 to enable masking of address bit 5
    SSPCON2.6 = 0      ; Not used in slave
    SSPCON2.7 = 1      ; General Call enabled
    SSPSTAT = 0
    SSPEN = 1             
    SSPIE = 1 
    SSPIF = 0 
    SSPCON1 = $36 		' Set to I2C slave with 7-bit address    

;---------------------------------------------------------------
    TRISA = %11111111
    TRISB = %11111111
    TRISC = %11111111

' -------------- Turn on Ints  ------------------------
    INTCON.7 = 1  ; global ints
    INTCON.6 = 1  ; peripheral ints
    IPR1.3 = 1    ; high priority

;------------------  Clear parameters --------------
    RXBufferPointer = 0
    TxBufferPointer = 0
    GeneralCall = 0 
    RxBufferOverFlow = 0
    TXBufferUnderFlow = 0
    WCOLCounter = 0
;----------------Timer Setup-----------------------------------  
     T0CON = %10000011 ; /16 prescaler
;-------- -------------------------------------------     
     WDTCON = 1  ; Turn on the WDT
;--------------------------------------------------------------   


INCLUDE "DT_INTS-18.bas"    '  Thanks Darrel!
INCLUDE "ReEnterPBP-18.bas"     ' 

ASM
INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
        INT_Handler    SSP_INT,  _I2C_Int,   PBP,  yes
        INT_Handler    TMR0_INT,  MainTimer, ASM, yes
    endm
    INT_CREATE               ; Creates the interrupt processor
endasm

''----------------- Initialization Done! -----------------------------

    Goto OverInt ; jump over ISR, don't execute it.
;----------------------- Timer INt ------------------------------------    
ASM
MainTimer
        movlw   0x00         ;  10 mSec
        movwf   TMR0H
        movlw   0x63
        movwf   TMR0L

        infsnz  MasterClock
        incf    MasterClock + 1

;    This is a good place to pick up pin changes        

 INT_ENABLE TMR0_INT
 INT_RETURN

ENDASM
;---------------------------------------------------------------------
'------------------------- I2C subroutine  -------------------------------- 
I2C_Int:
  ; We don't get here uless someone has matched our address register.

If R_W = 0 then             'This is a WRITE by the master to us
    IF BF = 0 Then goto i2CEXIT   ; Nothing for us!
    if D_A = 0 then         'We have an address
      address = SSPBUF     'Need to READ Address from buffer to clear it.

       IF Address = 0 THEN
           GeneralCall = 1   ; Set flag if we got a general call address 
       ELSE
           GeneralCall = 0     
       ENDIF


    else            
        IF WCOL OR SSPOV THEN I2CExit
         IF RXBufferPointer < RxBufferLen - 1 THEN
             RXBuffer [RxBufferPointer] = SSPBuf   ; 
             RxBufferPointer = RXBufferPointer + 1
         ELSE
             Dummy = SSPBuf  ; Grab the data but don't overwrite old
             RXBufferOverFlow = 1
         ENDIF 

        ENDIF


    else   ' R_W = 1 Master wants to read FROM us

          IF !D_A Then
                TxBufferPointer = 0		' Mark as first read
                RXBufferPointer = 0
          EndIF

          IF CKP THEN I2CExit

              dummy = SSPBUF  ;NECESSARY!

SENDI2C:
              WCOL = 0
                  SSPBUF = TXBuffer[TXBufferPointer]	' Get data from array
                   IF WCOL THEN 
                       WCOLCounter = WCOLCounter + 1            ; Don't hang the bus with infinite WRITES!
                       IF WColCounter >= 7 Then goto I2CExit     ; 7
                       RANDOM Holdoff
                       Pauseus Holdoff >> 3    ; wait 0-8 msec 
                       Goto SendI2C       ; Retry
                    ELSE
                       WColCounter = 0
                    ENDIF   
                   TXBufferPointer = TXBufferPointer + 1

             If TXBufferPointer = TXBufferLen THEN
                  TXBufferUnderflow = 1
                  TXBufferPointer = TXBufferLen - 1 ; Repeat last if req made again, but set flag now
             ENDIF
    ENDIF

I2CEXIT:
    SSPOV = 0
    BF = 0 
    sspif = 0
    CKP = 1 
@ INT_ENABLE SSP_INT      ; probably don't need this, but I like to be certain it gets restarted
@ INT_RETURN


' -------------------------end I2C subroutine  -------------------------------- 
'--------------------[End ISRs]---------------------------------------
OverInt:

@ INT_ENABLE  SSP_INT     
@ INT_ENABLE TMR0_INT
'--------------------[ main program loop]---------------------------------------
Main:
   IF RXBuffer[0] = $AA THEN
      IF RXBuffer[1] = $55 and RXBuffer[2] = 0  And RxBuffer[4] = 0 THEN
        Dummy = RXBuffer[3]
        WRITE 0,Dummy   ; Write a new address
        Pause 10
@ RESET  ; and pick up the new address      
      ENDIF 
   ENDIF
;-------------------  Load the input buffer to the output buffer for test -----------   
   For X = 0 to TXBufferLen - 1  
     TxBuffer[X] = RXBuffer[X]
    next x
;----------------------------------------------------------------------
goto main 

end

ASM
  ORG 0x0FF0  ; Keep track of pgm size in case we want to use it on a smaller chip
  NOP
ENDASM
Page last modified on March 07, 2018, at 05:59 PM