I2C Slave with a PIC


Closed Thread
Results 1 to 40 of 130

Hybrid View

  1. #1
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default

    Hi mister_e,
    good idea:

    What i have done is using th original code from Robert Soubie posted on his website.
    I made some more remarks and checked all gaainst the MCHIP AppNote AN734, i hope i made no mistake.

    1. I initialize the i2c:

    'Initialize I2C slave mode
    SCLDIR = 1 ' SCL must be made an input before enabling interrupts
    SDADIR = 1 ' SDA must be made an input before enabling interrupts
    SSPCON = $36 ' configure for i2c 7Bit
    gosub read_12c_address ' get address from B0 - B3
    SSPSTAT = 0 ' setting some regs...
    SSPIE = 1
    SSPIF = 0
    ' PIE1 = 1 ' ?????????
    PEIE = 1
    GIE = 1
    RxBufferIndex = 0
    TxBufferIndex = 0

    2. In the main program i include the int-handler:

    On Interrupt goto int_hand
    .... main program parts ....

    '***************** INTERRUPT HANDLER ************
    Disable
    int_hand:
    include "i2c_slave_int2.inc"
    'INTCON.1 = 0
    Resume
    Enable
    '*********************************************

    3. The "i2c_slave_int.inc" you can see here (derived from Robert Soubie)

    '*********************************************
    '* Name : i2c_slave_int.inc *
    '* Author : Ralf Mayr *
    '* : Derived from Robert Soubie *
    '* Notes : Original Code by Robert Soubie *
    '*********************************************


    goto i2c_interrupt_handler

    '*********************************************
    'write TXBuffer to I2C
    '*********************************************
    write_i2c:

    while STAT_BF = 1
    i = 0
    wend ' loop while buffer is full
    wcol = 0 ' clear collision flag
    SSPBUF = TxBuffer(TxBufferIndex)
    while wcol = 1
    wcol = 0
    SSPBUF = TxBuffer(TxBufferIndex)
    wend
    CKP = 1 ' release clock, allowing read by master
    TxBufferIndex = TxBufferIndex + 1 ' increment index
    if TxBufferIndex = 2 then ' all bytes have been transmitted
    TxBufferIndex = 0
    int_ready = 1 ' so reset index
    endif
    goto i2c_interrupt_handler_exit

    '***********************************************
    'Interrupt handling starts here
    '***********************************************
    i2c_interrupt_handler:

    'mask Status Register first
    i2c_Save_Status = SSPSTAT & i2c_slave_mask

    '***********************************************
    ' Write operation, last byte was an address, buffer is full
    ' BF = 1
    ' UA = NA
    ' RW = 0 (we get data)
    ' S = 1 (Start bit was set)
    ' P = NA
    ' DA = 0 (last byte was address)
    '***********************************************
    State_1:
    if i2c_Save_Status <> %00001001 then State_2
    i2cTempVAr = SSPBUF ' empty buffer
    if sspov then ' overflow occured?
    sspov = 0
    i2cTempVAr = SSPBUF ' empty buffer
    endif
    for RxBufferIndex = 0 to 2 ' empty receive buffer
    RxBuffer(RxbufferIndex) = 0
    next RxBufferIndex
    RxBufferIndex = 0 ' reset buffer index
    goto i2c_interrupt_handler_exit

    '***********************************************
    ' Write operation, last byte was data, buffer is full
    ' BF = 1
    ' UA = NA
    ' RW = 0 (we get data)
    ' S = 1 (Start bit was set)
    ' P = NA
    ' DA = 1 (last byte was data)
    '***********************************************
    State_2:
    if i2c_Save_Status <> %00101001 then State_3
    RxBuffer(RxBufferIndex) = SSPBUF ' read received byte and empty buffer
    if sspov then ' overflow occured?
    sspov = 0
    i2cTempVAr = SSPBUF ' empty buffer
    endif
    RxBufferIndex = RxBufferIndex + 1 ' point at next empty slot in buffer
    goto i2c_interrupt_handler_exit

    '***********************************************
    ' Read operation, last byte was an address, buffer is empty
    ' BF = unknown ?
    ' UA = NA
    ' RW = 1 (we send data)
    ' S = 1
    ' P = NA
    ' DA = 0 (last byte was address)
    '***********************************************
    State_3:
    if i2c_Save_Status <> %00001100 then State_4
    goto write_i2c ' write next byte

    '***********************************************
    ' Read operation, last byte was data, buffer is empty
    ' BF = 0
    ' UA = NA
    ' RW = 1 (we send data)
    ' S = 1 (Start bit was set)
    ' P = NA
    ' DA = 1 (last byte send was data)
    '***********************************************
    State_4:
    if i2c_Save_Status <> %00101100 then State_5
    goto write_i2c ' write next byte

    '***********************************************
    ' Unknown operation
    ' BF = 0
    ' UA = NA
    ' RW = 0
    ' S = 1 (Start bit was set)
    ' P = NA
    ' DA = 1 (last byte send was data)
    '***********************************************
    State_5:
    if i2c_Save_Status <> %00101000 then State_i2CErr
    CKP = 1
    goto i2c_interrupt_handler_exit


    '***********************************************
    ' We should never get here... BUT WE GET HERE *g*
    '***********************************************
    State_i2cErr:
    i2c_error = 1

    '***********************************************
    ' Did we receive one command byte and two parameter bytes?
    ' if so, RxBufferIndex equals 3
    '***********************************************
    i2c_interrupt_handler_exit:

    if rxbufferindex = 3 then
    CKP = 0 ' Disable clock
    include "Proc_i2c.inc"
    rxBufferIndex = 0 ' Reset Rx Buffer index for next time we get a command
    TxBufferindex = 0 ' Reset Tx Buffer index for sending two result bytes
    int_ready = 1
    CKP = 1 ' Enable clock
    endif

    if sspov then ' overflow occured?
    i2cTempVAr = SSPBUF ' empty buffer
    sspov = 0
    endif

    SSPIF = 0 ' reset interrupt flag that took us here

    4. The include file "Proc_I2C.inc resolves the vars and their values:

    i2c_OutL = RxBuffer(0)
    i2c_OutH = $ff
    if RxBuffer(0) = "M" then
    i2c_OutL = var1
    i2c_OutH = "M"
    else
    if RxBuffer(0) = "I" then
    i2c_OutL = var2
    i2c_OutH = "I"
    else
    if RxBuffer(0) = "G" then
    i2c_OutL = var3
    i2c_OutH = "G"
    else
    i2c_OutH = $FF 'error unknown command
    endif
    endif
    endif

    TxBuffer(0) = i2c_outh
    TxBuffer(1) = i2c_outL

    5. The masster accesses the slave with I2CWrite and I2CRead, but sometimes the master gets errors and also the slave sets the i2c_eror bit (a variable from me in State_i2cErr).
    - The master always sends three bytes (the "id" and the two databytes).
    - The master always reads two bytes (two values form the "id "in the write operation before)
    Writing to the slave seems to work fine, but reading from the slave results in errors and sometimes senseless values on the master side.

  2. #2


    Did you find this post helpful? Yes | No

    Default

    Hey Ralf,

    Where you able to solve the problem? I'm still working on the slave code, but I'm not able to read from the slave. I'm getting frustrated with this.

    Thanks!

    Daniel.

  3. #3
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default

    Hi Daniel,
    no, i stopped working on it, it is not possible to get it work... :-(

    I solved my problem using serin/serout.
    But it would be great when we exchange our know-how, so we can solve this together!

    -,Ralf

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


    Did you find this post helpful? Yes | No

    Default

    Here a working snipet for I2C slave communication.

    I2C write command will be received into variable array RxBuffer and RxBuffer[0] is used for the case select routine.
    I2C read command will return content of variable array TxBuffer. So before reading you have to update the array in someways. The easy way is to write a command that will update the array TxBuffer with the values you need than you read them.

    Array lenght can be changed, changing the constants "RxBufferLEN" & "TxBufferLEN"

    Slave address can be changed changing the constant "I2Caddress".

    A 20 MHz quartz is recommended.

    Add your code in the correct place and you should not have problem.


    Code:
    '****************************************************************
    '*  Name    : I2C_Slave                                         *
    '*  Author  :                                                   *
    '*  Notice  :                                                   *
    '*          : All Rights Reserved                               *
    '*  Date    : 03/01/2008                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : I2C Slave with Pic16F876                          *
    '*          :                                                   *
    '****************************************************************
    
    '-- set device & tris port config here (don't use SCL & SDA pins other than I2C) ----
    
    DEFINE I2C_HOLD 1
    
    '---------------- Alias pins -----------------------------------
    
    SCLDIR              var TRISC.3 
    SDADIR              var TRISC.4
    
    '--------------- 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 SSPCON.4            ' SSP (I2C) SCK Release Control
    SSPEN               VAR SSPCON.5            ' SSP (I2C) Enable
    SSPOV               VAR SSPCON.6            ' SSP (I2C) Receive Overflow Indicator
    WCOL                VAR SSPCON.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
    
    
    '------------------- Rx Buffer defintion --------------------
    RxBufferLEN         con 3           
    RxBuffer            var byte[Rxbufferlen]
    RxBufferIndex       var byte
    
    '------------------ Tx Buffer defintion ----------------------
    TxBufferLEN         con 3
    TxBuffer            var byte[txbufferlen]
    TxBufferIndex       var byte
    
    
    '------------------ Define constants ------------------------
    I2Caddress          CON $2                  ' Make address = 2
    
    
    
    
    ' --------- Define here your variables and alias ------------------
    
    
    
    
    ' -------------- Initialize I2C slave mode ------------------------
    
    SCLDIR = 1                                  ' SCL must be an input before enabling interrupts
    SDADIR = 1   
    SSPADD = I2Caddress                         ' Set our address
    SSPCON2.7 = 0                               ' General call address disabled
    SSPCON = $36                                ' Set to I2C slave with 7-bit address
    SSPSTAT = 0
    SSPIE = 1 
    SSPIF = 0 
    RxBufferIndex = 0
    TxBufferIndex = 0
    
    '----------------- Initialization Done! -----------------------------
    
    
    
    GoTo main
    
    
    '------------------------- I2C subroutine  -------------------------------- 
    
    i2cslave:                                   ' I2C slave subroutine
    SSPIF = 0                                   ' Clear interrupt flag
    IF R_W = 1 Then i2crd                       ' Read data from us
    IF BF = 0 Then i2cexit                      ' Nothing in buffer so exit
    IF D_A = 1 Then i2cwr                       ' Data for us (not address)
    IF SSPBUF != I2Caddress Then i2cexit        ' Clear the address from the buffer
    readcnt = 0                                 ' Mark as first read
    GoTo i2cexit
    
    i2cwr:                                      ' I2C write data to us
    datain = SSPBUF                             ' Put buffer data into array
    Rxbuffer[Rxbufferindex]=datain
    rxbufferindex =rxbufferindex+1
    
    if rxbufferindex=RxBufferLEN then           ' end of buffer transfer 
    WrData=1
    rxbufferindex=0
    endif
    
    GoTo i2cexit
    
    i2crd:                                      ' I2C read data from us
    IF D_A = 0 Then
    TxBufferIndex = 0
    EndIF
    
    while STAT_BF : wend                        ' loop while buffer is full
    wcol = 0                                    ' clear collision flag
    SSPBUF = TxBuffer[TxBufferIndex]
    while wcol 
    wcol = 0
    SSPBUF = TxBuffer[TxBufferIndex]
    wend
    CKP = 1                                     ' release clock, allowing read by master
    TxBufferIndex = TxBufferIndex + 1           ' increment index
    if TxBufferIndex = TxBufferlen then         ' all bytes have been tx
    TxBufferIndex = 0                           ' reset index            
    endif
                 
    i2cexit:
    Return
    
    ' -------------------------end I2C subroutine  -------------------------------- 
    
    Main:
    IF SSPIF = 1 Then
    GoSub i2cslave
    EndIF
    
    SSPOV = 0
    WCOL = 0
    
    Select case RBuffer[0]
    '--------------------- Place here your case select code
    end select
    
    WrData=0  
    GoTo Main
    
    
    ' ----------------- This space for your program code
    
    End
    Enjoy

    Al.
    All progress began with an idea

  5. #5


    Did you find this post helpful? Yes | No

    Default

    Hello Al,

    Thank you very much for answering my message. You can't imagine how much I appreciate this working snipet for I2C slave communication.

    I will test it right away and let you know how everything went.

    Thanks a lot one more time!

    Daniel.

  6. #6


    Did you find this post helpful? Yes | No

    Default

    Hello Al,

    It works perfectly!!! I'm so happy now!!! Thank you very very much!!

    I'll post my code as soon as it's done, so everybody else can use it.

    Daniel.

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


    Did you find this post helpful? Yes | No

    Default

    Glad to hear that!

    Al.
    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, 03:58
  2. PIC as I2C Slave
    By Mainul in forum General
    Replies: 4
    Last Post: - 5th January 2013, 14:23
  3. I2C Slave, config Vref - + in pic with ADC
    By sebapostigo in forum PBP Wish List
    Replies: 4
    Last Post: - 5th March 2007, 04:21
  4. Pic as an i2c slave
    By Robert Soubie in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 25th January 2007, 22:11
  5. Use pic as slave in I2C
    By robert0 in forum General
    Replies: 2
    Last Post: - 3rd February 2006, 20: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