I2C Master Slave issues.


Closed Thread
Results 1 to 10 of 10
  1. #1
    Join Date
    Aug 2005
    Location
    NC, USA
    Posts
    53

    Default I2C Master Slave issues.

    Hi. I have been struggling getting an I2C master slave routine going between two different PICs. I can write from the master with no issues, but when ever I try to read it resets the master and it keeps resetting as soon as it hits an I2C cmd. It seems to go through once, but then starts to reset and never goes through the routine again as if something is not being released or the like from the slave... I have attached the master and slave code below. Any help would be greatly appreciated. Thanks, Charlie

    ' PicBasic Pro Master PIC18F2220 to read and write to I2C slave

    @ __CONFIG _CONFIG1H, _INTIO2_OSC_1H
    @ __CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_128_2H
    @ __CONFIG _CONFIG3H, _MCLRE_OFF_3H
    @ __CONFIG _CONFIG4L, _LVP_OFF_4L

    OSCCON = $70
    DEFINE OSC 8

    DEFINE I2C_HOLD 1
    SCL VAR PORTC.3 ' Clock pin
    SDA VAR PORTC.4 ' Data pin

    ' Alias pins (0=Output, 1=Input)
    L1 VAR LATB.7 :TRISB.7 = 0
    L2 VAR LATB.6 :TRISB.6 = 0
    L3 VAR LATB.5 :TRISB.5 = 0
    L4 VAR LATB.4 :TRISB.4 = 0

    'Define RAM
    i var byte
    a VAR BYTE[8] ' Holds 8 characters read from slave
    j var byte

    'blink L1-L4 to signal its alive or has been reset
    for i = 1 to 12
    high L1: pause 25: low L1
    high L2: Pause 25: Low l2
    high l3: pause 25: low l3
    high l4: pause 25: low l4
    next i
    j= 125

    loop:
    toggle L1
    j= j+1
    I2CWrite SDA,SCL,$02,[j], bogus ' Write value to slave
    if j>130 then j=125
    Pause 250
    'I2CRead SDA,SCL,$02,[STR a\8], bogus ' Read string from slave
    GoTo loop ' Do it forever

    bogus:
    high l2: Pause 1000: low l2
    GoTo loop


    ' PicBasic Pro I2C slave program - PIC16F819

    @ device INTRC_OSC_NOCLKOUT
    '@ DEVICE XT_OSC ' System Clock Options
    @ DEVICE WDT_ON ' Watchdog Timer
    @ DEVICE PWRT_ON ' Power-On Timer
    @ DEVICE BOD_ON ' Brown-Out Detect
    @ DEVICE MCLR_OFF ' Master Clear Options
    @ DEVICE LVP_OFF ' Low-Voltage Programming
    @ DEVICE CPD_OFF ' Data Memory Code Protect
    @ DEVICE PROTECT_OFF ' Program Code Protection

    OSCCON = $70 'sets the oscillator speed
    DEFINE OSC 8 'Oscillator speed in MHz: 3(3.58) 4 8 10 12 16 20 24 25 32 33 40

    ' Alias pins (0=Output, 1=Input)
    scl VAR PORTB.3: TRISB.3 = 1 ' I2C clock input
    sda VAR PORTB.4: TRISB.4 = 1 ' I2C data input
    L1 var PORTA.2 :TRISA.2 = 0
    L2 VAR PORTA.4 :TRISA.4 = 0
    L3 VAR PORTB.0 :TRISB.0 = 0
    L4 VAR PORTB.3 :TRISB.3 = 0 ' Green LED
    L5 VAR PORTB.6 :TRISB.6 = 0 ' Red LED

    ' Define used register flags
    SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag
    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

    ' Define constants
    I2Caddress CON 2 ' Make our address 2

    ' Allocate RAM
    result VAR BYTE ' ADC result
    datain VAR BYTE ' Data in
    dataout VAR BYTE[8] ' Data out array
    readcnt VAR BYTE ' I2C read count

    ' Initialize I2C slave mode
    SSPADD = I2Caddress ' Set our address
    'SSPCON2 = 0 ' General call address disabled
    SSPCON = $36 ' Set to I2C slave with 7-bit address
    readcnt = 0 ' Zero counter

    high L1: high L2: high L3: high L4 : High L5
    pause 200
    low L1: low L2: low L3: low L4 : Low L5
    dataout[0] = 0
    dataout[1] = 1
    dataout[2] = 2
    dataout[3] = 3
    dataout[4] = 4
    dataout[5] = 5
    dataout[6] = 6
    dataout[7] = 7
    dataout[8] = 8

    mainloop: ' Main program loop
    toggle l1
    IF SSPIF Then ' Check for I2C interrupt flag
    GoSub i2cslave
    EndIF
    GoTo mainloop ' Do it all forever

    i2cslave: ' I2C slave subroutine
    SSPIF = 0 ' Clear interrupt flag
    IF R_W = 1 Then i2crd ' Read data
    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 data into array
    toggle l2
    if datain = 127 then
    high l5
    else
    low l5
    endif
    GoTo i2cexit

    i2crd: ' I2C read data from us
    toggle l3
    IF D_A = 0 Then
    readcnt = 0 ' Mark as first read
    EndIF
    SSPBUF = dataout[readcnt] ' Get data from array
    CKP = 1 ' Release SCL line
    readcnt = readcnt + 1 ' Move along read count
    GoTo i2cexit ' That's it

    i2cexit:
    Return

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


    Did you find this post helpful? Yes | No

    Default

    I must be blind... but nowhere i see you have disabled the multiplexed analog modules for your LEDs... didn't go too far in your code though.

    And proof that's probably a copy/paste code example prior to check the datasheet SDA=PORTB.1, SCL=PORTB.4. Lucky your are... TRISB=255 at power-up

    So.. is there any Register Bit that change between the F877 and the 819... hummm.. let's see
    Last edited by mister_e; - 28th March 2008 at 02:25.
    Steve

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

  3. #3
    Join Date
    Aug 2005
    Location
    NC, USA
    Posts
    53


    Did you find this post helpful? Yes | No

    Default

    I am only using a couple channels of the analog. I have removed all the analog and many other things from the program just trying to get a simple communication going, but to no avail...

    I just changed the master loop to the following to see if once it crashes I can write anymore and I can not. The master writes until it does a read, then the master resets, and the master will not write anymore, it just keeps resetting. So I think the slave is being put in some state and holds there that causes the reset...

    loop:
    toggle L1
    j= j+1
    I2CWrite SDA,SCL,$02,[j], bogus ' Write value to slave
    if j>130 then
    j=125
    I2CRead SDA,SCL,$02,[STR a\8], bogus ' Read string from slave
    endif
    Pause 250
    GoTo loop ' Do it forever

  4. #4
    Join Date
    Mar 2008
    Location
    Texas, USA
    Posts
    114


    Did you find this post helpful? Yes | No

    Default

    I have yet to get involved with the hardware issues of I2C ports on PICs, so this may be no help, but who's doing the clocking during the read from the slave to the master? Is it setup in the slave I2C to allow for the master to provide the clock? Again, I'm not able to know for sure what you've done with the hardware since I'm not familiar with those registers.

    In my bit-banging I2C (current project) I've locked down the I2C transfers by failing to deal with the acknowledges correctly and ill timed stop commands after a "last byte" read. I don't know how PBP deals with this read issue, but a correct stop command comes after a reading device does not send an acknowledge (after reading the last byte), else the sending I2C drives the SDA line with the next bit of data. This can mess up the master’s ability to issue the stop command.

    Also, I noted in the PBP manual this:

    I2CREAD and I2CWRITE can be used to read and write data to a serial EEPROM with a 2-wire I2C interface such as the Microchip 24LC01B and similar devices. This allows data to be stored in external non-volatile memory so that it can be maintained even after the power is turned off. These commands operate in the I2C master mode and may also be used to talk to other devices with an I2C interface like temperature sensors and A/D converters.
    No, I'm not Superman, but I did stay at a Holiday Inn Express last night!

  5. #5
    Join Date
    Aug 2005
    Location
    NC, USA
    Posts
    53


    Did you find this post helpful? Yes | No

    Default

    I have it working kinda... It is real sensitive to having the slave ready and waiting, which is not possible because I ultimately need the slave to do more involved tasks.

    I have attached the code below with comments of my remaining issues. ANy further help would be great!

    ' PicBasic Pro Master PIC18F2220 to read and write to I2C slave

    @ __CONFIG _CONFIG1H, _INTIO2_OSC_1H
    @ __CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_128_2H
    @ __CONFIG _CONFIG3H, _MCLRE_OFF_3H
    @ __CONFIG _CONFIG4L, _LVP_OFF_4L

    OSCCON = $70
    DEFINE OSC 8

    ' Set up serial UART
    define HSER_RCSTA 90H ' Set Receive Status and control register
    DEFINE HSER_TXSTA 24H ' set transmit status and control register
    'DEFINE HSER_BAUD 4800 ' 2403=2400Kbps, 9615=9600Kbps,19231=19.2Kbps
    DEFINE HSER_BAUD 9615 ' 2403=2400Kbps, 9615=9600Kbps,19231=19.2Kbps
    define HSER_CLROERR 1 ' reset on serial buffer overflow
    'RCIF VAR PIR1.5 ' UART receive interrupt flag

    ' Define Analog parameters
    ADCON0 = %00010001 '
    ADCON1 = %00001100 ' Anolog AN0-AN4, all else digital
    ADCON2 = %10000111 ' right justify result
    CMCON = %00000111 ' Comparators OFF to allow inputs on pins CMCON = 7
    INTCON = %00000000 ' all interrupts OFF
    Define ADC_BITS 10 ' Set number of bits in result
    Define ADC_CLOCK 3 ' Set clock source (3=rc)
    Define ADC_SAMPLEUS 50 ' Set sampling time in uS

    DEFINE I2C_HOLD 1
    DEFINe I2C_SLOW 1 'access a standard speed device at above 8MHz
    SCL VAR PORTC.3 ' Clock pin
    SDA VAR PORTC.4 ' Data pin

    ' Alias pins (0=Output, 1=Input)
    L1 VAR LATB.7 :TRISB.7 = 0
    L2 VAR LATB.6 :TRISB.6 = 0
    L3 VAR LATB.5 :TRISB.5 = 0
    L4 VAR LATB.4 :TRISB.4 = 0

    'Define RAM
    i var byte
    a VAR BYTE[4] ' Holds 8 characters read from slave
    j var byte

    'blink L1-L4 to signal its alive or has been reset
    for i = 1 to 12
    high L1: pause 25: low L1
    high L2: Pause 25: Low l2
    high l3: pause 25: low l3
    high l4: pause 25: low l4
    next i
    j= 125

    loop:
    toggle L1
    j= j+1
    I2CWrite SDA,SCL,$02,[j], bogus ' Write value to slave
    if j>130 then
    j=125
    pause 1
    I2CRead SDA,SCL,$02,[STR a\4], bogus ' Read string from slave
    endif
    hserout ["DATA 0:",dec a[0]," 1:",dec a[1]," 2:",dec a[2]," 3:",dec a[3]," 4:", dec a[4] ," ",13]
    'a[0-2] are the slave analogs, it seems to be reporting back the right numbers :-)
    'a[3] should be readcnt from master, its just toggles between 2 and 3??
    'a[4] should be datain from the slave. j is toggling LED in slave, so the number is
    ' being sent, its just not getting returned, it only send back an 8 :-(
    Pause 250
    GoTo loop

    bogus:
    high l2: Pause 1000: low l2
    GoTo loop


    ' PicBasic Pro I2C slave program - PIC16F819

    @ device INTRC_OSC_NOCLKOUT
    @ DEVICE WDT_ON ' Watchdog Timer
    @ DEVICE PWRT_ON ' Power-On Timer
    @ DEVICE BOD_ON ' Brown-Out Detect
    @ DEVICE MCLR_OFF ' Master Clear Options
    @ DEVICE LVP_OFF ' Low-Voltage Programming
    @ DEVICE CPD_OFF ' Data Memory Code Protect
    @ DEVICE PROTECT_OFF ' Program Code Protection

    OSCCON = $70 'sets the oscillator speed
    DEFINE OSC 8 'Oscillator speed in MHz: 3(3.58) 4 8 10 12 16 20 24 25 32 33 40

    ' Define ADCIN parameters
    Define ADC_BITS 10 ' Set number of bits in result
    Define ADC_CLOCK 3 ' Set clock source (3=rc)
    Define ADC_SAMPLEUS 50 ' Set sampling time in uS
    TRISA = %11111111 ' Set PORTA to all input
    ADCON1 = %10000100 ' Set A2 A4 digital, A0 A1 A3 Analog, rt justify

    AN0 var word ' average Positioning Potentiometer Voltage
    AN1 var word ' Trim Pot 1
    AN3 VAR WORD ' Trim Pot 2
    AN0i var word ' Positioning Potentionmeter

    ' Alias pins (0=Output, 1=Input)
    scl VAR PORTB.3: TRISB.3 = 1 ' I2C clock input
    sda VAR PORTB.4: TRISB.4 = 1 ' I2C data input
    L1 var PORTA.2 :TRISA.2 = 0
    L2 VAR PORTA.4 :TRISA.4 = 0
    L3 VAR PORTB.0 :TRISB.0 = 0
    L4 VAR PORTB.3 :TRISB.3 = 0 ' Green LED
    L5 VAR PORTB.6 :TRISB.6 = 0 ' Red LED

    ' Define used register flags
    DEFINe I2C_SLOW 1 'access a standard speed device at above 8MHz
    SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag
    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

    ' Define constants
    I2Caddress CON 2 ' Make our address 2

    ' Allocate RAM
    result VAR BYTE ' ADC result
    datain VAR BYTE ' Data in
    dataout VAR BYTE[4] ' Data out array
    readcnt VAR BYTE ' I2C read count

    ' Initialize I2C slave mode
    SSPADD = I2Caddress ' Set our address
    'SSPCON2 = 0 ' General call address disabled
    SSPCON = $36 ' Set to I2C slave with 7-bit address
    readcnt = 0 ' Zero counter

    low L1: low L2: low L3: low L4 : Low L5

    GoTo mainloop ' Skip over subroutines

    i2cslave: ' I2C slave subroutine
    SSPIF = 0 ' Clear interrupt flag
    IF R_W = 1 Then i2crd ' Read data
    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 data into array
    toggle l2
    if datain = 127 then
    high l5
    else
    low l5
    endif
    'this is toggling, so the master is sending the number is its toggling the led, so apears good
    'I want to receive more than on byte, how do I do this?
    GoTo i2cexit

    i2crd: ' I2C read data from us
    IF D_A = 0 Then
    'toggle l3 'this causes master to continously reset, too much of a pause?
    readcnt = 0 ' Mark as first read
    EndIF
    SSPBUF = dataout[readcnt] ' Get data from array
    CKP = 1 ' Release SCL line
    readcnt = readcnt + 1 ' Move along read count
    GoTo i2cexit ' That's it

    i2cexit:
    Return

    mainloop: ' Main program loop
    ' have to check12c every step of both PICs lock up. Need a way of doing this as an iterupt??
    ' I plan on having a lot of other code the slave needs to execute, It is not practical to
    ' be continously checking like this...
    gosub checki2c
    toggle l1
    gosub checki2c
    ADCIN 0, AN0 ' Read ADC channel 0
    gosub checki2c
    AN0 = an0/4
    gosub checki2c
    dataout[0] = AN0

    gosub checki2c
    ADCIN 1, AN1
    gosub checki2c
    AN1 = an1/4
    gosub checki2c
    dataout[1] = AN1

    gosub checki2c
    ADCIN 3, AN3
    gosub checki2c
    AN3 = an3/4
    gosub checki2c
    dataout[2] = AN3

    gosub checki2c
    dataout[3] = readcnt

    gosub checki2c
    dataout[4] = datain
    'this value is not getting back to the master???/

    GoTo mainloop ' Do it all forever

    checki2c:

    'Check for I2C interrupt flag
    IF SSPIF Then
    GoSub i2cslave
    EndIF

    return

  6. #6
    Join Date
    Mar 2008
    Location
    Texas, USA
    Posts
    114


    Did you find this post helpful? Yes | No

    Default

    If you are having issues with the slave not being ready, use the standard I2C busy protocol; have the slave hold the clock low while it's busy. Master will check clock line status before trying to send out data.
    No, I'm not Superman, but I did stay at a Holiday Inn Express last night!

  7. #7
    Join Date
    Aug 2005
    Location
    NC, USA
    Posts
    53


    Did you find this post helpful? Yes | No

    Default

    Hi. The issue with holding the clock line low is I have multiple slaves, so I don't think the master will get a word in inchwise with all the slaves pulling the clock low...

  8. #8
    Join Date
    Mar 2008
    Location
    Texas, USA
    Posts
    114


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by cpayne View Post
    Hi. The issue with holding the clock line low is I have multiple slaves, so I don't think the master will get a word in inchwise with all the slaves pulling the clock low...
    Yes, with muli slaves that could get nasty. I thought about that but had re-read your first line in the top post and it said 2 pics. I thought this was just a 2 pic i2c system.
    No, I'm not Superman, but I did stay at a Holiday Inn Express last night!

  9. #9
    Join Date
    Aug 2005
    Location
    NC, USA
    Posts
    53


    Did you find this post helpful? Yes | No

    Default

    Yes, I am trying to get two working for now, then as soon as I get one good slave, I plan on adding...

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


    Did you find this post helpful? Yes | No

    Default

    Maybe I'm missing something, but it looks like you are polling for the Interrupt Staus Bit in MAIN, and when it is set, you go off and read the receive register. Because you are using a polled operation, not an interrupt-driven one, you can't catch data as soon as it arrives. If you use Darrel's Instant Interrupts and make your I2C routine an ISR, you should be able to receive data any time - even halfway through an A/D conversion.
    Charles Linquist

Similar Threads

  1. I2C Master/Slave 16F88/16F767 working code
    By DanPBP in forum Code Examples
    Replies: 2
    Last Post: - 23rd October 2012, 22:31
  2. HARDWARE I2C SAMPLE CODE question
    By Michael Wakileh in forum Code Examples
    Replies: 2
    Last Post: - 16th June 2009, 21:07
  3. Another I2C Slave Routine Problem
    By DanPBP in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 19th February 2009, 05:50
  4. Please help with i2cslave i2c slave
    By cycle_girl in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 1st December 2005, 13:55
  5. Replies: 2
    Last Post: - 10th June 2005, 02:34

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