New I2C library for Teensy3

Cool, I like the addition of Wire or Wire1 access. I assume it works if you use both Wire & Wire1 concurrently, each with their own sensor. Have you tried it with 2?
 
I have a strange problem, which may not be related to the i2c_t3 library, but I hope someone reading this thread can help me.

The problem is that I get failed calls to endTransmission() and requestFrom() - but only after my code has been running for minutes or even hours. The typical pattern is that I get acknowledge fails periodically, but with increasing frequency. After some hours I finally get timeout on all endTransmission calls.

I am using a Teensy 3.2 and eight MCP23017 port expanders.

Any ideas how I2C can become increasingly unstable?
 
I have a strange problem, which may not be related to the i2c_t3 library, but I hope someone reading this thread can help me.

The problem is that I get failed calls to endTransmission() and requestFrom() - but only after my code has been running for minutes or even hours. The typical pattern is that I get acknowledge fails periodically, but with increasing frequency. After some hours I finally get timeout on all endTransmission calls.

I am using a Teensy 3.2 and eight MCP23017 port expanders.

Any ideas how I2C can become increasingly unstable?

It could be that some of the port expander slaves are dropping clocks and getting out-of-sync or stuck (they may not be getting stuck in a way that completely blocks the bus). Perhaps try pulling some slaves off the bus to see if it is a particular device, or try reducing the clock rate to see if you can improve the data integrity. If it is a noisy environment (bad supply/ground connections, no bypass caps, etc), that could also contribute to traffic errors.

If basic tweaks don't work then you'll need more detailed diagnosis and error codes to try and figure out why it's failing, eg:
  • always same device fails?
  • same error code?
  • MCP23017 has a reset line. If a fail occurs and you toggle the reset line, does it start working again?

I would start with the basic stuff, trying to clean up the signaling on the line and reducing speed if necessary. If a scope shows the signals are clean, then maybe check for bad connections or bad slave devices.

In theory START/STOP signals on the line are supposed to reset Slaves regardless of their state, but having seen the verilog that some people write for these interfaces, and having written interfaces myself I can tell you theory isn't always reality.
 
It could be that some of the port expander slaves are dropping clocks and getting out-of-sync or stuck (they may not be getting stuck in a way that completely blocks the bus). Perhaps try pulling some slaves off the bus to see if it is a particular device, or try reducing the clock rate to see if you can improve the data integrity. If it is a noisy environment (bad supply/ground connections, no bypass caps, etc), that could also contribute to traffic errors.

If basic tweaks don't work then you'll need more detailed diagnosis and error codes to try and figure out why it's failing, eg:
  • always same device fails?
  • same error code?
  • MCP23017 has a reset line. If a fail occurs and you toggle the reset line, does it start working again?

I would start with the basic stuff, trying to clean up the signaling on the line and reducing speed if necessary. If a scope shows the signals are clean, then maybe check for bad connections or bad slave devices.

In theory START/STOP signals on the line are supposed to reset Slaves regardless of their state, but having seen the verilog that some people write for these interfaces, and having written interfaces myself I can tell you theory isn't always reality.

Thanks for the suggestions. I have not had the chance to put a scope on the signal yet, but that would surely get me a better insight on what is going on.

The thing I don't understand is how the signal can become worse over time and eventually lock up the I2C bus completely. And what is even stranger is that resetting the Teensy actually resolves the lock-up.
 
Okay, here is what I found out so far:

1) Unplugging my slave-device seems to lock up the I2C bus in such a way that it cannot recover when I re-connect it.
2) endTransmission() returns I2C_TIMEOUT because i2c->currentStatus is still I2C_SENDING when finish_() is called.
3) Looking at my scope, the SCL and SDA pins are stuck in high state.
4) Calling resetBus() or begin() does not get I2C running again.

Any ideas what might cause this?
 
Is there a way to use a rate less than 100? I have a situation where the capacitance is high enough to disrupt the i2c even at 100. Unfortunately there's no way for me to reduce the capacitance so I just need to find a way to get this working. Thanks
 
Is there a way to use a rate less than 100? I have a situation where the capacitance is high enough to disrupt the i2c even at 100. Unfortunately there's no way for me to reduce the capacitance so I just need to find a way to get this working. Thanks

What pullup resistance are you using? I recall T3 has a very strong internal pullup of a few houndred ohms. Have you tried using that? In theory pullups under 1k should cope with line capacitance of up to about 1nF at 100kHz.
-Ben
 
recent thread noted the spec says 35K +/- 20+?% - - - something way too big to be usable - notes I've seen say use external resistors
 
Okay, here is what I found out so far:

1) Unplugging my slave-device seems to lock up the I2C bus in such a way that it cannot recover when I re-connect it.
2) endTransmission() returns I2C_TIMEOUT because i2c->currentStatus is still I2C_SENDING when finish_() is called.
3) Looking at my scope, the SCL and SDA pins are stuck in high state.
4) Calling resetBus() or begin() does not get I2C running again.

Any ideas what might cause this?

This is quite strange. Normally if the bus is stuck it is stuck low because some slave is holding a signal low. This plus your comment about resetting the T3 master making things work makes me wonder about the T3 device. Have you tried swapping in a different T3? I'll think about this but I'm really not sure what is going on.

One possibility might be something interfering with the interrupt being serviced. Have you tried running in immediate mode (non-interrupt), eg. using I2C_OP_MODE_IMM in the begin() call or by calling Wire.setOpMode(I2C_OP_MODE_IMM); (can add that line right after begin() when bus is idle). Check and see if that changes anything.
 
Is there a way to use a rate less than 100? I have a situation where the capacitance is high enough to disrupt the i2c even at 100. Unfortunately there's no way for me to reduce the capacitance so I just need to find a way to get this working. Thanks

There is a way to run at lower rates, but it is not builtin to the library, so it requires some low-level register adjustments. If you look in the setRate_() function there are lines like this:
Code:
        case I2C_RATE_100:  *(i2c->F) = 0x2C; break;   // 100k    576 (actual 104k)
        case I2C_RATE_200:  *(i2c->F) = 0x24; break;   // 200k    288 (actual 208k)
Those lines are setting the I2C divider ratio. You can adjust I2C0_F (or I2C1_F if you use Wire1), to alter the divide ratio.

If you look in the manual here:
http://pjrc.com/teensy/K20P64M72SF1RM.pdf

On page 1173 you will see the clockrate setting, and on pages 1187-1188 you will see the divider table. Basically knowing your bus freq, you pick a divide value to get you the rate you want and put that setting into I2C0_F. I would run the begin() call with the 100kHz rate setup, then modify the value directly:
Code:
I2C0_F = 0xYY;
where YY is your byte value determined from the table and register definition.
 
1) Unplugging my slave-device seems to lock up the I2C bus in such a way that it cannot recover when I re-connect it.
2) endTransmission() returns I2C_TIMEOUT because i2c->currentStatus is still I2C_SENDING when finish_() is called.
3) Looking at my scope, the SCL and SDA pins are stuck in high state.
4) Calling resetBus() or begin() does not get I2C running again.

I've been noticing a very similar behavior with a project I'm working on. I've noticed it during both un/re-plugging slave devices (occasionally, not always) as well as randomly occurring during normal operations (usually between 2 seconds to an hour after power-on), but only when I have more than about 4 slaves connected. Both SDA and SCL lines stay high, no output from the Teensy. The functions resetBus() and begin() have no effect, and don't transmit even when called multiple times in a error catching function. The only thing besides power-cycling that I've found to clear this situation is to manually pull SCL low briefly (manually with a jumper).

nox771 said:
Have you tried swapping in a different T3?

I've seen this with 3 different T3.2 units

nox771 said:
One possibility might be something interfering with the interrupt being serviced. Have you tried running in immediate mode (non-interrupt), eg. using I2C_OP_MODE_IMM in the begin() call or by calling Wire.setOpMode(I2C_OP_MODE_IMM); (can add that line right after begin() when bus is idle). Check and see if that changes anything.

I've tried running using I2C_OP_MODE_IMM and the entire Teensy then locks up.

I've been running the I2C at 100kHz, the T3.2 at 24MHz (optimized), have 2K2 pullups from the T3.2 3V3 output, and <200pF I2C bus. Scope traces of both SDA and SCL look clean. Besides i2c_t3 I'm also using 3 of the serial ports, one of which has 1Hz GPS NMEA coming into TinyGPS++, and TaskScheduler. Nothing that I know would have conflicting interrupts.

Note: I bumped the I2C rate up to 400kHz and haven't been able to duplicate the issue yet in the past hour. But with so little testing I don't want to claim that fixed it.

Edit: Forgot, the SPI library is also used for logging to an SD card.
 
Last edited:
I've been noticing a very similar behavior with a project I'm working on. I've noticed it during both un/re-plugging slave devices (occasionally, not always) as well as randomly occurring during normal operations (usually between 2 seconds to an hour after power-on), but only when I have more than about 4 slaves connected. Both SDA and SCL lines stay high, no output from the Teensy. The functions resetBus() and begin() have no effect, and don't transmit even when called multiple times in a error catching function. The only thing besides power-cycling that I've found to clear this situation is to manually pull SCL low briefly (manually with a jumper).

I've seen this with 3 different T3.2 units

I've tried running using I2C_OP_MODE_IMM and the entire Teensy then locks up.

This is all really strange. Slow-degredation could be caused by things like memory leaks on the software side, or temperature on the hardware side. I'm not sure about something like temp, but given the historical use of the library I think something like a memory leak would have shown up by now.

I think the common factor here is the heavy loading on the I2C bus. I'm wondering if the peripheral has trouble with slow-rise signals. I've worked on the hardware side of these interfaces before and there can be all manner of circuits used from very simple to excessively complex. Sometimes designers redesign everything and sometimes they use "off-the-shelf" blocks (either way could be potentially error prone). Even though I2C is only a 2 wire bus, there is an implicit conversion from analog to digital, and various methods of setting A/D switch points (eg. fixed ground referenced, mid-level based on input swing, mid-level based on supply, etc...). It's possible slow-rise signals are messing with the hardware side peripheral logic (given the rather poor state of the internal pullup design for I2C on these parts, this would not be surprising to me at all).

A suggestion I have would be to speedup the rise-time on the bus. Cut the pullup resistance way down to get the edge rates up and see if there is any effect. I'm really not sure what else might be going on, I'll think about it some more.
 
Can someone please give me a bit of guidance, as I am struggling to get this working correctly.

The plan is to have a TeensyLC driving some WS2812 LEDS, this will be connected to a Raspberry PI 3, which is hosting a web server and will allow me to change the LED sequence/colors. The idea was to use I2C to communicate between the TeensyLC and PI, with the PI as the master ans TeensyLC as the slave.

Everything works, until I add another I2C device and then things get weird. When I write to the other I2C device (in this example a Teensy3) I receive data on the TeensyLC. The sample code blow is supposed to send "Hello TeensyLC" followed by a random number. Here's what I get when I run it...

Code:
Hello TeensyLC571
Hello TeensyLC5711
Hello TeensyLC57111
Hello TeensyLC571111
Hello TeensyLC5711111
Hello TeensyLC57111111
Hello TeensyLC833
Hello TeensyLC8333
Hello TeensyLC83333
Hello TeensyLC833333
Hello TeensyLC8333333
Hello TeensyLC83333333
Hello TeensyLC474
Hello TeensyLC4744
Hello TeensyLC47444
Hello TeensyLC474444
Hello TeensyLC4744444
Hello TeensyLC986
Hello TeensyLC9866
Hello TeensyLC98666
Hello TeensyLC986666
Hello TeensyLC9866666
Hello TeensyLC98666666

Every time it writes to the Teensy3, I am getting a repeat of the TeensyLC data + the last character repeated. I am sure I am just being stupid and missing the obvious, so please put me out of my misery.

EDIT: I just hooked up the Teesny3 to another PC so I could debug it's output at the same time using the code below and it is printing as expected.


The Teesny3 is running the slave example code and the TeensyLC is running the slightly modified code below ...
Code:
#include <i2c_t3.h>

// Function prototypes
void receiveEvent(size_t len);

//
// 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, I2C_RATE_400);

    // register event
    Wire.onReceive(receiveEvent);

    Serial.begin(9600);
}

void loop()
{
    digitalWrite(LED_BUILTIN,HIGH); // double pulse LED while waiting for I2C requests
    delay(10);                      // if the LED stops the slave is probably stuck in an ISR
    digitalWrite(LED_BUILTIN,LOW);
    delay(100);
    digitalWrite(LED_BUILTIN,HIGH);
    delay(10);
    digitalWrite(LED_BUILTIN,LOW);
    delay(880);
}

//
// handle Rx Event (incoming I2C request/data)
//
void receiveEvent(size_t len)
{
    while(Wire.available())
    {
      char c = Wire.read();     // receive byte as a character
    }
    Serial.println();           // print newline
}

The PI is running Windows IoT and here's the code for it...
Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Devices.Enumeration;
using Rinsen.IoT.OneWire;
using Windows.Devices.I2c;
using System.Diagnostics;
using System.Threading;

namespace App1
{
    public sealed partial class MainPage : Page
    {
        // teensy vars
        private I2cDevice _teensyLC;
        private Timer _teensyLCTimer;
        private I2cDevice _teensy3;
        private Timer _teensy3Timer;

        public MainPage()
        {
            this.InitializeComponent();
            initTeensy();
        }

        private async void initTeensy()
        {
            var settings = new I2cConnectionSettings(0x66); // teensylc address
            settings.BusSpeed = I2cBusSpeed.FastMode;
            string aqs = I2cDevice.GetDeviceSelector("I2C1");
            var dis = await DeviceInformation.FindAllAsync(aqs);
            _teensyLC = await I2cDevice.FromIdAsync(dis[0].Id, settings);
            _teensyLCTimer = new Timer(this.TeensyLCTimerCallback, null, 0, 1000);
            // teensy 3
            settings = new I2cConnectionSettings(0x44); // teensy3 address
            settings.BusSpeed = I2cBusSpeed.FastMode;
            aqs = I2cDevice.GetDeviceSelector("I2C1");
            dis = await DeviceInformation.FindAllAsync(aqs);
            _teensy3 = await I2cDevice.FromIdAsync(dis[0].Id, settings);
            _teensy3Timer = new Timer(this.Teensy3TimerCallback, null, 0, 200);
        }

        private void TeensyLCTimerCallback(object state)
        {
            byte[] writeBuff = new byte[6];
            try
            {
                string msg = "Hello TeensyLC" + new Random().Next(999).ToString();
                byte[] sendBuff = new byte[msg.Length];
                sendBuff = System.Text.Encoding.UTF8.GetBytes(msg);
                _teensyLC.Write(sendBuff);
                Debug.Write("TeensyLC message sent [" + msg + "]\r\n");
            }
            catch (Exception f)
            {
                Debug.WriteLine(f.Message);
            }
        }

        private void Teensy3TimerCallback(object state)
        {
            byte[] writeBuff = new byte[6];
            try
            {
                string msg = "Hello Teensy3" + new Random().Next(999).ToString();
                byte[] sendBuff = new byte[msg.Length];
                sendBuff = System.Text.Encoding.UTF8.GetBytes(msg);
                _teensy3.Write(sendBuff);
                Debug.Write("Teensy3 message sent [" + msg + "]\r\n");
            }
            catch (Exception f)
            {
                Debug.WriteLine(f.Message);
            }
        }
    }
}

TIA.

Les
 
Last edited:
The Teesny3 is running the slave example code and the TeensyLC is running the slightly modified code below ...
Code:
//
// handle Rx Event (incoming I2C request/data)
//
void receiveEvent(size_t len)
{
    while(Wire.available())
    {
      [COLOR=#ff0000]char c = Wire.read();[/COLOR]     // receive byte as a character
    }
    Serial.println();           // print newline
}

You must have some other kind of receive function. This doesn't seem to do anything at all. It reads a byte into the same local-scope "c" var, over and over, then dumps it when it exits scope and then prints a newline.

The original Slave example is only designed to work with the original Master example - it is using a protocol layer on top of base I2C communication (it has a command and address byte as part of the data payload). Your PI master is not going to be talking to it the right way.

I would start by taking a closer look at the T3 and LC receiveEvent() functions. I would not run two Slaves until you get one working exactly right. If you have trouble with that, post just that one with details of the problem.
 
You must have some other kind of receive function. This doesn't seem to do anything at all. It reads a byte into the same local-scope "c" var, over and over, then dumps it when it exits scope and then prints a newline.

The original Slave example is only designed to work with the original Master example - it is using a protocol layer on top of base I2C communication (it has a command and address byte as part of the data payload). Your PI master is not going to be talking to it the right way.

I would start by taking a closer look at the T3 and LC receiveEvent() functions. I would not run two Slaves until you get one working exactly right. If you have trouble with that, post just that one with details of the problem.

Thanks for the reply, and sorry somehow I messed up the code, it should be...

Code:
void receiveEvent(size_t len)
{
    while(Wire.available())
    {
      char c = Wire.read();     // receive byte as a character
      Serial.print(c);          // print the character
    }
    Serial.println();           // print newline
}

I realise the original slave code was designed to work with the master which is why I modified it. (The PI code is just sending a string for this simple test and works fine with a single TeensyLC device) The point is that this code works perfectly when I swap out the TeensyLC with a Teensy3. Why? (something to do with the STOP signal?)

The original project is using a DS2482-100 with a DS18B20 thermal sensor and the Rinsen OneWire library, when I added the TeensyLC, I ran into the problems described above, where every time the sensor was read I would receive data on the TeensyLC. To help troubleshoot the issue I created a new project without the DS2482, substituting it with a Teensy3 and still I have the same issues. However the same code running on a Teensy3, in the original project works fine with the DS2482.

Hope this makes sense.

Regards,

Les
 
[/CODE]
I realise the original slave code was designed to work with the master which is why I modified it. (The PI code is just sending a string for this simple test and works fine with a single TeensyLC device) The point is that this code works perfectly when I swap out the TeensyLC with a Teensy3. Why? (something to do with the STOP signal?)

The original project is using a DS2482-100 with a DS18B20 thermal sensor and the Rinsen OneWire library, when I added the TeensyLC, I ran into the problems described above, where every time the sensor was read I would receive data on the TeensyLC. To help troubleshoot the issue I created a new project without the DS2482, substituting it with a Teensy3 and still I have the same issues. However the same code running on a Teensy3, in the original project works fine with the DS2482.

The STOP method on T3 and LC is different, wherein LC is using a STOP interrupt (a newer development) and T3 is using a pin hack (but one that has been running quite well for a long time), so it is possible there is something going on there.

Overall I'm still not getting a complete picture of what's going on here. As I understand it, talking to either the T3 or LC slaves individually if only one is connected to the bus works fine, is that right? These are running a basic Slave that reads the data and prints it, that's all right? No other blocking interrupts or other wierdness in parallel?

This may not be on the Slave side. One thing that I see is that these timers look like an integer multiple of each other:
Code:
_teensyLCTimer = new Timer(this.TeensyLCTimerCallback, null, 0, 1000);
_teensy3Timer = new Timer(this.Teensy3TimerCallback, null, 0, 200);
I don't know if they step on each other, or if it's right or wrong (I'm unfamiliar with this code), but it seems something could be colliding if these are sharing an interface. Is it possible to use one timer and ping-pong the messages between Slaves? That would eliminate some concerns if things aren't thread safe and they collide.

Ideally a logic analyzer shot of traffic right when the problem occurs would help, but I'm guessing that's a difficult thing.
 
Overall I'm still not getting a complete picture of what's going on here.

It's actually hard to explain without seeing it in action. (It took me a whole day to get this far and creating the new project helped me see whats going on, all though I have no idea why.)

As I understand it, talking to either the T3 or LC slaves individually if only one is connected to the bus works fine, is that right? These are running a basic Slave that reads the data and prints it, that's all right? No other blocking interrupts or other wierdness in parallel?

Correct. In the PI code, if I comment out the Teensy3 timer, this is the output I get on the LC...

Code:
Hello TeensyLC551
Hello TeensyLC97
Hello TeensyLC881
Hello TeensyLC307
Hello TeensyLC568
Hello TeensyLC993
Hello TeensyLC777
Hello TeensyLC562
Hello TeensyLC986
Hello TeensyLC412
Hello TeensyLC837
Hello TeensyLC263
Hello TeensyLC525

Now if I stop the PI code and comment out the LC timer, this is what I get...

Code:
Hello TeensyLC5255
Hello TeensyLC52555
Hello TeensyLC525555
Hello TeensyLC5255555
Hello TeensyLC52555555
Hello TeensyLC525555555
Hello TeensyLC5255555555
Hello TeensyLC52555555555
Hello TeensyLC525555555555
Hello TeensyLC5255555555555
Hello TeensyLC52555555555555
Hello TeensyLC525555555555555
Hello TeensyLC5255555555555555
Hello TeensyLC52555555555555555
Hello TeensyLC525555555555555555
Hello TeensyLC5255555555555555555
Hello TeensyLC52555555555555555555
Hello TeensyLC525555555555555555555
Hello TeensyLC5255555555555555555555
Hello TeensyLC52555555555555555555555
Hello TeensyLC525555555555555555555555
Hello TeensyLC5255555555555555555555555
Hello TeensyLC52555555555555555555555555
Hello TeensyLC525555555555555555555555555
Hello TeensyLC5255555555555555555555555555
Hello TeensyLC52555555555555555555555555555
Hello TeensyLC525555555555555555555555555555
Hello TeensyLC5255555555555555555555555555555
Hello TeensyLC52555555555555555555555555555555

The last block of data is being received and the 'Wire.available()' is growing by one byte each time something is sent to the Teensy3. (or another device on the bus) If I reboot the LC, it receives nothing, it only happens if at least one block of data has already been sent.

I don't know if they step on each other, or if it's right or wrong (I'm unfamiliar with this code), but it seems something could be colliding if these are sharing an interface. Is it possible to use one timer and ping-pong the messages between Slaves? That would eliminate some concerns if things aren't thread safe and they collide.

I just made the Teensy3 timer much shorter to try and illustrate what's going on, I don't think they ever actually run at exactly the same time.(I am sure I would get exception when writing to the device if there was a sharing violation)

Regards,

Les
 
Ok I get it, your saying the T3 traffic is re-triggering the LC receiveEvent, which somehow is probably reprinting the last character in the buffer. I'll have to see if I can rig a local test case. I'm in the middle of the library update for 3.5, but I'll see if I can work it in.
 
Actually I'm wondering if this is due to interaction with Serial. For Serial to function there is implicit ISR traffic due to USB (USB runs at a higher priority). receiveEvent() is a callback from inside the I2C ISR, so it's really part of the ISR. Stacking ISRs works due to the NVIC, but one thing you can try is to pull the Serial stuff out of receiveEvent(). The way the code is written compounds this effect due to the way it is written - printing one byte at a time, versus printing a whole buffer. Since I2C is slow this creates a lot of dragged out USB traffic.

To fix that here is something to try - use receiveEvent() to stuff the data in a buffer, and then set a flag. Mark the flag as volatile. In your main loop check for the flag, and if it occurs print the buffer then clear the flag.
 
When the ReceiveEvent is called :: void receiveEvent(size_t len)

The number of known bytes available is provided. There may be a problem - and this may just hide the symptom, but what do you get with:

Code:
void receiveEvent(size_t len)
{
    for ( size_t ii=0; ii<len; ii++)
    {
      char c = Wire.read();     // receive byte as a character
      Serial.print(c);          // print the character
    }
    Serial.println();           // print newline
}

If this works then this message all the next messages should arrive and be handled properly. If the chatter persists that may help clarify the problem.
 
Last edited:
When the ReceiveEvent is called :: void receiveEvent(size_t len)

The number of known bytes available is provided. There may be a problem - and this may just hide the symptom, but what do you get with:

Code:
void receiveEvent(size_t len)
{
    for ( size_t ii=0; ii<len; ii++)
    {
      char c = Wire.read();     // receive byte as a character
      Serial.print(c);          // print the character
    }
    Serial.println();           // print newline
}

If this works then this message all the next messages should arrive and be handled properly. If the chatter persists that may help clarify the problem.

Thanks for the suggestion but it makes no difference.

Actually I'm wondering if this is due to interaction with Serial. For Serial to function there is implicit ISR traffic due to USB (USB runs at a higher priority). receiveEvent() is a callback from inside the I2C ISR, so it's really part of the ISR. Stacking ISRs works due to the NVIC, but one thing you can try is to pull the Serial stuff out of receiveEvent(). The way the code is written compounds this effect due to the way it is written - printing one byte at a time, versus printing a whole buffer. Since I2C is slow this creates a lot of dragged out USB traffic.

To fix that here is something to try - use receiveEvent() to stuff the data in a buffer, and then set a flag. Mark the flag as volatile. In your main loop check for the flag, and if it occurs print the buffer then clear the flag.

I though this had made a difference until I removed the LED flash from the main loop.

First off I tweaked the PI code to print a counter, rather than a random number and this is the expected output...

Code:
Hello TeensyLC [0]
Hello TeensyLC [1]
Hello TeensyLC [2]
Hello TeensyLC [3]
Hello TeensyLC [4]
Hello TeensyLC [5]
Hello TeensyLC [6]
Hello TeensyLC [7]
Hello TeensyLC [8]
Hello TeensyLC [9]
Hello TeensyLC [10]
This is what I am now getting...
Code:
Hello TeensyLC [0]
Hello TeensyLC [0]]
Hello TeensyLC [0]]]
Hello TeensyLC [0]]]]
Hello TeensyLC [0]]]]]
Hello TeensyLC [1]
Hello TeensyLC [1]]
Hello TeensyLC [1]]]
Hello TeensyLC [1]]]]
Hello TeensyLC [1]]]]]
Hello TeensyLC [1]]]]]]
Hello TeensyLC [2]
Hello TeensyLC [2]]
Hello TeensyLC [2]]]
Hello TeensyLC [2]]]]
Hello TeensyLC [2]]]]]
Hello TeensyLC [2]]]]]]
Hello TeensyLC [3]
Hello TeensyLC [3]]
Hello TeensyLC [3]]]
Hello TeensyLC [3]]]]
Hello TeensyLC [3]]]]]
Hello TeensyLC [3]]]]]]

TeensyLC code...

Code:
#include <i2c_t3.h>

// Function prototypes
void receiveEvent(size_t len);

volatile bool msgRecieved = false;
char msg[31];
//
// 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, I2C_RATE_400);

    // register event
    Wire.onReceive(receiveEvent);

    Serial.begin(9600);
}

void loop()
{
    if (msgRecieved)
    {
      Serial.println(msg);
      msgRecieved = false;
    }
}

//
// handle Rx Event (incoming I2C request/data)
//
void receiveEvent(size_t len)
{
    memset(msg, 0, sizeof(msg));
    for ( size_t ii=0; ii<len; ii++)
    {
      char c = Wire.read();     // receive byte as a character
      msg[ii] = c;          // add the character
    }
    msgRecieved = true;
}

Regards,

Les
 
Back
Top