New I2C library for Teensy3

Hi nox771, thanks for your fast answer!
I am not entirely sure if I understand all of it right, but I will make my way through your examples,
especially the timout one.
Thanks again
Roland
 
question to Brian/nox771. can I use this library from an interrupt handler (Interval timer) to send 1 byte of data? I think the interrupt priority of interval timer is 128. I am migrating code from arduino mega that sets port/pin in a timer interrupt handler. Due to the limited number of pins of the T3.1, I have to use an i2c io expander, but want to retain the code design of controlling an 8 bit port from a timer interrupt handler, since controlling the port pin is time critical and cannot be delayed (how much latency is added by sending the 1 byte via i2c? compared to direct port bit setting) like in case main loop blocks. or should I do direct i2c register manipulation from the timer interrupt handler routine to send the 1 byte of data?
 
The latest library has automatic priority escalation, so it can run from inside interrupts. The "interrupt" example does exactly what you are trying to do.

Edit: I just saw a typo in that example, it is using internal pullups even though the comments say external. Just be sure to set your begin() call correctly for your setup.
 
Last edited:
beta testing of teensy LC shows that the LC's I2C pullups are high impedance (44Kohms).
That's almost unusably high. I guess it could work for 100kbit rate.

So, 200 ohms on 3.1 or 44k on LC, I don't know what's up with Freescale. You would think they could make something in the range of 2k to 5k.
 
That's almost unusably high. I guess it could work for 100kbit rate.

So, 200 ohms on 3.1 or 44k on LC, I don't know what's up with Freescale. You would think they could make something in the range of 2k to 5k.
The teensy 3.* is the outlier. Paul's note in Wire.cpp would suggest Freescale screwed up for the 3.* I2C pullup. The LC pullup value matches other architectures (AVR and ARM DUE/maple) value for the internal pullup (20k to 50K), and for that mattter, the value of the 3.* INPUT_PULLUP is around 32K.
 
Since I hadn't played with I2C pullups on 3.1 til now, i'm concerned about the power limits on the I2C pins. if the 3.1 I2C pullup is only 190 ohms (I measured 164 ohms on my 3.1), then such a pin could draw 17ma. Is that a concern? Does the pulsing of I2C signals mitigate power concerns??
 
The I2C specification requires a pin to be able to sink 3mA. In this case I'd use an external pull-up.

I was more concerned that several of the i2c_t3 library examples use I2C_PULLUP_INT, and that old arduino users might be in the habit of using "internal pullups" ...
 
As far as current, the mitigating factor is that the I2C bus when idle is at a high voltage level, so it is not a static 17mA current (it's probably not 17mA either, the pulldown devices will have some impedance also). The current only flows during periods of traffic. The worst case condition would be SDA line during transmitting a continuous stream of zeroes. I think it's probably fine for burst traffic. If I was driving some kind of display and sending large framebuffer data (potentially with a lot of zeroes), then I would probably use external.

On the next rev with LC support I'll probably change the examples to external pullup (since 44k is just about useless). I usually have it set as internal because that's how I test it (and I'm too lazy to remember to change it back).
 
I pulled the i2c_t3 from github and the kriswiner/MPU-9250 was hanging on me, sometimes with no serial.print. Tried a few sketches there and confirmed other sketches work. Opened the i2c_T3\example\scanner and it was hanging with no serial.print. Adjusted the begin() with a while(!serial and delay) then I got a line, and hacked into the debug print with no pins set and it prints starting scan, then prints after wire.begin and then never prints after Wire.endTransmission();

I have kriswiner hardware on 29_30(bottom solder) [with onboard pull-ups], but I also set to scan two other OPEN pins pairs (16_17 && 18_19) on this teensy and one T3.1 with nothing soldered and nothing returns.

Is this an open issue for IDE 1.6 w/TeensyD 1.21b7? It is wrong to assume it would just time out on open i2c pins? It acts the same on the 29_30 pair that should be responding on the one T3.1.

Running: Current beta-7 at 96Mhz.
 
You need to use the Wire1.begin call and Wire1.write etc. on the bottom I2C pins 29/30 when using the i2c_t3.h library. You can't use these pins with the Arduino Wire.h library AFAIK.
 
Makes sense - the scanner started working with wire1 - ACK's "everywhere" 1-127 on the soldered board . . . now to go get a corrected sample to work. The scanner does just hang on the unpopulated teensy3.1
 
I have kriswiner hardware on 29_30(bottom solder) [with onboard pull-ups], but I also set to scan two other OPEN pins pairs (16_17 && 18_19) on this teensy and one T3.1 with nothing soldered and nothing returns.

Is this an open issue for IDE 1.6 w/TeensyD 1.21b7? It is wrong to assume it would just time out on open i2c pins? It acts the same on the 29_30 pair that should be responding on the one T3.1.

IIRC you want to avoid floating I2C pins, it will hang on floating pins because they eventually get pulled low and then it thinks another bus master is holding the SDA/SCL low. It hangs at this point in sendTransmission():
Code:
        // we are not currently the bus master, so wait for bus ready
        while(*(i2c->S) & I2C_S_BUSY);
I need to augment that with a timeout check, but it hasn't been done yet. Timeout was set to start after acquiring control of the bus, but I suppose it makes more sense to pull it before the above point. I'll try to roll it in with the LC fixes. For now just be sure to use pullups on the pins.
 
Sounds like a good fix and that explains it not working on open pins. And with 3 sets shown on the 3.1/LC cards it would be easy to get into this state and nice to have it get resolved. I resorted to scanner having it sit was not helpful - as I had just hand soldered to 10 teensy bottom pads making a $45 unit I wanted to see work. For my first time practice with solder paste I put a Tiny13 onto an SMD converter board, then I did these 10 'cut' through holes.
T_padSolder.jpg
 
(Nevermind. I thought there was LC support already in the Github version, but there is not, yet).
 
Last edited:
That was not intended as a criticism. Just my replacement text for a long "this doesn't seem to work" post followed by several realizations as to why. I was trying to use this library to read Adafruit I2C FRAM on the Wire1 second I2C interface on LC.
 
All,

I've uploaded a new v8 version of the library (refer to top post). I'll be updating GitHub shortly also. It has the following changes:

Teensy LC support
  • Fully supported - Master/Slave modes, IMM/ISR/DMA operation, Wire/Wire1 interfaces
  • Wire: pins 16/17 or 18/19 (rate limited to I2C_RATE_1200 due to 24MHz F_BUS)
  • Wire1: pins 22/23 (rate limited to I2C_RATE_2400 due to 48MHz F_CPU)
Improved Timeout behavior:
  • Added timeout on acquiring the bus. Prior to sending a START the Master will wait for the bus to not be busy. If that does not occur in the specified time, then it will exit with a timeout error (more below). This should prevent lockups involving the I2C waiting for the bus to be released (due to stuck Slave or something else). Of course this requires that a timeout is specified on the calls.
Added setDefaultTimeout(timeout) function:
  • To assist in specifying timeouts, there is this new function. The default timeout is initially zero (infinite wait), however once it is set to something else then all subsequent commands will use that timeout. This should save some code editing, just throw one of these at the top of the code, and there you go.
Added resetBus() function:
  • In the above case where the Master can't send a START because a Slave is holding the SDA low, this command will toggle the SCL line (up to 9 clock pulses), to try and get the Slave to release SDA. Once SDA is released the Master should be able to send new commands.
Added I2C_AUTO_RETRY define:
  • This user define puts the above behavior all together. When this is defined, if the Master cannot send a START due to bus busy, it will call resetBus() automatically, and then if the SDA line releases, it will issue the START and continue on. So instead of a timeout on bus busy it will try to free the bus and then retry the START. If the bus remains busy it will return as a timeout error. Because of what it is doing, in the general sense this is not compatible with multi-master buses. However I am defaulting this to defined because I think the majority of scenarios are single-master. This may be a bad assumption, I don't know, so if anyone thinks this is a problem then leave a comment.
Added setRate(rate) function:
  • This is just for simplicity, similar to setClock(freq). It does not require specifying the bus freq.

This update was more involved than I originally anticipated. The DMA and Slave modes both gave me trouble for a while. However, this latest code seems to work well. I ran a bunch of tests in different configurations on the LC and it all seemed to work. I also checked 3.0/3.1 for regressions and I didn't find anything. If anyone has problems then let me know.


Misc notes:

  • Thanks - First thanks to manitou for the LC investigations. That was helpful in getting going on the LC update. Also thanks to Swap_File for the resetBus() idea. Hopefully this new feature will help out with flaky devices.
  • DMA and timeouts - I still don't have a good fix for timeouts in DMA mode. If they give you trouble switch to ISR mode. DMA is like a freight train without a driver, once you set it on it's way it doesn't want to stop. IMO the current implementation is a bad fit for error-prone communication. It doesn't respond to bus events, and abruptly stopping it causes the I2C hardware to get stuck.
  • I2C_FLT - there is some odd stuff going on in this register on LC. I've seen bit4 toggling when I read it back, and in the ISR clearing STOPF isn't sufficient to get things working, the read value must be written back to it. It's strange...
 
Back
Top