I2C Slave with a PIC


Closed Thread
Results 1 to 40 of 130

Hybrid View

  1. #1
    Join Date
    Mar 2008
    Location
    Gerogetown, Texas
    Posts
    94


    Did you find this post helpful? Yes | No

    Default

    Here is a working 18F2455 I2C slave. It will receive or send any amount of bytes you choose. The slave will not work if USB is enable on the chip.

    In this example the Master is sending 0 to 127 on byte(0), and fixed data on Bytes 1 and 2.

    The Slave sends three bytes back, tests the received byte(0) and lights a couple of leds. When the master sends (Byte(0) = 4), the slave ends three different bytes back. I also have eight leds connected to the slave, four on PortB 4-7 and four on PortA 0-3. These leds display the value of the received Byte(0).



    Slave code

    Code:
    '*  Date    : 3/17/2009                                         *
    '*  Version : 1.0                                               *
    '*  Notes   :                                                   *
    '*          :  18F2550 Slave I2c                                *
    '****************************************************************
    asm     __CONFIG    _CONFIG1L, _PLLDIV_5_1L & _FCMEN_OFF_1H
            __CONFIG    _CONFIG1H, _FOSC_HS_1H    
            __CONFIG    _CONFIG2L, _VREGEN_OFF_2L
            __CONFIG    _CONFIG2H, _WDT_OFF_2H & _WDTPS_512_2H
            __CONFIG    _CONFIG3H, _PBADEN_OFF_3H
            __CONFIG    _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
    endasm
    DEFINE OSC 20          
    Define I2C_SLOW 1     'At this clock speed this needed to be added to make it work.
    DEFINE I2C_HOLD 1
    
    ADCON1 = $F       'All digital
    CMCON = 7         'PortA Digital
    
    
    '--------------- Define used register flags -------------------
    
    SSPIF               VAR PIR1.3    ' SSP (I2C) interrupt flag
    SSPIE               VAR PIE1.3 
    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
    STAT_BF             VAR SSPSTAT.0 ' SSP (I2C) Buffer Full
    STAT_RW             VAR SSPSTAT.2 ' SSP (I2C) Read/Write
    STAT_DA             VAR SSPSTAT.5 ' SSP (I2C) Data/Address
    CKE                 VAR SSPSTAT.6 ' SSP (I2C) Data/Address
    WrData              var byte
    j                   var byte
    '------------------- Rx Buffer defintion --------------------
    RxBufferLEN         con 16           
    RxBuffer            var byte[Rxbufferlen]
    RxBufferIndex       var byte
    RxCnt               var byte
    rxcnt = 0
    '------------------ Tx Buffer defintion ----------------------
    TxBufferLEN         con 3
    TxBuffer            var byte[txbufferlen]
    TxBufferIndex       var byte
    TxCnt               var byte
    txcnt = 0
    '------------------ Define vars ------------------------
    rxinptr             var byte
    rxoutptr            var byte
    txinptr             var byte
    txoutptr            var byte
    rxinptr = 0
    rxoutptr = 0
    txinptr = 0
    txoutptr = 0
    I2Caddress          CON $02                  ' Make address = 2
    
    result	            VAR		BYTE			' ADC result
    DummyRead           var     byte
    DataIn 	            VAR     BYTE[8]			' Data in 
    DataOut	            VAR     BYTE[8]			' Data out array
    readcnt	            VAR     BYTE            ' I2C read count
    address             var     byte
    StatMask            var     byte
    StatMask = %00101101
    readcnt = 0				' Zero counter
    ' PicBasic Pro I2C slave program 
    ' Alias pins
    Led1    var PORTC.0
    LED2    Var PORTC.1
    
    
    
    
    scl     VAR     PORTB.1         ' I2C clock input
    sda     VAR     PORTB.0         ' I2C data input
    TRISB = %00000011
    TRISC = %00000000
    TRISA = %00000000
    LATB = $F0
    'PortA= $0F
    PORTA = $0F      'leds off  on A port
    PORTB = $F0       ' Leds off on B port
    
    
    high LED1
    high led2
    
    ' -------------- Initialize I2C slave mode ------------------------
    SSPADD = I2Caddress ' Set our address
    SSPCON1 = $36        ' Set to I2C slave with 7-bit address
    SSPCON2 = %00000000   ' clear sspcon2
    SSPCON2 = %00000001   'enable clock stretching
    SSPSTAT = %00000000    ' clear sspstat
    SSPIE = 1               'Enable MSSP interrupt enable bit
    SSPIF = 0               'Clear MSSP interrupt flag
    RxBufferIndex = 0
    TxBufferIndex = 0
    Temp            var  byte
    RxIndex         var  byte
    TxIndex         var  byte
    Stat            var  byte
    
    dataout[0] = 41     ' just some data to start with
    dataout[1] = 122
    dataout[2] = 103
    dataout[3] = 4
    
    
    '    '   Interrupt definition   
    '    '   ====================
    '        '   USB interrupt used to keep USB connection alive
    INCLUDE "DT_INTS-18.bas"    ' Base Interrupt System
    INCLUDE "ReEnterPBP-18.bas"     ' Include if using PBP interrupts
    
    ASM
    INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
            
            INT_Handler    SSP_INT,  _I2C_Int,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    endasm
    
    
    @ INT_ENABLE  SSP_INT     ; Master Synchronous Serial Port Interrupt Flag bit. The transmission/reception is complete
    
    '----------------------[ Skip over subs ]--------------------------------------
    goto Programstart
    
    I2C_Int:
    
    If R_W = 0 then                            'Write from master
        if D_A = 0 then                        ' It's address from master
           address = SSPBUF                    ' do nothing
           rxinptr = 0                          ' Clear counters
           rxoutptr = 0
        else
            WCOL = 0
            sspov = 0
            if bf = 1 then                     'There is data in buffer
               if rxcnt < rxbufferlen  then
                  rxbuffer[rxinptr] = SSPBUF
                  rxinptr = rxinptr + 1
                  if rxinptr = rxbufferlen then rxinptr = 0
               endif   
               rxcnt = rxcnt + 1
               
            EndIF 
        endif
    else                                   ' Read by master
        if SSPSTAT = %00001101 then        'last byte was an address byte.
               txinptr = 0                 'read BF
               txoutptr = 0
        endif
            dummyread = SSPBUF             'dummy read  empty buffer
            if bf = 0 then                 ' if buffer is empty
                if txcnt > 0 then          ' Is there a byte to transfer
                   SSPBUF = txbuffer[txoutptr]   'get the byte and send it
                   txoutptr = txoutptr + 1       
                   if txoutptr = txbufferlen then txoutptr = 0
                   txcnt = txcnt - 1
                else
                'no byte to send
                endif       
            endif
    endif
    
    sspif = 0
    CKP = 1 
    
    @ INT_RETURN
    '-------------------[ end of interrupt ]--------------------------------------
    
    
    ' ************************************************************
    ' * main program loop -                                      *
    ' *                                                          *
    ' * ..                                                       *
    ' ************************************************************
    
    ProgramStart: 
    
         if txcnt < txbufferlen  then
              
                TxBuffer[txinptr] = dataout[txinptr] 
                txinptr = txinptr + 1
                if txinptr = txbufferlen  then txinptr = 0
    
                txcnt = txcnt + 1
        endif
        if rxcnt != 0 then
           datain[rxoutptr] = rxbuffer[rxoutptr]
           rxoutptr = rxoutptr + 1
           if rxoutptr = rxbufferlen  then
              rxoutptr = 0
           endif
           rxcnt = rxcnt - 1
    
    
        endif
    Select case datain[0]             'Test data from master byte 0
           case 0
              low led1                'turn on LED1
           case 1
              high led1               'turn off led1
              low led2                'turn on led2
           case 2
             low led1: low led2       'turn on both
           case 3
              high led1: high led2    'turn off both
           case 4                     'Change the data out to master
              dataout[0] = 44
              dataout[1] = 45
              dataout[2] = 46
           
    end select
                                        'Eight leds for testing, 4 on Port b and four on Port a
    portb = ~datain(0) <<4              'Lower nibble to RB4 to RB7
    porta = ~(datain(0) & $F0)>>4       'upper nibble RA0 to RA3
    goto ProgramStart 
     end
    It seems the 18F chips are very sensitive to the correct timing. Also it is a good idea to read AN734B to understand the difference between I2C slave with 16F chips and 18F chips.

    Hope this helps someone out

    Dave

  2. #2
    Join Date
    Oct 2008
    Location
    Southern California
    Posts
    17


    Did you find this post helpful? Yes | No

    Talking It works!

    Guys,

    This weekend I put together software nuggets from both DaveC3 and BigWumpus. In doing so, I could see the influence of most of you that have been working on this thread over the last few weeks. I went through and trimmed out the dead code, and moved a few things around to work for my uses. I'll post both the master and slave(s) in the next day or two so others can learn from our efforts! Thanks to everyone for taking on this tough problem.

    Thanks,
    rswain

  3. #3


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by rswain View Post
    Guys,

    This weekend I put together software nuggets from both DaveC3 and BigWumpus. In doing so, I could see the influence of most of you that have been working on this thread over the last few weeks. I went through and trimmed out the dead code, and moved a few things around to work for my uses. I'll post both the master and slave(s) in the next day or two so others can learn from our efforts! Thanks to everyone for taking on this tough problem.
    Hey rswain!

    Any news about this?

    Thanks!

    Daniel.

  4. #4
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default I2C SLave in a 18F6722

    Hi all,
    wanted to come back earlier with my experiences, but had too much work.
    But :
    I use Al's i2cslave in an 18F6722 I in an interrupthandler, in Al's code i made a little correction:

    while STAT_BF = 1
    i = SSP1BUF ' Dummy Read inserted => clears BF Flag
    wend ' loop while buffer is full

    This seems to be neccessary for this PIC's, the original code from Al results in
    staying in this loop for ever.

    I read back eight variables and write two variables with no problems.
    The master and the slave have both the " DEFINE I2C_HOLD 1" at start up.

    Regards,
    Ralf

  5. #5
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default i2c slave with 18F14K22

    Hi again,
    did somebody test Al's code with a 18F14K22?
    Regards,
    Ralf

  6. #6
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default

    There is an other problem with the i2cslave:

    1. When the i2caddress is specifiead as constant (i2caddress CON $0F) it works perfect.

    2. When bulding the address via a variable, it doesnt work:
    ...
    i2caddress VAR byte
    ...
    i2caddress = $0F

    I need this because i build it from the status of four bits of Port A

    Any idea?

    Regards,
    Ralf

  7. #7
    Join Date
    May 2008
    Location
    Italy
    Posts
    825


    Did you find this post helpful? Yes | No

    Default

    I need this because i build it from the status of four bits of Port A

    Any idea?

    Ralf, you can try this:

    Code:
    
    
    Select Case PortA
    
    Case 1
    i2caddress CON $01
    Case 2
    i2caddress CON $02
    case 3
    i2caddress CON $03
    .
    .
    .
    .
    Case x
    i2caddress CON $x
    End Select
    It should work.

    Edited:

    No! it doesn't work sorry.

    Al.
    Last edited by aratti; - 25th March 2010 at 13:19.
    All progress began with an idea

Similar Threads

  1. Problem with PICto PIC I2C MASTER-SLAVE
    By juanen19 in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 11th June 2013, 02:58
  2. PIC as I2C Slave
    By Mainul in forum General
    Replies: 4
    Last Post: - 5th January 2013, 13:23
  3. I2C Slave, config Vref - + in pic with ADC
    By sebapostigo in forum PBP Wish List
    Replies: 4
    Last Post: - 5th March 2007, 03:21
  4. Pic as an i2c slave
    By Robert Soubie in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 25th January 2007, 21:11
  5. Use pic as slave in I2C
    By robert0 in forum General
    Replies: 2
    Last Post: - 3rd February 2006, 19:26

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