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

Thread: i2c communication (400 kHz) between teensy and arduino - delay required

  1. #1
    Junior Member
    Join Date
    Mar 2015
    Posts
    17

    i2c communication (400 kHz) between teensy and arduino - delay required

    Hi,

    I have a teensy 3.2 connected to an arduino mega via i2c, pullups 3.9 k to 5 V. The teensy is the master, the arduino the slave.

    The communication is working fine with the standard i2c speed (100 kHz). However, if I change it to 400 kHz, then the onRequest handler of the arduino is never called. After many hours, I found out that if I add a tiny delay between sending data to the arduino and requesting data from the arduino, it works.

    Here is a "minimum working example" that reproduces the behavior.
    Teensy code:
    Code:
    #include <i2c_t3.h>
    
    void setup() {
      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
      Wire.onReceive(receiveEvent);
    }
    
    void receiveEvent(unsigned int howMany) {
      char cmd = Wire.read();
      // toy code ...
    }
    
    void loop() {
      Wire.beginTransmission(1); 
      Wire.write('S');
      Wire.endTransmission();
      delayMicroseconds(3); // 3 microseconds seems to be the minimum number, for 2 it stops working
      Wire.requestFrom(1, 1);
    
      delay(1000);
      Wire.beginTransmission(1); 
      Wire.write('D');
      Wire.endTransmission();
      delayMicroseconds(3); // 3 microseconds seems to be the minimum number, for 2 it stops working
      Wire.requestFrom(1, 1);
      
      delay(1000);
    }
    Arduino:
    Code:
    #include <Wire.h>
    
    #define CSPin 2
    
    bool mode;
    
    void setup() {
      pinMode(CSPin, OUTPUT);
      digitalWrite(CSPin, HIGH);
      Wire.begin(1);          
      Wire.onReceive(receiveEvent);
      Wire.onRequest(requestEvent);
      mode = false;
    }
    
    void loop() {}
    
    void receiveEvent(int howMany) {
      char cmd = Wire.read();
      if(cmd == 'S') {
        mode = true;
      } else {
        mode = false;
      }
    }
    
    void requestEvent() {
      if(mode) {
        digitalWrite(CSPin, LOW);
      } else {
        digitalWrite(CSPin, HIGH);
      }
      Wire.write('K');
    }

    While I can live with that delay, I want to understand why it does not work without.
    Can someone explain that behavior?

  2. #2
    Senior Member
    Join Date
    May 2017
    Posts
    202
    I don't have an answer. I do find it interesting that at 400khz, one bit time is 2.5 us. So it appears you need to wait longer than one bit time although that could be a coincidence.

  3. #3
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,385
    I'd guess that the Arduino Mega is so horribly slow, compared to the Teensy 3.2, that it is still processing the incoming 'S' or 'D' after reception and will be badly surprised when your requestFrom() arrives already from the Teensy while the Mega is still occupied with the handling of receiveEvent(). You might narrow this down by driving le Mega's Led high while receiveEvent() is running and low when it's ready. Then, you might probably see with a logic analyzer that receiveEvent is still running when you send the request.

    Another guess is that the bool mode should be declared volatile to prevent conflicts.

  4. #4
    Junior Member
    Join Date
    Mar 2015
    Posts
    17
    thanks for your answers!

    In my understanding of i2c (correct me if I am wrong), the arduino should stretch the i2c clock until its "receiveEvent" handler has finished. So in theory the teensy should wait until the receiveEvent() code is finished.

    I will try later this day to connect two teensy and also two arduinos to check whether this just affects the specific teensy arduino combination.

    Declaring the bool mode as volatile seems to make sense since receiveEvent() is called in an interrupt, however, I guess it should not cause this issue here. I will try anyway, thanks!

  5. #5
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,385
    Quote Originally Posted by cinhcet View Post
    In my understanding of i2c (correct me if I am wrong), the arduino should stretch the i2c clock until its "receiveEvent" handler has finished. So in theory the teensy should wait until the receiveEvent() code is finished.
    I haven't looked closer to the source code of the Wire library for Arduino, but I guess they did everything to make the stuff non blocking on these old, slow, and asthmatic MCUs...
    Quote Originally Posted by cinhcet View Post
    Declaring the bool mode as volatile seems to make sense since receiveEvent() is called in an interrupt, however, I guess it should not cause this issue here. I will try anyway, thanks!.
    Don't guess... modern versions of the gcc compiler tend sometimes to exaggerate and to do too much cleaning.

Posting Permissions

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