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

Thread: i2c_t3 basic example returns FAIL

  1. #1
    Junior Member
    Join Date
    Dec 2018
    Location
    UK
    Posts
    9

    i2c_t3 basic example returns FAIL

    Trying to run the basic_master_callback (on Teensy 3.6) and basic_slave (on Teensy LC) examples from the Teensy i2c_t3 library, in an attempt to help myself understand several other i2c communication problems I am having, just seems to lead to more problems!

    My setup is shown in the picture, and the code used is mentioned above. The Serial monitor returns the following on repeat, forever increasing the same error counter and data message:

    Sending to Slave: 'Data Message #0' Reading from Slave:
    FAIL - Cannot acquire bus, possible stuck SDA/SCL

    I2C_ERRCNT_RESET_BUS: 0
    I2C_ERRCNT_TIMEOUT: 0
    I2C_ERRCNT_ADDR_NAK: 0
    I2C_ERRCNT_DATA_NAK: 0
    I2C_ERRCNT_ARBL: 0
    I2C_ERRCNT_NOT_ACQ: 1
    I2C_ERRCNT_DMA_ERR: 0
    Sending to Slave: 'Data Message #1' Reading from Slave:
    FAIL - Cannot acquire bus, possible stuck SDA/SCL

    I2C_ERRCNT_RESET_BUS: 0
    I2C_ERRCNT_TIMEOUT: 0
    I2C_ERRCNT_ADDR_NAK: 0
    I2C_ERRCNT_DATA_NAK: 0
    I2C_ERRCNT_ARBL: 0
    I2C_ERRCNT_NOT_ACQ: 2
    I2C_ERRCNT_DMA_ERR: 0

    Any ideas what I might be doing wrong?
    Any help is much appreciated!

    Additional information:
    I successfully found a current sensor using the basic_scanner example, but could not detect the Teensy LC in the same situation with basic_slave code on the device. Is it possible I was also doing something else wrong here?
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	i2c_t3 Setup.jpg 
Views:	17 
Size:	46.2 KB 
ID:	15491  

  2. #2
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,306
    From your picture, it looks like the pull-up resistors are on the wrong pins (it looks like you have attached the resistors to pins 24, 25, an 26). They should be on the same pins as SDA/SCL. Even though you have two teensys on the breadboard, you only need one set of pullup-resistors (i.e. you need the pull-up resistors somewhere on the bus).

    In addition to the resistors being on the wrong pins, it looks like you have wired them as pull-down pins (pull-up pins go between the data pin and 3.3v, pull-down pins go between the data pin and ground).

    Finally from the marking on the resistors, they are probably not strong enough. In the past, Paul has said 2.2K resistors are what a 3.3v system needs, and it looks like you only have 2K resistors. You can go to higher resistors, and it will work, though much higher, and it will degrade the max speed that the i2c bus can run at. The 2.2K resistor is more of a guideline for simple 3.3v i2c buses. If you have a longer or more complicated i2c bus, you will likely need to calculate what level of resistors to use.

  3. #3
    Junior Member
    Join Date
    Dec 2018
    Location
    UK
    Posts
    9
    The pull-down resistors are on pins 10, 11 and 12, I placed them there as the software below requires, to receive different parts of information. (This actually took me ages to figure out as I haven't done much to do with pull-up/down resistor stuff!)

    I would have thought 2k ohms was close enough to 2.2k ohms to do the job, particularly as the pull down resistors in this case are only to pull down the data line for the purposes of the software, but as you say I just need to pass the boundary of 2.2k ohms? (but I'll swap them for some 2.2k ones anyway)

    I wondered if I could get away with using the internal pull ups for the Teensy 3.6, but I read somewhere that there may be a hardware bug? So will I need a pull up resistor on each of the SDA and SCL lines at a value of 2.2k?
    If there really is a hardware bug then for the Teensy 3.6, should I always use 2.2k pull-ups on the I2C lines?

    Thanks for your help!


    This is the code from the examples:

    Basic_Master_Callback.ino

    Code:
    // -------------------------------------------------------------------------------------------
    // Basic Master Callback
    // -------------------------------------------------------------------------------------------
    //
    // This creates a simple I2C Master device which when triggered will send/receive a text
    // string to/from a Slave device.  It is intended to pair with a Slave device running the
    // basic_slave sketch.  
    //
    // Functionally this sketch is similar to the basic_master sketch, except for three things:
    // 1) It uses callbacks to handle the results and errors, instead of explicitly coding such
    //    routines after each send/receive call.
    // 2) It can optionally demonstrate background transfers by setting the NONBLOCKING flag (from
    //    external observation these transfers will appear similar, but the LED duration will
    //    be shorter as they exit immediately after initiating the transfer).
    // 3) There is an added test to dump error diagnostics from the error counting system.
    //
    // Pull pin12 input low to send.
    // Pull pin11 input low to receive.
    // Pull pin10 input low to dump error diagnostics.
    //
    // This example code is in the public domain.
    //
    // -------------------------------------------------------------------------------------------
    
    #include <i2c_t3.h>
    
    // Memory
    #define MEM_LEN 256
    char databuf[MEM_LEN];
    int count;
    
    #define NONBLOCKING
    
    void setup()
    {
        pinMode(LED_BUILTIN,OUTPUT);    // LED
        digitalWrite(LED_BUILTIN,LOW);  // LED off
        pinMode(12,INPUT_PULLUP);       // Control for Send
        pinMode(11,INPUT_PULLUP);       // Control for Receive
        pinMode(10,INPUT_PULLUP);       // Control for Diagnostics
    
        // Setup for Master mode, pins 18/19, external pullups, 400kHz, 50ms default timeout
        Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
        Wire.setDefaultTimeout(50000); // 50ms
    
        // Data init
        memset(databuf, 0, sizeof(databuf));
        count = 0;
    
        Serial.begin(115200);
    
        Wire.onTransmitDone(transmitDone);
        Wire.onReqFromDone(requestDone);
        Wire.onError(errorEvent);
    }
    
    void loop()
    {
        uint8_t target = 0x66; // target Slave address
    
        // Send string to Slave
        //
        if(digitalRead(12) == LOW)
        {
            digitalWrite(LED_BUILTIN,HIGH);   // LED on
    
            // Construct data message
            sprintf(databuf, "Data Message #%d", count++);
    
            // Print message
            Serial.printf("Sending to Slave: '%s' ", databuf);
    
            // Transmit to Slave
            Wire.beginTransmission(target);   // Slave address
            Wire.write(databuf,strlen(databuf)+1); // Write string to I2C Tx buffer (incl. string null at end)
            #if defined(NONBLOCKING)
                Wire.sendTransmission();          // Transmit to Slave, non-blocking
            #else
                Wire.endTransmission();           // Transmit to Slave, blocking
            #endif
    
            // After send complete, callback will print result
    
            digitalWrite(LED_BUILTIN,LOW);    // LED off
            delay(100);                       // 100ms delay
        }
    
        // Read string from Slave
        //
        if(digitalRead(11) == LOW)
        {
            digitalWrite(LED_BUILTIN,HIGH);   // LED on
    
            // Print message
            Serial.print("Reading from Slave: ");
    
            // Read from Slave
            #if defined(NONBLOCKING)
                Wire.sendRequest(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer), non-blocking
            #else
                Wire.requestFrom(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer), blocking
            #endif
    
            // After request complete, callback will print result
    
            digitalWrite(LED_BUILTIN,LOW);    // LED off
            delay(100);                       // 100ms delay
        }
    
        // Diagnostics - print error count summary
        //
        if(digitalRead(10) == LOW)
        {
            digitalWrite(LED_BUILTIN,HIGH);   // LED on
    
            // Print errors
            Serial.print("\n");
            Serial.printf("I2C_ERRCNT_RESET_BUS: %d\n", Wire.getErrorCount(I2C_ERRCNT_RESET_BUS));
            Serial.printf("I2C_ERRCNT_TIMEOUT:   %d\n", Wire.getErrorCount(I2C_ERRCNT_TIMEOUT));
            Serial.printf("I2C_ERRCNT_ADDR_NAK:  %d\n", Wire.getErrorCount(I2C_ERRCNT_ADDR_NAK));
            Serial.printf("I2C_ERRCNT_DATA_NAK:  %d\n", Wire.getErrorCount(I2C_ERRCNT_DATA_NAK));
            Serial.printf("I2C_ERRCNT_ARBL:      %d\n", Wire.getErrorCount(I2C_ERRCNT_ARBL));
            Serial.printf("I2C_ERRCNT_NOT_ACQ:   %d\n", Wire.getErrorCount(I2C_ERRCNT_NOT_ACQ));
            Serial.printf("I2C_ERRCNT_DMA_ERR:   %d\n", Wire.getErrorCount(I2C_ERRCNT_DMA_ERR));
    
            // uncomment to zero all errors after dumping
            //for(uint8_t i=0; i < I2C_ERRCNT_DMA_ERR; i++) Wire.zeroErrorCount((i2c_err_count)i);
    
            digitalWrite(LED_BUILTIN,LOW);    // LED off
            delay(100);                       // 100ms delay
        }
    }
    
    //
    // Trigger after Tx complete (outgoing I2C data)
    //
    void transmitDone(void)
    {
        Serial.print("OK\n");
    }
    
    //
    // Trigger after Rx complete (incoming I2C data)
    //
    void requestDone(void)
    {
        Wire.read(databuf, Wire.available());
        Serial.printf("'%s' OK\n",databuf);
    }
    
    //
    // Trigger on I2C Error
    //
    void errorEvent(void)
    {
        Serial.print("FAIL - ");
        switch(Wire.status())
        {
        case I2C_TIMEOUT:  Serial.print("I2C timeout\n"); Wire.resetBus(); break;
        case I2C_ADDR_NAK: Serial.print("Slave addr not acknowledged\n"); break;
        case I2C_DATA_NAK: Serial.print("Slave data not acknowledged\n"); break;
        case I2C_ARB_LOST: Serial.print("Arbitration Lost, possible pullup problem\n"); Wire.resetBus(); break;
        case I2C_BUF_OVF:  Serial.print("I2C buffer overflow\n"); break;
        case I2C_NOT_ACQ:  Serial.print("Cannot acquire bus, possible stuck SDA/SCL\n"); Wire.resetBus(); break;
        case I2C_DMA_ERR:  Serial.print("DMA Error\n"); break;
        default:           break;
        }
    }
    Basic_Slave.ino

    Code:
    // -------------------------------------------------------------------------------------------
    // Basic Slave
    // -------------------------------------------------------------------------------------------
    //
    // This creates a simple I2C Slave device which will print whatever text string is sent to it.
    // It will retain the text string in memory and will send it back to a Master device if 
    // requested.  It is intended to pair with a Master device running the basic_master sketch.
    //
    // This example code is in the public domain.
    //
    // -------------------------------------------------------------------------------------------
    
    #include <i2c_t3.h>
    
    // Function prototypes
    void receiveEvent(size_t count);
    void requestEvent(void);
    
    // Memory
    #define MEM_LEN 256
    char databuf[MEM_LEN];
    volatile uint8_t received;
    
    //
    // Setup
    //
    void setup()
    {
        pinMode(LED_BUILTIN,OUTPUT); // LED
    
        // Setup for Slave mode, address 0x66, pins 18/19, external pullups, 400kHz
        Wire.begin(I2C_SLAVE, 0x66, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
    
        // Data init
        received = 0;
        memset(databuf, 0, sizeof(databuf));
    
        // register events
        Wire.onReceive(receiveEvent);
        Wire.onRequest(requestEvent);
    
        Serial.begin(115200);
    }
    
    void loop()
    {
        // print received data - this is done in main loop to keep time spent in I2C ISR to minimum
        if(received)
        {
            digitalWrite(LED_BUILTIN,HIGH);
            Serial.printf("Slave received: '%s'\n", databuf);
            received = 0;
            digitalWrite(LED_BUILTIN,LOW);
        }
    }
    
    //
    // handle Rx Event (incoming I2C data)
    //
    void receiveEvent(size_t count)
    {
        Wire.read(databuf, count);  // copy Rx data to databuf
        received = count;           // set received flag to count, this triggers print in main loop
    }
    
    //
    // handle Tx Event (outgoing I2C data)
    //
    void requestEvent(void)
    {
        Wire.write(databuf, MEM_LEN); // fill Tx buffer (send full mem)
    }

  4. #4
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,306
    Quote Originally Posted by JBrownlow View Post
    I would have thought 2k ohms was close enough to 2.2k ohms to do the job, particularly as the pull down resistors in this case are only to pull down the data line for the purposes of the software, but as you say I just need to pass the boundary of 2.2k ohms? (but I'll swap them for some 2.2k ones anyway)

    I wondered if I could get away with using the internal pull ups for the Teensy 3.6, but I read somewhere that there may be a hardware bug? So will I need a pull up resistor on each of the SDA and SCL lines at a value of 2.2k?
    If there really is a hardware bug then for the Teensy 3.6, should I always use 2.2k pull-ups on the I2C lines?
    As I understand it, ARM processors internal pull-ups are just not strong enough, so you need a set of pull-ups on the SCL/SDA lines. I.e., it is not a 'bug', but a 'feature'. I was looking through some Adafruit Feather machines for their M0, M4, and ESP32 feathers and they have similar wording that you may need pullups:

  5. #5
    Junior Member
    Join Date
    Dec 2018
    Location
    UK
    Posts
    9
    On this page scoll down to the Pullups section on the readme file, this is where I read it, but HW bug did sound like the incorrect terminology to me! https://github.com/nox771/i2c_t3

    Adding the pull ups seems to have fixed my issue! Thanks a lot.

    The reason I thought I could get it working without pull-ups was because in the readme file linked above it said this should still work for a single device on i2c when I2C_PULLUP_INT is used in the line below, instead of I2C_PULLUP_EXT:

    Code:
    Wire.begin(I2C_SLAVE, 0x66, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);

  6. #6
    Junior Member
    Join Date
    Dec 2018
    Location
    UK
    Posts
    9
    Interestingly I can only make it work using external pull-ups and I only get errors using any other method with internal pull-ups.

    I'm happy enough that this is resolved!

  7. #7
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,306
    Quote Originally Posted by JBrownlow View Post
    On this page scoll down to the Pullups section on the readme file, this is where I read it, but HW bug did sound like the incorrect terminology to me! https://github.com/nox771/i2c_t3

    Adding the pull ups seems to have fixed my issue! Thanks a lot.

    The reason I thought I could get it working without pull-ups was because in the readme file linked above it said this should still work for a single device on i2c when I2C_PULLUP_INT is used in the line below, instead of I2C_PULLUP_EXT:

    Code:
    Wire.begin(I2C_SLAVE, 0x66, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
    I would imagine that README file was written when the author was using a AVR processor (like an Arduino Uno) where internal pull-ups do work. I wish there was a solder jumper on the ARM machines that you could enable a pull-up resistor without having to wire it up.

Posting Permissions

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