• AVR Freaks

Hot!difficulties with Slave i2c BTO on K42

Author
j2423
Super Member
  • Total Posts : 283
  • Reward points : 0
  • Joined: 2015/05/15 23:10:36
  • Location: 0
  • Status: offline
2018/12/12 11:06:14 (permalink)
0

difficulties with Slave i2c BTO on K42

Have a slave (0x31) that hangs the bus every 5 mins or so.
 
Inevitably this occurs somewhere in the Transmit segment as in 'scope screenshot attached.
 
(The hanging tends to occur mid-byte, so don’t think it’s clock stretching gone wrong.)
 
Haven’t been able to figure out the Cause (suggestions welcome!) so decided to put a band-aid on it by using the Slave BTO feature of the K42.

In the K42 data sheet 33.3.9 it says:
For example, Timer2 can be selected as the bus timeout source and configured to count when the SCL pin is low. If the timer runs over before the SCL pin transitioned high, the timer-out pulse will reset the module.
 
That sounds promising but how do you know when the SCL pin goes low?
 
There’s a small amount of documentation on BTO in TB2669, pages 11 and 12, but the example that they give is for Receive and suggests Enabling the Timer when (1==RXIF)&&(1==RXBF). It doesn’t clarify whether hardware or software should do this but I’m thinking software.

/* Setup Buffer Timer Overflow */
I2C1BTObits.BTO = 0b010; // uses TMR4
I2C1ERRbits.BTOIF = 0; // clear interrupt
I2C1ERRbits.BTOIE = 1; // enable interrupt

PIR2bits.I2C1RXIF=0;
PIE2bits.I2C1RXIE=1; // used for BTO purposes
 
//Then in the ISR :
if (PIR3bits.I2C1IF){
if ((1==PIR2bits.I2C1RXIF)&&(1==I2C1STAT1.RXBF)) {
TMR4_Counter8BitSet(0);
TMR4_StartTimer();
}
}

Presumably, since this is about catching a peripheral that has hung, only the BTO knows that SCL has floated high again before the SMA=0 so you just leave the Timer running. But you do need to Stop the timer so it’s not in the overflowed state when SMA=1 again. How do you do that?
 
If the module is configured as a slave and a bus time-out event occurs while the slave is active (Slave Mode Active bit SMA = 1), the SMA and Slave Clock Stretching (CSTR) bits are cleared, the module is reset, and the Bus Time-Out Interrupt Flag (BTOIF) bit is set. (TB2669)
 
Now their generous example is for the Receive scenario. Which is not the problem I’m having and can easily test. How to trigger the Timer for the Transmit case? Frankly I’m totally confused. Surely the moment that SMA=1 the peripheral is alive and could do something to hang the bus so that’s the time to start the timer?
Are there no other examples to be found of how to do this?

Attached Image(s)

#1

9 Replies Related Threads

    mbrowning
    USNA79
    • Total Posts : 1874
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: online
    Re: difficulties with Slave i2c BTO on K42 2018/12/12 11:44:44 (permalink)
    +1 (1)
    I think you set up the timer in mode 00111 (free running period with hardware reset high level). TMRx_ers is set to TxINPPS which is set to be the pin that I2C uses for SCL. Thus the timer only runs when SCL is low and is reset when SCL is high. If the timer overflows, then the flag is set, and the bus timeout interrupt is triggered.
     
    This is all automatic, no software involvement except for initializing the timer and I2C registers, and handling the timeout condition.
     
    I guess you can use the bus timeout interrupt to reset/powerdown the slave, but if you can't do that then none of this really helps.
    #2
    j2423
    Super Member
    • Total Posts : 283
    • Reward points : 0
    • Joined: 2015/05/15 23:10:36
    • Location: 0
    • Status: offline
    Re: difficulties with Slave i2c BTO on K42 2018/12/12 13:03:55 (permalink)
    0
    Can't tell you how excited am to try. Thanks a lot!
     
    btw. is it often necessary to power cycle to clear a hang on a PIC18 slave? Guess am about to find out! From TB2669:
     
    SMBus and PMBus protocols require a bus watchdog to prevent a stalled device from hanging the bus indefinitely. The I2C module provides a bus time-out feature that can be used to reset the module if one of the bus devices is taking too long to respond.
     
    On SMBus Wikipedia says: 
     
    SMBus has a time-out feature which resets devices if a communication takes too long. This explains the minimum clock frequency of 10 kHz to prevent locking up the bus. I²C can be a ‘DC’ bus, meaning that a slave device stretches the master clock when performing some routine while the master is accessing it. This will notify to the master that the slave is busy but does not want to lose the communication. The slave device will allow continuation after its task is complete. There is no limit in the I²C-bus protocol as to how long this delay can be, whereas for an SMBus system, it would be limited to 35 ms. SMBus protocol just assumes that if something takes too long, then it means that there is a problem on the bus and that all devices must reset in order to clear this mode. Slave devices are not then allowed to hold the clock LOW too long.
    post edited by j2423 - 2018/12/12 13:05:14
    #3
    j2423
    Super Member
    • Total Posts : 283
    • Reward points : 0
    • Joined: 2015/05/15 23:10:36
    • Location: 0
    • Status: offline
    Re: difficulties with Slave i2c BTO on K42 2018/12/14 02:05:39 (permalink)
    0
    Well, the BTOIF triggers perfectly using the timer as you suggest. Many thanks.
     
    Not sure what is meant by BTO resetting the peripheral. It didn't clear my SCL low hang.
     
    However by running the entire I2C1_Initialize() sequence after the interrupt all is good and the bus takes off again.
     
    Should probably try to understand by elimination what exactly is required after the BTO event.
     
    Anyone happen to know?
    #4
    Doubletop
    Starting Member
    • Total Posts : 43
    • Reward points : 0
    • Joined: 2019/03/07 21:46:09
    • Location: 0
    • Status: offline
    Re: difficulties with Slave i2c BTO on K42 2021/01/20 14:04:13 (permalink)
    0
    j2423
     
    Should probably try to understand by elimination what exactly is required after the BTO event.
     
    Anyone happen to know?




    Have you managed to resolve this?
     
    I am using a variant of Chris Harris's I2C example and have the BTO timer working and interrupting.
     
     
    void I2C1_ReadDataBlock(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
    {
         I2C1ADB1 = (uint8_t)(address << 1); // Load slave address and shift
        I2C1TXB = reg; // Load slave starting register address
        I2C1CNT = 1; // Load count
        I2C1CON0bits.RSEN = 1; // Set RSEN for master read
        I2C1CON0bits.S = 1; // Set Start to get things going
        while(!I2C1CON0bits.MDR); // Wait until master is ready to receive data
        
        address = (uint8_t)(address << 1);
        I2C1ADB1 = (uint8_t)(address | 0x01); // Load address with Read enabled
        I2C1CNT = len; // Load length of expected packet in bytes
        I2C1CON0bits.S = 1; // Set Start to begin Restart condition
        I2C1CON0bits.RSEN = 0; // Clear RSEN
        while(I2C1CNT) // While there is a count
        {
            
            while(!I2C1STAT1bits.RXBF); // Wait until buffer receives data
            *data++ = I2C1RXB; // Transfer data into array, hardware decrements count
        }
        wait4Stop();
    }

     
    The problem is that the code halts at while(!I2C1STAT1bits.RXBF); and the BTO timeout occurs and the interrupt is serviced. I've tried executing the I2C1_Initialize function but when the interrupt returns to the while loop the bus doesn't recover so still hangs.
     
    I've tried any amount of resetting flags etc but still the same. I've also tried adding other conditions aound the checking BTO flag and  a forced exit with a return (messy) this has resulted in a later hang in the line.
     
     while(!I2C1CON0bits.MDR); // Wait until master is ready to receive data

     
    There must be some smart way of releasing the bus, causing the slaves to release and exiting this loop. 
     
    Any clues anyone?
    post edited by Doubletop - 2021/01/20 14:30:07
    #5
    mbrowning
    USNA79
    • Total Posts : 1874
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: online
    Re: difficulties with Slave i2c BTO on K42 2021/01/20 17:41:57 (permalink)
    0
    You should start your own thread rather than hijack another on a different subject.
    But since you're here:
    In the code I use that's most similar to yours, I set RSEN=0 and never change it.
    Instead of testing MDR I test MMA to find the end of the TX part of a read access.
    Otherwise essentially the same except I break it all up into state machine chunks cause I just don't do blocking code.
     
    I vaguely remember having a problem like yours at some point, but I don't recall if what I did above fixed it or there was something else.
     
    You should test ACKSTAT to see if the slave is even communicating.
     
     
    #6
    Mysil
    Super Member
    • Total Posts : 4111
    • Reward points : 0
    • Joined: 2012/07/01 04:19:50
    • Location: Norway
    • Status: online
    Re: difficulties with Slave i2c BTO on K42 2021/01/20 20:02:17 (permalink)
    +1 (1)
    Hi,
    If a I2C transfer is disturbed during Reading from a I2C Slave device,
    then it may happen that I2C slave is trying to  transmit a 0 bit on SDA signal line,
    and is waiting for additional SCL pulses.
     
    If the I2C Slave  is Not a SMBus device, then I2C Master cannot clear this state, by just initializing Master code.
    Master will detect a Bus Collision when a new transfer is attempted.
    See: Section 3.1.16 Bus clear in: I2C-bus Specification and User Manual, UM10204, it is available on NXP  website.
     
    If Bus Timeout is used in Master mode, then I think the BTO timer should be Reset before a new transfer is started.
    Make sure that BTO interval is more than long enough for the longest transfer to be performed.
     
    Also, I have seen strange signaling on the Bus, causing trouble for other devices on the bus, 
    if the Timer that is used for Bus Timeout is left running when there is No transfer going on.
     
        Mysil
    #7
    Doubletop
    Starting Member
    • Total Posts : 43
    • Reward points : 0
    • Joined: 2019/03/07 21:46:09
    • Location: 0
    • Status: offline
    Re: difficulties with Slave i2c BTO on K42 2021/01/20 21:48:14 (permalink)
    0
    mbrowning
    You should start your own thread rather than hijack another on a different subject.



    Yes I would normally, but my question was aimed at J2423 to see how they had resovled the problem with the intention of keeping all the related information in one place. However, thanks for taking the time to reply.
     
    I agree with you that blocking code is not recomended and something I wouldn't normally do. However, in an attempt to get something working the code is from Chris Best example on Microchip Xpress I2C Master and Slave Communication using the PIC18F26K42. ( https://mplabxpress.microchip.com/mplabcloud/example/details/519)
     
    I'll  have a look at your suggestions and make changes to Chris's code to see if they can improve things.
     
    Thanks again
    #8
    Doubletop
    Starting Member
    • Total Posts : 43
    • Reward points : 0
    • Joined: 2019/03/07 21:46:09
    • Location: 0
    • Status: offline
    Re: difficulties with Slave i2c BTO on K42 2021/01/20 21:59:54 (permalink)
    0
    Mysil
    Hi,
    If a I2C transfer is disturbed during Reading from a I2C Slave device,
    then it may happen that I2C slave is trying to  transmit a 0 bit on SDA signal line,
    and is waiting for additional SCL pulses.




    My problem exists because I have numerous interrupts firing with the I2C functions being used in the low level main loop. As the I2C at the bottom of the stack I haven't looked at making that interrupt driven, until I discovered this problem and implemented BTO.
     
    As this thread adresses the BTO timer is reset when the SCL line goes high. I have extended timer to ensure that it doesn't interfere with 'normal' operation of the I2C only when it is delayed by other system interrupts.
     
    Anyway ideas are gratefully recieved and provide a catalyst for further thought.
    #9
    oliverb
    Super Member
    • Total Posts : 403
    • Reward points : 0
    • Joined: 2009/02/16 13:12:38
    • Location: 0
    • Status: offline
    Re: difficulties with Slave i2c BTO on K42 2021/01/21 06:15:03 (permalink)
    0
    Thinking of the original problem: that looks like an indefinite clock-stretch. I wonder if the slave ISR is failing to fill/empty the buffer at a crucial point.
     
    I was working on an i2C slave design in 2018, I believe I was able to use the MCC-supplied I2C slave code back then though possibly with slight modification. Its been two years so I'm not clear on the details. The source code I have now retains the MCC code to emulate an I2C RAM, and uses the array as a mailbox for settings. An older design used an interupt handler obtained from the forum, I'm not sure where I found it now but I could try to dig up the old post.
     
    I don't believe I ever had bus lock-up, but I had a lot of capacitance on the bus so it was slow, and also the master was in software and quite dumb so it would probably force through a lock-up.
     
    Link to an older example https://www.microchip.com/forums/FindPost/741878
     
     
     
    post edited by oliverb - 2021/01/21 08:49:51
    #10
    Jump to:
    © 2021 APG vNext Commercial Version 4.5