PIC as I2C Master/Slaves


Closed Thread
Results 1 to 5 of 5
  1. #1
    Adamey's Avatar
    Adamey Guest

    Default PIC as I2C Master/Slaves

    Hello, new member here and first post.

    I got into PIC's by learning on PICAXE. One thing that makes PICAXE great for beginners is the built-in functions that let you develop programs quickly without worrying about all the code running underneath. The drawback is that there are limitations (like program size and speed). My needs have grown beyond what I can do with a PICAXE, so I picked up PBP and a programmer and am starting to learn more about PICs and how they work.

    I have a project that I got working using four PICAXE chips, one acting as the master and three as slaves. All communicate using I2C. The built-in functions for I2C on the PICAXE I found extremely useful. The master can read and write data to the slaves at will, without affecting the operation of any program running on the slave PICAXE. In essence, the slave PICAXE behaves just like an I2C EEPROM. When data is written to the slave PICAXE, an interrupt is set so the slave knows it has data "waiting".

    I used this in a project where the slaves are gathering data from various sources, performing math on the data and placing the results in scratchpad memory for the master to read (polled at specific intervals). I also have the master send "commands" to the slaves by placing data into their scratchpad memory. The slaves then go and perform tasks on their own while the master continues on with its own tasks (mainly user input and data display).


    I did search the forums for I2C communication and PIC to PIC, but haven't yet seen anything similar to this. I'm wondering if anyone has done something like this, and what methods they used (I2C, HSERIN/OUT or something else). I have a feeling this might be a significant programming challenge.

  2. #2
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default Re: PIC as I2C Master/Slaves

    Hi, and welcome!

    You might find this example useful: http://www.picbasic.co.uk/forum/content.php?r=224 I have not used I2C yet, so I can't give you much advice, but there are plenty of folks here that have.

    Walter

  3. #3
    Join Date
    Sep 2005
    Location
    Campbell, CA
    Posts
    1,107


    Did you find this post helpful? Yes | No

    Default Re: PIC as I2C Master/Slaves

    This may help. 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
    Charles Linquist

  4. #4
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default Re: PIC as I2C Master/Slaves

    Thanks Charles! When I saw you mention it earlier on the other thread, I was tempted to ask you for it. Very nice work.

  5. #5
    Join Date
    Sep 2005
    Location
    Campbell, CA
    Posts
    1,107


    Did you find this post helpful? Yes | No

    Default Re: PIC as I2C Master/Slaves

    It should be "plug and play" in virtually any 18F chip. I have a full ASM version working, but it hasn't been tested to the degree this code has.
    Charles Linquist

Members who have read this thread : 2

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