Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: Teensy 3.2 in I2C slave mode - Some times SCL stay low

  1. #1
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13

    Teensy 3.2 in I2C slave mode - Some times SCL stay low

    Dear all

    Since few days (and weeks) I try to managed by myself with an I2C issue, but I now freezed.
    I made an 5V I2C network with one master and many slaves : some PCF8574 devices and one Teensy 3.2.
    I used for Teensy:
    - i2c_t3 - I2C library for Teensy 3.x & LC - (v11.0) Modified 01Dec18 by Brian (nox771 at gmail.com)
    - a I2C level translator, a PCA9517 with 2.2k pull-up resistors on 3.3V side

    All works fine, except that at least once by day, the SCL line stay low. After investigation, I realised that the SCL low is due to the Teensy.
    Jumpers on my Teensy's "mother board" allow me to disconnect SDA et SCL of the Teensy to the I2C network.
    So, when I disconnect Teensy's SCL of the rest of the network, other I2C re-works, but freeze when I reconnect it.
    The only solution was to manualy restart the Teensy (power off and after on).

    I have two questions :
    1- In a slave mode, what are the reasons for the Teensy act on SCL line?
    2- The more importante, because it could happen : How, can I automatically maneged the "I2C module" restart?

    Many thanks in advance for your ideas

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,770
    This note is in the i2c_t3.h file:
    // ------------------------------------------------------------------------------------------------------
    // Auto retry - uncomment to make the library automatically call resetBus() if it has a timeout while
    // trying to send a START (occurs at the beginning of any endTransmission() or requestFrom()
    // call). This will toggle SCL to try and get a hung Slave device to release the SDA line.
    // If successful then it will try again to send a START, if not then it will return a timeout
    // error (same as if auto retry was not defined).
    //
    // Note: this is incompatible with multi-master buses, only use in single-master configurations
    //
    //#define I2C_AUTO_RETRY
    This seems like it is worth trying as the code triggers for SLAVE usage for a single Master bus:
    #if defined(I2C_AUTO_RETRY)
    // if not master and auto-retry set, then reset bus and try one last time
    Not sure if it will help. what bus speed is in use? Are those level translators up to that speed?

  3. #3
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13
    Also, after the finding of this issue, I begining to investigate in detail and made many test.
    First of all I read the K20 microcontroller's datasheet.
    And especially chapter 46 - Inter-Integrated Circuit (I2C) page 1169

    • SBRC bit : I realised that in slave mode the i2c_t3 library don't setting the SBRC bit (Slave Baut Rate Control) of Control Register 2 (I2Cx_C2) that can allow the slave to strech the clock and in this fact to put SCL low (page 1178)
      -->so, I made modifications
      - in "kinetis.h" :
      Code:
      #define I2C_C2_SBRC			((uint8_t)0x10)			// Slave Baud Rate Control
      - in ""i2c_t3.cpp" function i2c_t3::begin_ :
      Code:
              *(i2c->C2) = (address2) ? (I2C_C2_HDRS|I2C_C2_RMEN|I2C_C2_SBRC) // Set high drive select and range-match enable			
                                      : (I2C_C2_HDRS|I2C_C2_SBRC);              // Set high drive select
      --> but no effect on the issue
    • SCL Low Timeout Flag : I tried a way to catch the SCL low event. I'm lucky there a Timeout interrupt for that : bit SLTF of I2Cx_SMB register (page 1181). Behavior descibed on pages 1191 and 1194
      --> I made
      - setting on I2Cx_SLTH and I2Cx_SLTL on my setup() function
      Code:
      	l_Temp =  F_BUS / 100;
      	l_Temp = l_Temp  * TIMEOUT_I2C_SCL_LOW;
      	l_Temp = l_Temp / (64 * 10000);							//divider of /64 cause of TCKSEL = 0 of register I2C0_SMB
      	byte_Temp = (l_Temp >> 16) & 0xFF;
      	I2C0_SLTH = byte_Temp;
      	byte_Temp = l_Temp & 0xFF;
      	I2C0_SLTL = byte_Temp;
      - modifications in ""i2c_t3.cpp" function i2c_isr_handler :
      Code:
              //
              // Slave Mode
              //
      
          	if ((*(i2c->SMB) & I2C_SMB_SLTF) == I2C_SMB_SLTF)				
          	{	*(i2c->SMB) = I2C_SMB_SLTF;									// clearle flag
          		i2c->ui_NbInterruptTimeoutSCL = i2c->ui_NbInterruptTimeoutSCL + 1;
          		if (i2c->b_FlagTimeoutSCL == false)							        // to take account the first timeout of a serie of timeout
          		{	i2c->ui_NbFlagInterruptTimeoutSCL = i2c->ui_NbFlagInterruptTimeoutSCL + 1;
          			i2c->b_FlagTimeoutSCL = true; }
          	}
      b_FlagTimeoutSCL is clear in my program each time I received an I2C message
      --> so, this "trap" works fine but I have to add a reset I2C or something that release the SCL line.


    By the way, there is something I don't understand well. When you read the spec :

    page 1191 - When the I2C module is a slave, if it detects the TTIMEOUT,MIN condition, it resets its communication and is then able to receive a new START condition.
    page 1194 - The SLTF bit must be cleared by software by writing 1 to it in the interrupt routine. You can determine the interrupt type by reading the Status Register.
    page 1199 - Figure 46-43. Typical I2C SMBus interrupt routine

    Nothing said that the user have to reset by software the I2C module...
    I probably miss something

    Any way, thanks having take time to read me, and of course to nox771 of the library

  4. #4
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,770
    Code noted above when enabled does resetBus_(i2c,bus); in only this case.
    Code:
            #if defined(I2C_AUTO_RETRY)
                // if not master and auto-retry set, then reset bus and try one last time
                if(!(*(i2c->C1) & I2C_C1_MST))
                {
                    resetBus_(i2c,bus);

  5. #5
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13
    @defragster : thanks for your time, and ideas

    My I2C network runs at 100kHz
    Code:
    	Wire.begin(I2C_SLAVE, adresse_I2C_TEENSY, I2C_PINS_18_19, I2C_PULLUP_EXT, 100000);				// Setup for Slave mode, address 0x66, pins 18/19, external pullups, 100kHz
    	Wire.setDefaultTimeout (3000);
    Concerning the #define I2C_AUTO_RETRY, I'm a little bit confused of its usage.
    For me, that mades a reset of the bus, when the device is a master, to force a "wrong' slave device to release SDA line.
    But this reset function is call only when your device is a slave (!I2C_C1_MST)...

  6. #6
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,770
    ... Just browsing the code … as I understood there to be a resetBus() in that library.

    The original post says : Teensy 3.2 in I2C slave mode

    That code is only active - when the #define is enabled and then when the i2c object is Not { ! } in Master mode as I read it: if(!(*(i2c->C1) & I2C_C1_MST))

    That agreed with the comments in the code as well.

    If the problem is reproducible it will be easy to tell if it helps by uncommenting this in the .h file :: //#define I2C_AUTO_RETRY

    And perhaps adding a digitalWriteFast( LED_BUILTIN, !(digitalReadFast( LED_BUILTIN )) ); in that code to a pin you can monitor for the execution of that code when it would do the reset and hopefully see the bus stay active..

  7. #7
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13
    I will uncomment this line and made test, and also use the Build-in Led to check.

    But for me there is something strange with that way of reset.
    Because, for me, in a slave mode an I2C device don't have to sent START, or toggles SCL line to force other I2C devices to relaese bus.
    And also the function i2c_t3::acquireBus_ in which the resetBus_(i2c,bus) function is, is only call in "master" functions.

    Any way, I will made test and put GND on SCL to by sure.

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,770
    Interested to hear the results - it is there for a reason. And it reads like it may involve the issue as reported - AFAIK. I did look at some part of this code some time ago - but only to replicate other parts - never actual details.

    It seems the master cycle would only trigger in a specific case, so that may not happen if anything.

    Might just try taking the LED always LOW at setup() and just setting it HIGH at first - to see it ON - of course as provided above it will toggle the LED on each instance.

    100 KHz isn't the fastest for sure - not sure what the level shift parts used are reliably capable of.

  9. #9
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13
    @defragster : thank again for our discussion, even if my issue isn't solve, it make me feel not alone

    Well, I did test as described below :
    • uncomment ligne #define I2C_AUTO_RETRY
    • put ligne digitalWriteFast( LED_BUILTIN, true); after resetBus_(i2c,bus); in i2c_t3.cpp
    • put ligne digitalWriteFast( LED_BUILTIN, false); in the message received fonction
    • configure the teensy as an slave I2C
    • make a short circuit between GND and SCL


    An unfortnately, as I think, nothing happens...

    But if I put the code

    Code:
        	if ((*(i2c->SMB) & I2C_SMB_SLTF) == I2C_SMB_SLTF)				
        	{	*(i2c->SMB) = I2C_SMB_SLTF;									// earse  flag
                  digitalWriteFast( LED_BUILTIN, true);
        	}
    juste after the code
    Code:
        else
        {
            //
            // Slave Mode
            //
    inside function
    Code:
    void i2c_isr_handler(struct i2cStruct* i2c, uint8_t bus)
    the led switch on when I made the short circuit

    My question is, that I probably not be alone to encounter the issue. How can I properly reset the I2C module, and is it normal do want do that?
    I know that for MEGA 2560 there is a simple way to achieved that
    Code:
    	TWCR = 0; //releases SDA and SCL lines to high impedance
    	TWCR = _BV(TWEN) | _BV(TWEA); //reinitialize TWI

  10. #10
    Senior Member
    Join Date
    Apr 2019
    Posts
    143
    A really simple solution is to put the teensy on a serial port and communicate that way, the teensy has many more ways of communicating other than i2c

  11. #11
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13
    Shame on me...
    Even if it didn't solve my problem, here is the correct setup of registers I2C0_SLTH and I2C0_SLTL
    Code:
    	l_TempTimeout =  F_BUS / 64;
    	l_TempTimeout = 1000000000  / l_TempTimeout; 													
    	l_TempTimeout = (TIMEOUT_I2C_SCL_LOW * 1000) / l_TempTimeout;									// /64 cause of TCKSEL = 0 of register I2C0_SMB
    	byte_Temp = (l_TempTimeout >> 8) & 0xFF;
    	I2C0_SLTH = byte_Temp;
    	byte_Temp = l_TempTimeout & 0xFF;
    	I2C0_SLTL = byte_Temp;

  12. #12
    Junior Member
    Join Date
    Mar 2019
    Location
    France
    Posts
    13
    Well, now I can detected and managed the SCL staying low with the registers I2C0_SLTH and I2C0_SLTL registers it seems that the I2C reset freeze the Teensy or have no effets.
    In this fact, I decied to rewrite all my programm and to check step by step when the disturbs happens.

    And then, I realize that the IntervalTimer is the key. I use IntervalTimer.h to time my main loop and this is the cause of my issue.
    I will investigate a little bit to find which Timer is use with IntervalTimer and why is incompatible with FTM2 of OCTOWS2811.

    I will open an other thread, to know how to use a timer to sequence the main loop with the OctoWS2811 library.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •