I2C Slave with a PIC


Closed Thread
Page 1 of 4 1234 LastLast
Results 1 to 40 of 130
  1. #1
    Join Date
    Nov 2008
    Posts
    48

    Default I2C Slave with a PIC

    Hi there,
    i tried, as mentined in an other thread before, that i try to implement
    the i2c-slave code from Robert Soubie in a PIC18F2431, but there are still
    problems in that code: Writing to the slave wokrs fine, but reading from
    the slave results in errors and sometimes senseless values on the master side.
    Did someone here use this code from Robert and could help on this problem?
    Regards,
    Ralf

  2. #2
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    How about posting what you've done so far, this way we could check with your code?
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  3. #3
    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.

  4. #4


    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.

  5. #5
    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

  6. #6
    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

  7. #7


    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.

  8. #8


    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.

  9. #9
    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

  10. #10


    Did you find this post helpful? Yes | No

    Default

    A short video:

    The master on the left, a 16F877 is telling the first 16F88 (on the top) to turn on/off the LED, and then reads 24 from it. After that, the master tells the second 16F88 (on the bottom) to turn on/off the LED, and then reads 12 from it.

    It's in slow motion because I was testing everything, but I discovered that the I2C protocol is very fast!

    Al, thanks a lot one more time!

    Daniel.

  11. #11


    Did you find this post helpful? Yes | No

    Default Hi

    Hi Daniel: I would like to try out your code,could you post a link if not too much trouble.

    Thanks RC

  12. #12


    Did you find this post helpful? Yes | No

    Default

    Sure! Let me know if you need anything else

    Master 16f877 - External 4Mhz Crystal:
    Code:
    '-------------------------------------------------------------------------------
    '-------------------------------------------------------------------------------
    ' Master
    '-------------------------------------------------------------------------------
    '-------------------------------------------------------------------------------
    
    DEFINE OSC 4
    
    'OPTION_REG.7 = 0
    
    ADCON1 = 7
    
    '------------------------------------------------------------------------------
    
    DEFINE I2C_SLOW 1
    
    TRISB.5 = 1
    TRISB.7 = 1
    
    '------------------------------------------------------------------------------
    
    scl VAR PORTB.5		' i2c clock input
    sda VAR PORTB.7     ' i2c data input
    
    '------------------------------------------------------------------------------
    
    I2Caddress VAR BYTE
    
    valor VAR BYTE
    
    '------------------------------------------------------------------------------
    
    ' Set LCD Data port
    DEFINE LCD_DREG PORTD
    ' Set starting Data BIT (0 OR 4) IF 4-BIT bus
    DEFINE LCD_DBIT 4
    ' Set LCD Register Select port
    DEFINE LCD_RSREG PORTC
    ' Set LCD Register Select BIT
    DEFINE LCD_RSBIT 6
    ' Set LCD Enable port
    DEFINE LCD_EREG PORTC
    ' Set LCD Enable BIT
    DEFINE LCD_EBIT 7
    ' Set LCD bus size (4 OR 8 bits)
    DEFINE LCD_BITS 4
    ' Set number of lines ON LCD
    DEFINE LCD_LINES 2
    ' Set command delay time in us
    DEFINE LCD_COMMANDUS 2000
    ' Set Data delay time in us
    DEFINE LCD_DATAUS 50
    
    '------------------------------------------------------------------------------
    
    Pause 500       ' Wait for LCD to startup
    LCDOut $fe, 1
    LCDOut $fe, "Daniel"
    Pause 500       ' Wait for LCD to startup
    
    valor = 0
    
    '------------------------------------------------------------------------------
    
    main:
          I2Caddress = $3
    
          LCDOut $fe, 1
          LCDOut "Writting 1 - LED ON..."
          Pause 500
    
          I2CWrite SDA, SCL, I2Caddress, [6], bogus ' Write offset to slave
          Pause 500
    
          LCDOut $fe, 1
          LCDOut "Writting 1 - LED OFF..."
          Pause 500
    
          I2CWrite SDA, SCL, I2Caddress, [8], bogus ' Write to slave
          Pause 500
    
          LCDOut $fe, 1
          LCDOut "Reading 1..."
          Pause 500
    
          I2CRead SDA, SCL, I2Caddress, [valor], bogus ' Read from slave
          LCDOut $fe, 1
          LCDOut "Value: ", DEC valor
          Pause 500
    
          '--------
    
          I2Caddress = $5
    
          LCDOut $fe, 1
          LCDOut "Writting 2 - LED ON..."
          Pause 500
    
          I2CWrite SDA, SCL, I2Caddress, [4], bogus ' Write to slave
          Pause 500
    
          LCDOut $fe, 1
          LCDOut "Writting 2 - LED OFF..."
          Pause 500
    
          I2CWrite SDA, SCL, I2Caddress, [10], bogus ' Write to slave
          Pause 500
    
          LCDOut $fe, 1
          LCDOut "Reading 2..."
          Pause 500
    
          I2CRead SDA, SCL, I2Caddress, [valor], bogus ' Read from slave
          LCDOut $fe, 1
          LCDOut "Value: ", DEC valor
          Pause 500
    
          '--------
    
          GoTo main       ' Do it forever
    
    '-------------------------------------------------------------------------------
    
    bogus:
    		LCDOut $fe,1, "Time out"	' I2C command timed out
    		Pause 500
    
    		GoTo main
    
    '-------------------------------------------------------------------------------
    
    End
    
    '-------------------------------------------------------------------------------
    '-------------------------------------------------------------------------------
    Last edited by DanPBP; - 19th February 2009 at 19:34.

  13. #13


    Did you find this post helpful? Yes | No

    Default

    1' Slave - 16F88 - Internal 8Mhz
    Code:
    '------------------------------------------------------------------------------
    '------------------------------------------------------------------------------
    ' Slave
    '------------------------------------------------------------------------------
    '------------------------------------------------------------------------------
    
    @ device pic16f88, intrc_osc_noclkout	' system clock options
    @ device pic16f88, wdt_on			' watchdog timer
    @ device pic16f88, pwrt_on			' power-on timer
    @ device pic16f88, mclr_off			' master clear options (internal)
    @ device pic16f88, protect_off		' code protect off
    
    '--- set device ---------------------------------------------------------------
    
    DEFINE OSC 8
    OSCCON = %01110001 '8mhz
    
    '------------------------------------------------------------------------------
    
    CMCON = 7
    ADCON1 = 0 ' Disable A/D converter
    ADCON0 = 0
    ANSEL = 0 ' all analog pins to digital
    
    '--- tris port config here (don't use SCL & SDA pins other than I2C) ----------
    
    DEFINE I2C_HOLD 1
    
    TRISB.1 = 1
    TRISB.4 = 1
    
    '--- Alias pins ---------------------------------------------------------------
    
    SDADIR VAR TRISB.1
    SCLDIR VAR TRISB.4
    
    '--- Define here your variables and alias -------------------------------------
    
    LEDT VAR PORTA.2
    LEDL VAR PORTB.7
    LEDM VAR PORTB.6
    LEDR VAR PORTB.5
    readcnt VAR BYTE
    datain VAR BYTE
    WrData VAR BYTE
    
    '--- 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 1       
    RxBuffer            VAR BYTE[Rxbufferlen]
    RxBufferIndex       VAR BYTE
    
    '--- Tx Buffer defintion ------------------------------------------------------
    
    TxBufferLEN         CON 1
    TxBuffer            VAR BYTE[txbufferlen]
    TxBufferIndex       VAR BYTE
    
    '--- Define constants ---------------------------------------------------------
    
    I2Caddress          CON $3 ' Make address = 3
    
    '--- Initialize I2C slave mode ------------------------------------------------
    
    SCLDIR = 1          ' SCL must be an input before enabling interrupts
    SDADIR = 1   
    SSPADD = I2Caddress ' Set our address
    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:
          txbuffer = 12
    
          IF SSPIF = 1 Then
             GoSub i2cslave
          EndIF
    
          SSPOV = 0
          WCOL = 0
    
          Select Case RxBuffer[0]
                 Case 6
                         High LEDT
                 Case 8
                         Low LEDT
          End Select
    
          WrData=0  
          GoTo Main
    
    
    '------------------------------------------------------------------------------
    
    End
    
    '------------------------------------------------------------------------------
    '------------------------------------------------------------------------------

  14. #14


    Did you find this post helpful? Yes | No

    Default

    2' Slave - 16F88 - Internal 8Mhz
    Code:
    '------------------------------------------------------------------------------
    '------------------------------------------------------------------------------
    ' Slave
    '------------------------------------------------------------------------------
    '------------------------------------------------------------------------------
    
    @ device pic16f88, intrc_osc_noclkout	' system clock options
    @ device pic16f88, wdt_on			' watchdog timer
    @ device pic16f88, pwrt_on			' power-on timer
    @ device pic16f88, mclr_off			' master clear options (internal)
    @ device pic16f88, protect_off		' code protect off
    
    '--- set device ---------------------------------------------------------------
    
    DEFINE OSC 8
    OSCCON = %01110001 '8mhz
    
    '------------------------------------------------------------------------------
    
    CMCON = 7
    ADCON1 = 0 ' Disable A/D converter
    ADCON0 = 0
    ANSEL = 0 ' all analog pins to digital
    
    '--- tris port config here (don't use SCL & SDA pins other than I2C) ----------
    
    DEFINE I2C_HOLD 1
    
    TRISB.1 = 1
    TRISB.4 = 1
    
    '--- Alias pins ---------------------------------------------------------------
    
    SDADIR VAR TRISB.1
    SCLDIR VAR TRISB.4
    
    '--- Define here your variables and alias -------------------------------------
    
    LEDT VAR PORTA.2
    LEDL VAR PORTB.7
    LEDM VAR PORTB.6
    LEDR VAR PORTB.5
    readcnt VAR BYTE
    datain VAR BYTE
    WrData VAR BYTE
    
    '--- 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 1       
    RxBuffer            VAR BYTE[Rxbufferlen]
    RxBufferIndex       VAR BYTE
    
    '--- Tx Buffer defintion ------------------------------------------------------
    
    TxBufferLEN         CON 1
    TxBuffer            VAR BYTE[txbufferlen]
    TxBufferIndex       VAR BYTE
    
    '--- Define constants ---------------------------------------------------------
    
    I2Caddress          CON $5 ' Make address = 5
    
    '--- Initialize I2C slave mode ------------------------------------------------
    
    SCLDIR = 1          ' SCL must be an input before enabling interrupts
    SDADIR = 1   
    SSPADD = I2Caddress ' Set our address
    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:
          txbuffer = 24
    
          IF SSPIF = 1 Then
             GoSub i2cslave
          EndIF
    
          SSPOV = 0
          WCOL = 0
    
          Select Case RxBuffer[0]
                 Case 4
                         High LEDT
                 Case 10
                         Low LEDT
          End Select
    
          WrData=0  
          GoTo Main
    
    
    '------------------------------------------------------------------------------
    
    End
    
    '------------------------------------------------------------------------------
    '------------------------------------------------------------------------------

  15. #15


    Did you find this post helpful? Yes | No

    Default Thank You!

    Daniel: Thanks to you and others in this great forum for sharing....It is so much easier to understand when you can see code that is working and is well commented.

    Thanks again to all the generous people on this forum!

    RC

  16. #16
    Join Date
    Oct 2004
    Location
    Hangover, Germany
    Posts
    289


    Did you find this post helpful? Yes | No

    Default

    I think, this part could be written better:

    Code:
           wcol = 0                                    ' clear collision flag
           SSPBUF = TxBuffer[TxBufferIndex]
    
           While wcol 
                 wcol = 0
                 SSPBUF = TxBuffer[TxBufferIndex]
           Wend
    this is much shorter:

    Code:
           Repeat
                 wcol = 0
                 SSPBUF = TxBuffer[TxBufferIndex]
           Until !wcol
    and works, too.
    PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2

  17. #17


    Did you find this post helpful? Yes | No

    Default

    Thanks for the update! This should be a hot topic now!

    Btw, how many times I have seen this topic on the forum without any answers because: "my code that works is proprietary and I cannot share it" or worst: "RTFM!". If the only thing you have to say is that, keep it to yourself! Or, the other one I hate: "did you try the example from melabs site?" The one that everyones says it doesn't work? Yes!!!

    Thanks a lot to Al, the I2C slave routine is working great and he was kind enough to share it with all of us. You're great Sr.!

  18. #18
    Join Date
    Aug 2006
    Location
    Look, behind you.
    Posts
    2,818


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by danielhr77 View Post
    Thanks for the update! This should be a hot topic now!

    Btw, how many times I have seen this topic on the forum without any answers because: "my code that works is proprietary and I cannot share it"
    Translation: My code does not work, but I won't admit it. At least 50% of the time <br> Anyway thanks Daniel and AL, Ralf , mister_e, Big Wumpus Something new to play with.
    Last edited by Archangel; - 7th March 2009 at 06:38.
    If you do not believe in MAGIC, Consider how currency has value simply by printing it, and is then traded for real assets.
    .
    Gold is the money of kings, silver is the money of gentlemen, barter is the money of peasants - but debt is the money of slaves
    .
    There simply is no "Happy Spam" If you do it you will disappear from this forum.

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


    Did you find this post helpful? Yes | No

    Default

    Translation: My code does not work, but I won't admit it. At least 50% of the time
    Interesting assumption Joe.

    Al.
    All progress began with an idea

  20. #20
    Join Date
    Aug 2006
    Location
    Look, behind you.
    Posts
    2,818


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by aratti View Post
    Interesting assumption Joe.

    Al.
    I mean it in context, sure there some very good professional coders in here, and when they say it I am sure it is true, now for a majority here, who likely are hobbyist, maybe some of which wish to make the jump with their own stellar idea, 50 / 50 is likely a generous assumption. And so what? EGO has value only to the person who owns it.<br>EDIT: Ego has value to anyone who wants to exert control over someone who has it too.
    Last edited by Archangel; - 7th March 2009 at 23:43.
    If you do not believe in MAGIC, Consider how currency has value simply by printing it, and is then traded for real assets.
    .
    Gold is the money of kings, silver is the money of gentlemen, barter is the money of peasants - but debt is the money of slaves
    .
    There simply is no "Happy Spam" If you do it you will disappear from this forum.

  21. #21
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default

    Hi there,
    i will test the code from Aretti soon on a PIC18F2431. I want to process four ad-converters and several digital io's. The slave address of the PIC is automatically detected when pluging it on a bus-system (16 addresses).
    When it is finished and working (hope so), i will post it here.
    FYI: I2C Apps from MCHIP seems not to work, a friend of me in an other company also tried this code to implement, no chance.
    All others syaing "i can't post my working code here" must be sayed, that these people are wrong here, a forum lives from shared ideas, code snippets.... they should keep out here and keep their code for them selves.

    Regards,
    Ralf

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


    Did you find this post helpful? Yes | No

    Default

    I will be interested in your port to the 18F series, and it sounds like you will be willing to post your code. I have an upcoming project that will need it. I tried to get Soubie's code working about a year ago with no luck.
    Charles Linquist

  23. #23
    Join Date
    Nov 2008
    Posts
    48


    Did you find this post helpful? Yes | No

    Default

    Charles,
    same problem, i also never got his code working.
    I come back next week, hope with a working code.
    Regards,
    Ralf

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


    Did you find this post helpful? Yes | No

    Unhappy Still not working here

    Guys,

    I've been working this problem for nearly a year now. I've tried Soubie's code with no luck, and the code from this thread isn't working either. I'm using the 18F4620 as the master talking to an 18F2620, the little brother of the 4620 as the slave. I've RTFM to the point I can recite it, and the Errata sheets, and I've tried countless logical, and even illogical options to trying to get it working.

    The best I can get so far is the master sends the address byte and the slave accepts it when it matches its own address and ignores addresses not matching its own. When the address matches, the slave sets the Buffer Full and the Interrupt Flags, but for some reason won't send an ACK back to the master (at least that's what this thread's code [and my own polls of the master's ACK flag] are saying). I've made sure to clear all flags as the datasheet clearly directs, and still no luck. If the slave would ACK, the master would send the next byte and so on.

    I'm operating both chips on their internal crystal (8 MHz) and using the 4x PLL (= 32MHz). Before you go there, I'm already successfully talking to an I2C real-time clock chip with no problems and I'm saving data to an external I2C EEPROM regularly with no problems. The I2C network is working with the PICs at 32 MHz. I'm on the right pins; I'm using the pull external pull-up resistors...

    I've had this exact hardware working in the past when using MikroElektronika Basic, but I'm much happier in PBP. This one problem is holding up the entire project. Trying to get two 18F's to ping-pong data back and forth is a killer.

    If someone has even a bit more success than what I've had, please post it and maybe together we can chip away at this challenge.

  25. #25


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by rswain View Post
    and the code from this thread isn't working either.
    Well, the code provided by Al (aratti) and the one I posted works great both ways!

    I don't know what to tell you without looking at your code, but I modified the one provided by Al just a little and worked right away!

    Can you post your code? Maybe we can see something that you're not seeing.

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


    Did you find this post helpful? Yes | No

    Default

    I'll be able to devote some time to a group project in about two weeks. I will also have another issue - I'm forced to work with 10-bit addresses.
    Charles Linquist

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


    Did you find this post helpful? Yes | No

    Default Code for 18F2620 that doesn't ACK for some reason

    Here's my slave code that's not sending back the ACK. I appologize for the "dead code" and commented out parts in advance. Maybe you'll see something I'm missing...

    Robert
    ----------------
    Code:
    'Oscillator Initialization
        DEFINE OSC 32               ' Osc. in MHz
        OSCCON = %01110000          
        OSCTUNE.6 = 1               
        ADCON0.0 = 0                ' Turns off A-to-D module
        ADCON1 = $0F                ' Makes 100% port A digital 
        TRISA = %00000000
        CMCON = 7 ' Comparators Off
    
    DEFINE I2C_HOLD 1
    'DEFINE I2C_SLOW 1
    
    ' Define used register flags
    SSPIF    VAR PIR1.3 ' SSP (I2C) interrupt flag
    SSPIE    VAR PIE1.3 ' SSP Int Enable
    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
    'STRETCH  VAR SSPCON2.0 ' SSP (I2C) Clock stretch
    
    A        var byte      ' my counter variable for testing
    '---------------- Alias pins -----------------------------------
    
    TRISC.3 = 1         ' input
    TRISC.4 = 1         ' input
    
    '--------------- Define used register flags -------------------
    
    '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 definition --------------------
    RxBufferLEN         con 3           
    RxBuffer            var byte[Rxbufferlen]
    RxBufferIndex       var byte
    
    '------------------ Tx Buffer definition ----------------------
    TxBufferLEN         con 3
    TxBuffer            var byte[txbufferlen]
    TxBufferIndex       var byte
    
    '------------------ Define constants ------------------------
    'I2Caddress          CON $2                  ' Make address = 2
    I2Caddress          CON $06                  ' Make address = 2
    
    ' Define constants
    U8       var byte
    U17      var byte
    InByte   var byte
    OutByte  var byte
    readcnt  VAR BYTE 
    'U8 = $06
    U17 = $08
    
    'STRETCH = 1
    WRData var byte
    ' Initialize I2C slave mode
    'SSPCON2 = 0 ' General call address disabled
    
    'SSPADD = My_I2C_address                     ' Set our address
    SSPADD = I2Caddress                         ' Set our address
    SSPCON2.7 = 0                               ' General call address disabled
    SSPCON1 = $36                               ' Set to I2C slave with 7-bit address
    SSPSTAT = 0
    SSPIE = 1 
    SSPIF = 0 
    RxBufferIndex = 0
    TxBufferIndex = 0
    bf = 0
    SSPOV = 0
    
        'Port C harware UART settings 
        DEFINE HSER_RCSTA 90h              
        DEFINE HSER_TXSTA 20h              
        DEFINE HSER_BAUD 9600              
        DEFINE HSER_CLROERR 1       
    '----------------- Initialization Done! -----------------------------
    rxbuffer[0] = 0
    rxbuffer[1] = 0
    rxbuffer[2] = 0
    
    GoTo main
      
    
    I2C_Slave:                                  ' I2C slave subroutine
      hserout ["SSPIF = ",#SSPIF,"  BF = ",#bf,13,10]
      hserout ["R_W = ",#R_w,"  D_A = ",#D_A,13,10]
      hserout ["SSPBUF = ",#SSPBUF,13,10]
      SSPIF = 0                                 ' Clear interrupt flag
      SSPov = 0                                 ' Clear interrupt flag
      bf = 0                                      ' clear buffer full
      IF R_W = 1 Then 
        hserout ["R_W = 1, Read data from U8",13,10]
        goto I2C_Read                  ' Read data from us
      endif
      IF SSPBUF = I2Caddress Then 
        hserout ["It's to me! ",#SSPBUF," = ",#I2Caddress,13,10]
      endif
      IF D_A = 1 Then 
        hserout ["Data (not address)",13,10]
        goto I2C_Write                 ' Data for us (not address)
      endif
      GoTo I2C_Exit
      
    I2C_Write:                                      ' I2C write data to us
      InByte = SSPBUF                             ' Put buffer data into array
      Rxbuffer[Rxbufferindex] = InByte
      rxbufferindex = rxbufferindex + 1
    
      hserout ["SSPBUF Write = ",#SSPBUF,13,10]
      GoTo i2c_exit
    
    I2C_Read:                                 ' I2C read data from us
      hserout ["SSPBUF Read = ",#SSPBUF,13,10]
      IF D_A = 0 Then
        TxBufferIndex = 0
      EndIF
    
    while BF : wend                        ' loop while buffer is full
    wcol = 0                                    ' clear collision flag
    SSPBUF = TxBuffer[TxBufferIndex]
    while wcol 
    wcol = 0
    SSPBUF = TxBuffer[TxBufferIndex]
    wend
      hserout ["SSPBUF Outbyte = ",#SSPBUF," should be outbyte 16 or 31",13,10]
    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
                 
    I2C_Exit:
    Return
    
    main:
      pause 300
      hserout [13,10,"Start of program U8",13,10]
      hserout ["RxBuffer = "]
      for a = 0 to 2
        hserout [dec rxbuffer[a],"  "]
      next a
      hserout [13,10]
    loop:
    '  IF SSPIF = 1 Then
      IF BF = 1 Then
        hserout [13,10,"Went into I2C_Slave routine",13,10]
        GoSub i2c_slave
        hserout ["RxBuffer = "]
        for a = 0 to 2
          hserout [dec rxbuffer[a],"  "]
        next a
        hserout [13,10]
        hserout ["SSPCON1 = ",hex sspcon1,"  ",bin sspcon1,13,10]
        hserout ["SSPCON2 = ",hex sspcon2,"  ",bin sspcon2,13,10]
        hserout ["SSPSTAT = ",hex sspstat,"  ",bin sspstat,13,10]
        hserout ["SSPBUF = ",#sspbuf,13,10]
        
        if rxbufferindex = RxBufferLEN then           ' end of buffer transfer 
          WrData = 1
          rxbufferindex = 0
          rxbuffer[0] = 0
          rxbuffer[1] = 0
          rxbuffer[2] = 0
          hserout ["RxBuffer Cleared = "]
          for a = 0 to 2
            hserout [dec rxbuffer[a],"  "]
          next a
          hserout [13,10]
        endif
      endif
    
      SSPOV = 0
      WCOL = 0
      IF RxBuffer[0] = 15 Then
        hserout ["Got a 15",13,10]
        hserout ["  Readcount is: ",#readcnt,13,10]
        hserout ["Have a 16 to send if asked",13,10]
        TxBuffer[0] = 16
      EndIF
      
      IF RxBuffer[0] = 30 Then
        hserout ["Got a 30",13,10]
        hserout ["  Readcount is: ",#readcnt,13,10]
        hserout ["Have a 31 to send if asked",13,10]
        TxBuffer[0] = 31
      EndIF
    WrData=0  
    pause 50
    GoTo loop
    
    End
    Last edited by ScaleRobotics; - 22nd October 2010 at 14:24. Reason: added code tags

  28. #28


    Did you find this post helpful? Yes | No

    Default

    One thing I learn these days is that you cannot mess with the I2C timing.
    Looking at your code, I guess those hserouts are killing the protocol.
    I'll take a closer look at everything else tomorrow.

  29. #29


    Did you find this post helpful? Yes | No

    Default

    Try this code, I cleaned it up a lot. Slave address is 2.

    1) From the master, try to read 12 from the slave

    2) Try to send one byte (zero) to the slave and do something.

    I don't have MPASM so, it could be some small errors, check them.

    Code:
    'Oscillator Initialization
    DEFINE OSC 32 ' Osc. in MHz
    OSCCON = %01110000 
    OSCTUNE.6 = 1 
    ADCON0.0 = 0 ' Turns off A-to-D module
    ADCON1 = $0F ' Makes 100% port A digital 
    TRISA = %00000000
    CMCON = 7 ' Comparators Off
    
    DEFINE I2C_HOLD 1
    
    ' Define used register flags
    SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag
    SSPIE VAR PIE1.3 ' SSP Int Enable
    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
    'STRETCH VAR SSPCON2.0 ' SSP (I2C) Clock stretch
    
    '---------------- Alias pins -----------------------------------
    
    TRISC.3 = 1 ' input
    TRISC.4 = 1 ' input
    
    '--------------- Define used register flags -------------------
    
    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 definition --------------------
    RxBufferLEN CON 1
    RxBuffer VAR BYTE[Rxbufferlen]
    RxBufferIndex VAR BYTE
    
    '------------------ Tx Buffer definition ----------------------
    TxBufferLEN CON 1
    TxBuffer VAR BYTE[txbufferlen]
    TxBufferIndex VAR BYTE
    
    '------------------ Define constants ------------------------
    
    I2Caddress CON $2 ' Make address = 2
    
    ' Define constants
    
    
    datain VAR BYTE
    readcnt VAR BYTE 
    WRData VAR BYTE
    
    
    'SSPADD = My_I2C_address ' Set our address
    SSPADD = I2Caddress ' Set our address
    SSPCON2.7 = 0 ' General call address disabled
    SSPCON1 = $36 ' Set to I2C slave with 7-bit address
    SSPSTAT = 0
    SSPIE = 1 
    SSPIF = 0 
    RxBufferIndex = 0
    TxBufferIndex = 0
    bf = 0
    SSPOV = 0
    
    'Port C harware UART settings 
    DEFINE HSER_RCSTA 90h 
    DEFINE HSER_TXSTA 20h 
    DEFINE HSER_BAUD 9600 
    DEFINE HSER_CLROERR 1 
    
    '----------------- Initialization Done! -----------------------------
    GoTo main
    
    '-------------------------------------------------------------------------------
    
    I2C_Slave: ' I2C slave subroutine
              sspif = 0                            ' clear interrupt flag
              IF r_w = 1 Then I2C_Read                ' read data from us
              IF bf = 0 Then I2C_Exit               ' nothing in buffer so exit
              IF d_a = 1 Then I2C_Write                ' data for us (not address)
              IF sspbuf != i2caddress Then I2C_Exit ' clear the address from the buffer
              readcnt = 0                          ' mark as first read
    
              GoTo I2C_Exit
    
    '-------------------------------------------------------------------------------
    
    I2C_Write: ' 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 i2c_exit
    
    '-------------------------------------------------------------------------------
    I2C_Read: ' I2C read data from us
    
           IF d_a = 0 Then
              txbufferindex = 0
           EndIF
    
           While stat_bf : Wend                        ' koop 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
    
    GoTo i2c_exit
    
    
    '-------------------------------------------------------------------------------
    
    I2C_Exit:
             sspov = 0
             wcol = 0
             wrdata = 0
    Return
    
    '-------------------------------------------------------------------------------
    
    '-------------------------------------------------------------------------------
    main:
          txbuffer[0] = 12 ' test value
    
          rxbuffer[0] = 0
    
          IF sspif = 1 Then
             GoSub i2c_slave
          EndIF
    
          Select Case rxbuffer[0]
                 Case 0
                       ' do something here, turn on LED for example.
          End Select
    
          GoTo main
    
    End

  30. #30
    Join Date
    Oct 2004
    Location
    Hangover, Germany
    Posts
    289


    Did you find this post helpful? Yes | No

    Exclamation

    You have to set the CKP-bit even after a WRITE-operation.
    Try to disable the HSEROUT-lines.
    Maybe this command will alter the TRISC-register, which will kill the I2C-engine.
    Sometime, you should clear the OV-bit...
    PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2

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


    Did you find this post helpful? Yes | No

    Default

    I have been trying to get a 18F2620 to run as a slave. i ran across this in the ERRATA for this device.
    Code:
    43. Module: MSSP (I2C Slave)
    The MSSP module operating in I2C, 7-Bit Slave
    mode (SSPM3:SSPM0 = 0110) may not send a
    NACK bit (/ACK) in response to receiving the slave
    address loaded in SSPADD<7:1>. Addresses are
    in one of these ranges:
    • 0x00 to 0x07
    • 0x78 to 0x7F
    These addresses were reserved by Philips® Semiconductors
    in “The I2C Specification”, Version 2.1,
    released January 2000. Section 10.1 “Definition of
    bits in the first byte” defines the purposes of these
    addresses.
    This specification can be found at:
    http://www.semiconductors.philips.com/i2c
    Work around
    This version of the silicon does not respond to
    slave addresses in the ranges previously listed.
    Use either of these work arounds:
    • Change the 7-bit slave address in SSPADD to
    an address in the range of 0x08 to 0x77.
    • Use Revision B silicon. This version of silicon
    removes this issue’s addressing restrictions.
    I have gotten sporadic results for the master reading the slave in the following code.

    Darrell's Instant Interrupt

    Code:
        '   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
    
    ''----------------- Initialization Done! -----------------------------
    
    @ INT_ENABLE  SSP_INT     ; Master Synchronous Serial Port Interrupt Flag bit. The transmission/reception is complete
    'txbuffer = 0
    The Interrupt handler

    Code:
    I2C_Int:
    If R_W = 0 then
        if D_A = 0 then
           address = SSPBUF
        else
    
    Still working on master to slave write
    '        if bf = 1 then
    '           if rxcnt <= rxbufferlen then
    '              datain[rxcnt] = SSPBUF
    '              rxcnt = rxcnt + 1
    '              if rxcnt = rxbufferlen then rxcnt = 0
    '           endif   
              
              
            EndIF 
        endif
    else
        dataout = SSPBUF     'dummy read
        if txcnt > 0 then
           SSPBUF = txbuffer[txoutptr]
           txoutptr = txoutptr + 1       
                  if txoutptr = txbufferlen then txoutptr = 0
           txcnt = txcnt - 1
        else
        'no byte to send
        endif       
    endif
    CKP = 1 
    @ INT_RETURN
    and the main loop. I want to send three bytes to the master. In this case "three sevens".

    Code:
    Main:
    SSPOV = 0
    WCOL = 0
         
         if txcnt < txbufferlen - 1 then
                        
                TxBuffer[txinptr] = 7
                txinptr = txinptr + 1
                if txinptr = txbufferlen then txinptr = 0
               
                txcnt = txcnt + 1
                
        endif
    
    WrData=0 
    
    
    
    goto main 
    end
    I did the same slave program in "C" and it works well.

    The Master is reading and writing to a RTC module and a bank of 4 24lc256 EEProms and a I2C Port expander with out any problems.

    It is getting close

    Take care

    Dave

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


    Did you find this post helpful? Yes | No

    Lightbulb That makes sense...

    Although the 16F guys have been having good luck with low addresses, it makes sense that the errata sheet would point out the old Phillips rule about low addresses. I haven't tried an address above $08 before... gotta go give that a shot too. I'll report back with any results, good or bad.

    Rswain

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


    Did you find this post helpful? Yes | No

    Unhappy New attempts

    Today I tried changing the Master and Slave addresses to higher numbers. I tried $26, $A6, and $02 just for good measure. They all responded with the same results; the slave sees the address, matches to its own, sets the interrupt flag, sets the Buffer Full flag, loads the address byte into the SSPBUF and I can read it from there. Although I reported before that the Slave wasn't sending an ACK, I think I was wrong. When I poll the ACKSTAT in the Master, it comes back with a "0" which I thought was NO ACK, but in fact a 0 is reporting a good ACK.

    I've also switched to 18F4685 on both Master and Slave just eliminate the possiblilty of bad chips. Same results.

    I took Daniel's suggestion to try to read from the Slave instead of sending to it. The slave responds by loading the first digit in its SSPBUF but I'm not seeing it show up at the Master.

    I notice that the Slave's D_A (SSPSTAT.5 ' SSP Data not Address) is always showing "1" for DATA and never have I seen a "0" for ADDRESS. Is that OK? How would that bit get changed?

    Rswain
    Last edited by rswain; - 14th March 2009 at 03:55.

  34. #34


    Did you find this post helpful? Yes | No

    Default

    I'll try to buy a 18F2620 this week and run a few test Hope I can get it here, I live in Argentina, it's not always easy to find those "big brothers" ...

    EDIT: I found a 18F452 laying around on the desk, will this serve the purpose???
    Last edited by DanPBP; - 14th March 2009 at 04:47.

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


    Did you find this post helpful? Yes | No

    Default Most any 18F will do

    Daniel - I'd be happy if any 18F would work. I'm starting to think something's wrong with PBP and 18F.

    Thanks for your continued attempts to beat this problem into submission!

    I'm going to switch to 16F877A (the old standby to see if I can get them to talk - once I get that, then we'll come back here and try again!

    Robert

  36. #36


    Did you find this post helpful? Yes | No

    Default

    I played all night with a 16F88 as a master and a 16F877 as a slave (the other way around I was playing these days)...

    I can send commands to the slave (16F877) and this is working fine, but something is wrong because I cannot read from the slave.

    I mean, I can read from the slave, but I'm not getting the value I wanted. For example, I'm supposed to read 12, but I'm reading 1.

    The code is the same I'm using for the 16F88 as a slave, so, that code is working fine. This is really strange.

    PS: today is my birthday, and it's almots 7am and I need some sleep... I'll continue later in the afternoon...
    Last edited by DanPBP; - 14th March 2009 at 09:40. Reason: more info added

  37. #37
    Join Date
    Oct 2004
    Location
    Hangover, Germany
    Posts
    289


    Did you find this post helpful? Yes | No

    Exclamation

    I has gone through this hell too.

    I bought a cheap LA (Po.Scope) in order to debug my code. I was looking for errors in PBP too, but at least the error was im my code (and maybe in PBP)...

    Please, post your code again.
    I use the 16F872 and 16F876 and 18F252 as I2C-slaves. They work all !!!

    Look at this page: http://www.astrosurf.com/soubie/pic_as_an_i2c_slave.htm
    Last edited by BigWumpus; - 14th March 2009 at 14:42.
    PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2

  38. #38


    Did you find this post helpful? Yes | No

    Default

    I saw that page and talked to Robert, but, to be honest, I don't understand how to use his code...

  39. #39
    Join Date
    Oct 2004
    Location
    Hangover, Germany
    Posts
    289


    Did you find this post helpful? Yes | No

    Exclamation

    Again ... post your code !
    PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2

  40. #40
    Join Date
    Oct 2004
    Location
    Hangover, Germany
    Posts
    289


    Did you find this post helpful? Yes | No

    Exclamation

    Quote Originally Posted by danielhr77 View Post
    I saw that page and talked to Robert, but, to be honest, I don't understand how to use his code...


    What ?

    It's PBP !
    PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2

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

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