This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: I2CMasterBusBusy stuck

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: ADS1110

I'm using an I2C module to communicate with the ADS1110 ADC. My controller is the only master on the line. Everything works fine, however occasionally, when I download the application onto the controller and enter debug mode, or when I restart the device, the I2C line will get stuck in the I2CMasterBusBusy state, and I am unable to communicate with the ADC (since I check I2CMasterBusBusy on every iteration). Is there a way to reset the state of the I2C bus? Should I use some kind of timeout?

Regards,

Ksawery

  • If the TM4C is halted or reset while doing an I2C transfer, the slave may hold the SDA signal low waiting for the remaining clocks. The master (TM4C) sees the bus stuck as busy. When you see this situation, particularly when trying to do the first transfer coming from a reset, you can make the I2CnSCL pin a digital output pin and "bit-bang" the clock to make the slave finish and release the SDA line. 

  • Thank you, I thought something like that might be happening, but I had no idea how to get out of the I2CMasterBusBusy condition. So what does "bit-banging" mean exactly? Should I just set the pin to 1 and loop until the SDA line is released? Or do I need to switch the pin between 1 and 0 periodically until the line is released?

    Regards,

    Ksawery

  • You need to make the SCL pin go low then high. The worst case scenario is when the slave was about to respond to a read request and the master was reset. In that case you need 9 toggles (low then high) of SCL then a stop condition (SCL low, SDA low, SCL high, SDA high). It gets a little more complicated if the slave does clock stretching or there are multiple masters on the bus.

  • Thank you, I will try this solution. Will the worst case work for all other cases as well? Here is a section of my code:

    // I2C configuration
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    if (!I2CMasterBusBusy(I2C0_BASE)
    {
    
    ... //read ADC
    
    }
    else //force ADC to release the SDA line
    {
         GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_2);
         GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_3);
    
         //Simulate SCL clock cycles
         for (ucSCLCycle = 0; ucSCLCycle < I2C_RESET_CYCLES; ucSCLCycle++) //I2C_RESET_CYCLES = 9
         {
             GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0); //SCL line low
             GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2); //SCL line high
         }
    
         //Simulate STOP condition
         GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0); //SCL line low
         GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0); //SDA line low
         GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2); //SCL line high
         GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_PIN_3); //SDA line high
    
         //Reconfigure pins to I2C
         GPIOPinConfigure(GPIO_PB2_I2C0SCL);
         GPIOPinConfigure(GPIO_PB3_I2C0SDA);
         GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
         GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    }

    Will this code be compatible with the standard speed of the I2C (100kbit/s)?

    For some reason I'm unable to reproduce the problem today, so I couldn't test my code as of yet.

    Regards,

    Ksawery

  • Ok, I finally managed to reproduce the problem, but the above code doesn't work the first time round - the else condition is entered twice before the line is no longer busy, so something is still wrong in the sequence of events.

    Regards,

    Ksawery

  • The SCL rate may be too fast. Do you have a logic analyzer or scope shot of the I2C bus in this condition? The ADS1110 supports 100KHz or 400KHz with no special configuration. Try adding a 2uS delay between each SCL transition.

  • Thank you. I don't have access to a scope at the moment unfortunately. I added the delay, but I'm finding it hard to reproduce the problem again. Why is 2uS specifically a good delay? I'm using I2C at the standard speed.

    I'll update on any progress if I manage to reproduce the issue.

    Regards,

    Ksawery 

  • From the ADS1110  data manual, there is nothing required to do to change between standard mode and fast mode. The I2C interface can work up to 400KHz. The 2uS low / 2uS high gives 250KHz which should be plenty of time. If the delay time is critical, you can use 1.25uS and that would then emulate a 400KHz SCL.

  • Thanks, that makes sense. I'll update on any results.

    Regards,

    Ksawery

  • I've managed to reproduce the issue again, and the solution does work, however the else condition is still entered twice before the I2C line is released. Perhaps I should increase the delay to match the 100kbit/s speed? Or maybe there's a bug in the order of events in my code? My code is now as follows:

    else //force ADC to release the SDA line
    {
        GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_2);
        GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_3);
    
        //Simulate SCL clock cycles
        for (ucSCLCycle = 0; ucSCLCycle < I2C_RESET_CYCLES; ucSCLCycle++)
        {
            GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0); //SCL line low
            SysCtlDelay(100);
            GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2); //SCL line high
            SysCtlDelay(100);
        }
    
        //Simulate STOP condition
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0); //SCL line low
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0); //SDA line low
        SysCtlDelay(100);
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2); //SCL line high
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_PIN_3); //SDA line high
    
        //Reconfigure pins to I2C
        GPIOPinConfigure(GPIO_PB2_I2C0SCL);
        GPIOPinConfigure(GPIO_PB3_I2C0SDA);
        GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
        GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    }

    The system clock is running at 50MHz.

    Regards,

    Ksawery

  • Ok, so trying different delays didn't change the outcome, however doubling the number of simulated SCL cycles from 9 to 18 (given that the else statement was entered twice when there were 9 cycles) solved the problem. So now i'm not sure why twice the number of SCL cycles are needed to release the I2C line?

    Regards,

    Ksawery

  • Ksawery said:
    I'm using an I2C module to communicate with the ADS1110 ADC. My controller is the only master on the line.     Everything works fine, however occasionally, when I download the application onto the controller and enter debug mode, or when I restart the device, the I2C line will get stuck in the I2CMasterBusBusy state

    Not to, 'Throw too big a monkey wrench' into this saga - but do you (really) want to deploy "I2CMasterBusBusy()?"

    The PDL notes:

    16.2.2.11 I2CMasterBusBusy

    Indicates whether or not the I2C bus is busy.
    Prototype: bool I2CMasterBusBusy(uint32_t ui32Base)
    Parameters: ui32Base is the base address of the I2C module. Description: This function returns an indication of whether or not the I2C bus is busy. This function can be used in a multi-master environment to determine if  another master  is currently using the bus.
    Returns: Returns true if the I2C bus is busy; otherwise, returns false.

    You describe your application as a, 'Single Slave tied to your single MCU' - thus can "I2CMasterBusBusy()' prove the correct function choice?    (i.e. How possibly can (another) Master be using this bus?)

    Instead - as a past (highly similar) thread noted - 

    16.2.2.12 I2CMasterBusy
    Indicates whether or not the I2C Master is busy.
    Prototype: bool I2CMasterBusy(uint32_t ui32Base)
    Parameters: ui32Base is the base address of the I2C module. Description: This function returns an indication of whether or not the I2C Master is busy transmitting or receiving data.
    Returns: Returns true if the I2C Master is busy; otherwise, returns false.

    Is not this, "I2CMasterBusy()" more appropriate for your 'Single Master' I2C Application?

    Do note - as past well advised - that parameters: 'I2C_MASTER_CMD_BURST_SEND_START' & 'I2C_MASTER_CMD_BURST_SEND_CONT' - BLOCK the generation of the I2C Stop Bit - if & when this 'more appropriate function'  (it would seem) is deployed...   (i.e. you would not employ I2CMasterBusy() following the presence of either of the above listed (devil) parameters...)

  • Thanks for your reply. Yes, I'm already using I2CMasterBusy() in my application and that part works fine. I wasn't sure whether I should use I2CMasterBusBusy() in my application since I have only one master, however I thought it wouldn't hurt either. Now that I experienced the issue that the ADC can sometimes hold the SDA line down, I'm not sure what would happen if I continue to run my application without the I2CMasterBusBusy() check. I'd rather account for this case manually, as per Bob Crosby's suggestions. As far as I'm aware, it doesn't cause any problems with the application.

    Regards,

    Ksawery

  • You are of course w/in your rights - yet if we, adopt that, 'Add unneeded functions procedure' - why STOP at 'Just this one?'

    More is 'not always' better - and in fact may 'open your application' to 'unintended consequences.'    The fact that you report (some) randomness is in fact a (likely) Warning - that 'ALL may not be well...'

    Your opening post (2nd sentence) clearly described a Single Master - and that fact was (apparently) 'missed!'

    Generating additional I2C clocks has succeeded in (sometimes - but not always) restoring Master-Slave exchanges.    However - the simple  'I2C Start'  usually 'Resets the Slaves' - enabling data exchanges again - yet (perhaps) w/out the 'randomness' which you are reporting.   (to my mind - that/similar techniques - prove superior to adding the (unnecessary) multi-master function...)

  • Ok, so the I2C START condition will indeed "reset" the slave? In that case, I agree that I2CMasterBusBusy() is not needed.

  • Well I tried removing the I2CMasterBusBusy() condition and the "workaround" code and everything worked fine, until the ADC held the line down again after entering debugging mode. The I2C start condition had no effect on it - the application was unable to read the ADC until a hard reset. So I will be sticking to the solution suggested by Bob Crosby.

    Regards,

    Ksawery

  • Ksawery said:
    everything worked fine, until the ADC held the line down again after entering debugging mode.

    Still - the employ of a function intended for 'Multi-Masters' - when only a 'Single Master is in play' - appears misguided.

    The, 'Why, When, Where & How' of your entry to 'Debug Mode' (which apparently (alone) causes your issue) - may deserve further (i.e. some) real examination...   

    Should not (some) concern/investigation be directed toward  the reason that the external  Slave (ADC) 'Held one of the I2C lines low?'    That is (or should be) your focus - is that not true?   

    By avoiding that analysis - are you not, 'Promoting a (solution)' - yet avoiding the proper (normal/customary) yet far more valuable, 'Search for the Cause?'    To be sure ... 'Prevention' always far outstrips -  any/all 'hoped for' cures...

  • Here is an article that claims 16 SCL cycles are required to recover a stuck slave after the master device was reset during a transmission.

    https://www.i2c-bus.org/i2c-primer/analysing-obscure-problems/blocked-bus/

    When I suggested 9 SCL I am afraid I missed the condition that the master was requesting a read and was reset during the ACK phase right after the command. It would require 2 8-bit transfers (16 clocks) to finish that read request. I think you are good with 18 clocks.

  • CB1,

    I believe in this case the root cause of the issue is well understood. When the IC2 master is reset during a transmission the I2C slave device hangs in its current state waiting for the next SCL. When this state holds the SDA line low, the bus is detected as busy. When the master comes out of reset it can detect this condition by reading the SDA line as a GPIO and checking it for low, or calling the I2CMasterBusy() function. 

    In a system where all the I2C slaves have a reset input pin, this condition can be avoided by making sure the I2C slaves are reset when the I2C master (microcontroller) is reset. I2C slave devices with low pin count may not have a reset input (like the ADS1110). In this case, the workaround described above can be used.

  • Bob,

    Bob Crosby said:
    When the IC2 master is reset during a transmission the I2C slave device hangs in its current state

    Thank you for addressing this issue.    However - where has it been stated that the 'I2C Master' (i.e. the only MCU on this I2C bus) has been, 'Reset during an I2C transmission?"    Neither my (limited) staff (school has reclaimed many) nor I find 'any' evidence of such an occurrence!     And that's a key/critical point - is it not? 

    Now if the I2C transactions were at (both) a 'High & Sustained Rate' - maybe then - the MCU's Reset (could) possibly occur during an ongoing transmission (actually transaction).  Yet - there is, 'No factual evidence - at all - in support of such (High Rate/Sustained I2C Transactions!')

    In addition - our poster would have to make a special effort to achieve such a condition (i.e. deliberately 'Resetting the MCU - WHILE an I2C transaction is on-going) - my group believes that proves 'unlikely' to have occurred.   Recall too - poster notes this 'hang' having occurred MULTIPLE TIMES - unless his MCU Reset circuit is 'extremely flawed' - the "MCU Reset DURING AN I2C XMSN" as 'Issue Trigger'   registers as  'far-fetched' in this specific case!"

    Further - the use of the 'I2CMasterBusBusy()' function remains 'improper' (has been so from the 'Get-Go') - for such a 'Single MCU/Master system' - which IS poster's reality.   (and while pointedly 'avoided' - continues to disturb!)

    Indeed 'your' special effort in investigating the (usually) 'Required number of SCL clocks' to 'release the bus' proves informative & helpful.   Yet - college student staff &  I 'continue' in the belief that the 'discovery of the most likely CAUSE of the Slave's discomfort' - remains 'unknown' - and  ZERO Investigative Pursuits have been launched.    (None here believe that's 'best practice' - and clearly deserves (some) time & effort!)   

    It would appear that, 'Simply joining the MCU's Reset to that of the ADC (assuming like voltage levels) would serve to 'Self-Clear' the ADC!    (should it have become disturbed/distressed.)   In addition - adequate 'Passage of Time' must be insured - prior to any transaction between the MCU and Addressed Peripheral - immediately post an MCU Reset.    It is believed that 'this discipline' - and the removal of the (improper) 'I2CMasterBusBusy()' - provide (both) a Broad & REAL SOLUTION - and (likely) eliminates (at least greatly reduces) the requirement for the 'Barrage of SCL Clocks!'

    From 'long-term' - sometimes painful experience - I believe that a 'more likely' CAUSE of such 'I2C hang' may be:

    "Unwanted/Illegal impulses' - directly coupled or induced into/upon the SCL signal line!"    Such would cause the 'MCU-Slave's' following (or ongoing) transaction to become 'Out of Sync' - likely triggering the Slave's 'Hang of the bus.'    Excessive I2C signal length, poor pcb layout, noise sources placed too close to (especially) the SCL signal trace and use of 'too high value pull-up resistors' (i.e. those internal to the MCU (from ANY vendor) - any/all of the above are, 'Proven, Likely suspects!'    

    Perhaps the 'extra level of probing' - modeled here - better illustrates the, 'identification of an Issue's 'Most Likely Cause' - and stemming from that insight - the development of a superior & far more focused - Solution!

  • Dear cb1,

    Thank you for your reply and efforts in trying to identify the problem. Also Bob Crosby, thank you for the clarification. I can confirm that the issue occurs very rarely, and I have noticed it purely by chance when repeatedly downloading my application onto the controller and entering debugging mode. So indeed, as you mentioned, that might have caused the unwanted/illegal impulses induced on the SCL line. I'm sure that during normal use, the issue is very unlikely to happen (assuming the remainder of the circuitry - which I'm not responsible for - works well). However, since I will be passing my project on to another engineering group (this is purely an internal project), who simply need it work and are not familiar with the specifics of the application, I don't want them to experience any unexpected problems (for example, a situation where they have to manually restart the device).

    Given the fact that I'm almost completely new to embedded programming and this is my first project at this workplace, for now I'm happy with this workaround - even if unnecessary, it has proven to work in those rare events. Perhaps, given more time to investigate the issue in the future, I might abandon the use of I2CMasterBusBusy() all together; however for now it has proven useful. If you have any additional insights into the problem, I will be glad to take them into account.

    Best regards.

    Ksawery

  • Thank you - your thoughtful response is appreciated.

    As one active here - first when the forum was owned/run by 'Luminary Micro Systems' (i.e. Stellaris creators) and extending now beyond 10 years - AND w/25+ years of 'Tech-Wars' (to include co-founding - taking that past Tech Firm Public) - 'some' lessons (may) have been learned.    And - it is hoped - that much of the knowledge, methods/(madness?) gleaned - may serve others - even here!

    Little left to add - yet these items (likely) demand consideration:

    • Any high performance, discrete ADC most always 'requires' a well designed pcb.   Breadboards almost 'guarantee' failure - most discrete (performance) ADCs are available upon Eval Boards - always a wise choice.
    • When 'wiring or cabling' between MCU & ADC boards - the 2 I2C signal connections should be (both) Short & as Direct as possible.   If high frequency signals, high currents (usually > 5A), or (other) noise sources are present - those I2C connections should 'maximize separation.'     
    • Should the above (wire/cable) guidance fail - it may prove useful to deploy a 'shielded cable' - especially for the (more vulnerable) SCL signal.   Begin by grounding the cable's shield to the ADC's ground - do not (initially) ground the MCU end of the cable.
    • Inadequate power - especially under high data rates - must always be (properly) suspected.
    • As noted (post prior) by tying (both) MCU & ADC's Reset Pins (assuming both prove compatible) the ability of an MCU's Reset to 'distress/disrupt' - is substantially lessened.   In addition - always allow adequate time for (any) MCU Peripheral to recover from reset - and become ready.   Vendor's API provides an 'exact function' which enables the MCU to confirm the peripheral's 'readiness.'

    You are silent as regards the 'point' (just above) - 'the joining of the MCU's & ADC's Reset lines' - as/if appropriate.   Multiple 'Verifies' have been awarded - yet this (believed) superior suggestion - appears to have 'escaped your notice' - may we ask why?

    Any serious 'Design Review' will detect the (improper) presence of the 'Multi-Master' I2C function - this cannot prove to your advantage - I don't know (how better) to (again) make this point...

  • Mr Cb1 and Mr Bob, You are so great, my idols, I completed my contest and  is  studying your reply now.

  • Thank you, Mr. Wang.   That's true for 'Mr. Bob' - not so much for this (simple) reporter.

    I will direct your kind writing to my parole officer - note that (both) a (past) Illinois Governor & 'cb1' -  hope for 'early release.'

    You may wish to 'PM' me as my time here is highly limited - 'going where one is 'appreciated' proves a superior choice...'

  • Dear Cb1,

          You know my english is not very well,but i can feel something ,Do you feel okay?

          Bless you.