New I2C library for Teensy3

It seems to be solved!

As stated above, the change I made is to use the i2c_t3.h library instead of Wire.h and added Wire.setDefaultTimeout(100000); in setup(). A few days ago the uC ran for almost 48 hours and no lock-up/freeze! =) Don't think I have been able to that before. Haven't tried the if(Wire.getError()) error checking function yet, but will give it a try when I have the possibility. Would be nice to have an understanding of if, and how many times, i2c-communication fails.

@Headroom: Yes, I get your point. The situation is that it's not the end of the world if I loose one or two i2c transmits in an hour. Its compass and wind data that are sent several times per second and then averaged across hundred samples.

My setup is an sailboat autopilot with i2c-master Teensy 3.2 connected to i2c-slave attiny85 and i2c-slave LSM303 compass. The attiny is connected over a phone cable that is over 15 meter long and in a pretty bad condition. Impressed that it all works so well, especially with the new library. =)

Thanks a lot for all your input and help!

Rvcolhiy.jpg
 
Last edited:
It seems to be solved!

As stated above, the change I made is to use the i2c_t3.h library instead of Wire.h and added Wire.setDefaultTimeout(100000); in setup(). A few days ago the uC ran for almost 48 hours and no lock-up/freeze! =) Don't think I have been able to that before. Haven't tried the if(Wire.getError()) error checking function yet, but will give it a try when I have the possibility. Would be nice to have an understanding of if, and how many times, i2c-communication fails.

Good to hear that it works!
 
Hi All,

I am having a problem with a function I am writing using the i2c_t3 library. I want to read consecutive registers from an i2c device.

From what I understand, the procedure is to tell the Wire.requestFrom() method that you want two bytes from the initial address. For instance, value_LSB is at address 0x01 and value_MSB is at address 0x02. To then retrieve the value of both registers, we call Wire.requestFrom(value_MSB, 2) and then call Wire.read() twice to read the first and second bytes in the RX buffer.

Do I have my principle of right, is the first question?

If I do, the following code is my function:
Code:
uint16_t deviceReadBytes(byte deviceAddr, byte regAddr, byte noOfBytes){
  byte data[noOfBytes];
  uint16_t value;

  Wire.beginTransmission(deviceAddr);       // Notify i2c which device we want to talk to
  Wire.write(regAddr);                      // Notify i2c which register of the device we want to access
  Wire.endTransmission();                   // End the i2c transmission with the device
  Wire.requestFrom(deviceAddr, noOfBytes);  // Request information from the i2c device

  while(!Wire.available()){
    // Waiting for i2c to return a value
  }

  // Read multiple bytes
  if (noOfBytes > 1) {
    for (int i = 1 ; i <= noOfBytes ; i++) {
      data[i - 1] = Wire.readByte();        // Write i'th byte to the data array
    }
    value = (data[0] << 8) | data[1];       // Bit shift the first byte and perform a bitwise or operation to combine the MSB & LSB values
  } else {  // Read one byte
    value = Wire.read();                    // Read byte from RX buffer into value
  }
  return value;
}

It is designed to read either one address or multiple addresses.

I do realize that when I say that it is designed for reading multiple address, it can only do two because of the bit shifting and the bitwise operation, but that is not important at this point. I can fix that in the logic later.

The reason I know there is a problem is that I know the values of two particular registers I am reading. If I read them individually I get the right values, if I read them using the above function I get the incorrect value for the second register.

Thanks for all and any help in advance.

Kind regards,

Dylan
 
I may not be up on the latest c++ stuff, but the one thing that I am not sure of is: byte data[noOfBytes];

That is to have a variable number of bytes on stack... So the first thing I would try is: maybe define it as data[10];

And see if your function works any differently.
 
Couple of other things: It would help also if you said something like the two values are: x and y and the return value for reading both was...

But:

For instance, value_LSB is at address 0x01 and value_MSB is at address 0x02. To then retrieve the value of both registers, we call Wire.requestFrom(value_MSB, 2)
So you are saying the value is stored: LSB, MSB
But in the code:
Code:
uint16_t deviceReadBytes(byte deviceAddr, byte regAddr, byte noOfBytes){
...
    value = (data[0] << 8) | data[1];       // Bit shift the first byte and perform a bitwise or operation to combine the MSB & LSB values
...
It looks like you are processing it like: MSB, LSB

Also sometimes I casting to make sure things work:
Might try something like:
Code:
    value = ((uint16_t)data[1] << 8) | data[0];       // Bit shift the first byte and perform a bitwise or operation to combine the MSB & LSB values
 
Hi KurtE,

Many thanks for your help! It was indeed a case of reading the bytes in the incorrect order. The fix was just to change...
Code:
    ...
    value = (data[0] << 8) | data[1];       // Bit shift the first byte and perform a bitwise or operation to combine the MSB & LSB values
    ...

to...

Code:
    ...
    value = (data[1] << 8) | data[0];       // Bit shift the first byte and perform a bitwise or operation to combine the MSB & LSB values
    ...

Many thanks and much appreciated!

Kind regards,

Dylan
 
where is getClock()?
Is it possible to get 1.7Mhz on teensy3.2?
Aiming for 1.2Mhz but debug timing looks like 800k so want getClock to check.
 
Last edited:
where is getClock()?
Is it possible to get 1.7Mhz on teensy3.2?
Aiming for 1.2Mhz but debug timing looks like 800k so want getClock to check.

Is Wire.getClock() not working?

In the most recent library it is this inline function (it returns a uint32_t value):
Code:
    // ------------------------------------------------------------------------------------------------------
    // Get I2C clock - return current clock setting
    // return: uint32_t = bus frequency (Hz)
    // parameters: none
    inline uint32_t getClock(void) { return i2c->currentRate; }

However you have to understand a few details on the clock system. For the I2C peripheral the theoretical rates and the actual rates are not the same. There are a few effects going on. One is that the peripheral will limit the bit clock (this is just due to internal latencies in the digital implementation of the block at a hardware level), so setting 1.2M may yield an actual 800k bit clock rate. This peripheral limitation is the primary limiter at the high end, and the really high rates give diminishing returns beyond a certain point. Internally the divide ratios are correct, but the external rates will be slower.

The other effect is due to divide ratios. You can set rates up to 3MHz on T3.2, but at high rates there are fewer divide ratios available so you may not get an exact setting that you want. So for instance there are divide ratios of 20 and 22 IIRC, so on a 60M bus clock using 20 will yield a 3M setting, but 22 will give ~2.73M (a fairly large jump). Essentially the value you set via setClock() is given as a "target" value, and the library will try to choose the closest available divide ratio. The rate you get back from getClock() will be this "quantized" ideal rate (it will not be the true external rate, which is something that would need to be measured via logic analyzer or similar).

So as an example, setting 2.8M via setClock() may in fact use a divide ratio that gives ~2.7M (depends on bus freq), and then on a logic analyzer the bit clock may come out at a much lower ~1.2M or something like that. There is a throughput plot on the first post and the github page which illustrates the effect.
 
Oh. I thought getClock() would give me the actual rate, so not much use to me.
getClock() is not working for me:

_8x8x8_LED_Cube:115: error: 'class i2c_t3' has no member named 'getClock'
Serial.println(Wire.getClock());

I got an 8x8 led cube that was looking a bit seizure inducing running i2c at 400k (730uS to update 5x mcp23017 io expanders)
Huge improvement with i2c_t3 able to do I believe 800k at 310uS.
I'm doing 1ms on per layer so i2c is holding me up.

mcp23017 is good for 1.7Mhz apparently.
 
That doesn't make sense. Make sure you are running the latest library version and it is not linking in an older version from Teensyduino. If you are using a latest library which is in your sketchbook/libraries folder, then it should dump out something like this when it compiles:
Code:
Multiple libraries were found for "i2c_t3.h"
 Used: C:\your_sketchbook_folder\libraries\i2c_t3
 Not used: C:\teensyduino_install_folder\arduino-1.6.9\hardware\teensy\avr\libraries\i2c_t3
If you follow the "used" path, make sure it points to the latest version - near the top of the .cpp or .h file it should say v9:
Code:
- (v9) Modified 01Jul16 by Brian (nox771 at gmail.com)

Or if you have the latest development teensyduino it should be upgraded already. You can find it here:
https://forum.pjrc.com/threads/36756-Teensyduino-1-30-Beta-4-Available
 
Well this is odd, I got some new BNO055 breakout boards from China (my design, should work well, with 4K7 pullups on the board ) and tried one out using a Teensy 3.1 and I can read both of the I2C addresses (BNO055 has one and BMP280 has one), and I get the right WHO_AM_I from all devices and the self checks pass. Then when the sketch goes to read some data, it stalls. This is with i2C_t3 using pins 16/17 like I have done 1 x 10^15 times before. I tried the boards on an STM32L4 and they work fine at 400 kHz. Boards seems OK. Then I tried back on the Teensy at 100 kHz and... works fine. Then I tried at 1000 kHz and... works fine, but 400 kHz, it stalls on the first data read as far as I can tell. I am using Teensiduino v 1.30 I believe and Arduino 1.6.8. Before I spew a lot of code your way, does this seem even possible? I mean, is there some weird RC resonance causing trouble at 400 kHz? Never seen this before...
 
A few recommendations:

1) Inside the latest version there is an archive folder containing all other versions. I would first try and run v8 release to see if the problem is still there. The code that sets the divider was changed a lot in v9, so it is unlikely but there may be something going on there. Running with v8 would verify it one way or the other.

2) On v9 code, run Wire.setClock(400000) to set 400kHz, then read the clock setting, eg. uint32_t rate = Wire.getClock(), and print it to see if it is set correctly to 400kHz. If not then post your F_BUS freq and whatever setup code you are running.

3) To get a more complete picture you could create a loop. First set default timeouts via setDefaultTimeout(), then sweep across freq, say 100kHz to 1M using setClock() and getClock() as above. The timeout should catch the case where it fails. Print the output at each freq.

I can't say if it is or isn't a HW fault. I haven't seen any other case where it works at higher and lower freq but not in the middle.
 
I am suspecting a hardware issue.

I went back to v.08 and also could not get it to work at 400 kHz, but it did at 100 kHz and 1000 kHz again. I went back to v.09 and was able to get it to work at 350 (352 kHz) and 450 (461) kHz but not at 390 (400 kHz) or 400 kHz (400kHz) where the frequencies are setClock(getClock). There must be a weird resonance at 400 kHz preventing the device from reading the data registers, meaning reading multiple bytes since I can read the WHO_AM_I registers and self test registers just fine and sometimes I can even get through the accel calibration at 400 kHz before it freezes up (doesn't continue). I'll look into this more tomorrow.
 
I am suspecting a hardware issue.

Maybe a logic analyzer might help. i've noticed 400khz I2C on T3.5 (381 KHz) isn't the same as on STM32L4 (432 KHz), but actual frequencies aren't that different, so i'd be surprised that a device wouldn't respond.
 
Last edited:
I am suspecting a hardware issue.

I went back to v.08 and also could not get it to work at 400 kHz, but it did at 100 kHz and 1000 kHz again. I went back to v.09 and was able to get it to work at 350 (352 kHz) and 450 (461) kHz but not at 390 (400 kHz) or 400 kHz (400kHz) where the frequencies are setClock(getClock). There must be a weird resonance at 400 kHz preventing the device from reading the data registers, meaning reading multiple bytes since I can read the WHO_AM_I registers and self test registers just fine and sometimes I can even get through the accel calibration at 400 kHz before it freezes up (doesn't continue). I'll look into this more tomorrow.

This seems like it is just that specific setting causing a problem. What is your F_BUS? Sometimes there are multiple divide settings that are the same divide ratio, but they differ on start/stop timing. It may be this particular setting is not right. Try also changing F_BUS to some other values and see if the problem goes away.
 
Not sure how to check what F_BUS is. It is the default, I mean I do not particularly set it in my code. How can I query the value?
 
It is a constant (define), you can just print it. Try this:
Code:
Serial.printf("CPU speed is: %d\n",F_CPU);
Serial.printf("Bus speed is: %d\n",F_BUS);

For a given F_CPU the F_BUS is setup in the kinetis.h file around line ~750. Path is:
Code:
[FONT=courier new]arduino_folder\hardware\teensy\avr\cores\teensy3\kinetis.h[/FONT]

BTW: to check different F_BUS values, just try compiling with different F_CPU settings.
 
Last edited:
I wrote this to keep an eye on the T_3.5/3.6:
Code:
void CPUspecs() {
  Serial.println();
#if defined(__MKL26Z64__)
  Serial.println( "CPU is T_LC");
#elif defined(__MK20DX256__)
  Serial.println( "CPU is T_3.1/3.2");
#elif defined(__MK20DX128__)
  Serial.println( "CPU is T_3.0");
#elif defined(__MK64FX512__)
  Serial.println( "CPU is T_3.5");
#elif defined(__MK66FX1M0__)
  Serial.println( "CPU is T_3.6");
#endif
  Serial.print( "F_CPU =");   Serial.println( F_CPU );
  Serial.print( "ARDUINO =");   Serial.println( ARDUINO );
  Serial.print( "F_PLL =");   Serial.println( F_PLL );
  Serial.print( "F_BUS =");   Serial.println( F_BUS );
  Serial.print( "F_MEM =");   Serial.println( F_MEM );
  Serial.print( "NVIC_NUM_INTERRUPTS =");   Serial.println( NVIC_NUM_INTERRUPTS );
  Serial.print( "DMA_NUM_CHANNELS =");   Serial.println( DMA_NUM_CHANNELS );
  Serial.print( "CORE_NUM_TOTAL_PINS =");   Serial.println( CORE_NUM_TOTAL_PINS );
  Serial.print( "CORE_NUM_DIGITAL =");   Serial.println( CORE_NUM_DIGITAL );
  Serial.print( "CORE_NUM_INTERRUPT =");   Serial.println( CORE_NUM_INTERRUPT );
  Serial.print( "CORE_NUM_ANALOG =");   Serial.println( CORE_NUM_ANALOG );
  Serial.print( "CORE_NUM_PWM =");   Serial.println( CORE_NUM_PWM );
}
 
Last edited:
Had my wifi wig out there for a moment...

The F_BUS is 96 MHz when I set 96 MHz for the CPU speed and 72 MHz when I set the CPU to 72 MHz. Interestingly, when I set the CPU speed to 96 MHz the 400 kHz (400 kHz) I2C setting causes the sensor to stop during the first data reads, but when I set it to 72 MHz CPU speed the 400 kHz (409.09 kHz) I2C bus speed works; the sensor data is read and the device functions normally. Something odd about the 96 Mhz clock speed, I usually don't use it, preferring the 72 MHz. but I guess I got lazy and just kept the default and tripped up on this "feature."

The above F_BUS values are wrong, this is just the CPU clock speed apparently...

With 72 MHz CPU setting, 400 kHz I2C clock:

I2C clock rate = 409090 Hz
F_CPU =72000000
ARDUINO =10608
F_PLL =72000000
F_BUS =36000000
F_MEM =24000000
NVIC_NUM_INTERRUPTS =95
DMA_NUM_CHANNELS =16
CORE_NUM_TOTAL_PINS =34
CORE_NUM_DIGITAL =34
CORE_NUM_INTERRUPT =34
CORE_NUM_ANALOG =21
CORE_NUM_PWM =12

sensor runs normally.


with 96 MHz setting, 400 kHz I2C clock:

I2C clock rate = 400000 Hz
F_CPU =96000000
ARDUINO =10608
F_PLL =96000000
F_BUS =48000000
F_MEM =24000000
NVIC_NUM_INTERRUPTS =95
DMA_NUM_CHANNELS =16
CORE_NUM_TOTAL_PINS =34
CORE_NUM_DIGITAL =34
CORE_NUM_INTERRUPT =34
CORE_NUM_ANALOG =21
CORE_NUM_PWM =12

sensor freezes.

with 72 MHz CPU and 300 kHz I2C:

I2C clock rate = 300000 Hz
F_CPU =72000000
ARDUINO =10608
F_PLL =72000000
F_BUS =36000000
F_MEM =24000000
NVIC_NUM_INTERRUPTS =95
DMA_NUM_CHANNELS =16
CORE_NUM_TOTAL_PINS =34
CORE_NUM_DIGITAL =34
CORE_NUM_INTERRUPT =34
CORE_NUM_ANALOG =21
CORE_NUM_PWM =12


and the sensor freezes, does not run...
 
Last edited:
I wrote this to keep an eye on the T_3.5/3.6:
Code:
void CPUspecs() {
  Serial.println();
#if defined(__MK20DX128__)
  Serial.println( "CPU is T_LC");
#elif defined(__MK20DX256__)
  Serial.println( "CPU is T_3.1/3.2");
#elif defined(__MKL26Z64__)
  Serial.println( "CPU is T_3.0");
#elif defined(__MK64FX512__)
  Serial.println( "CPU is T_3.5");
#elif defined(__MK66FX1M0__)
  Serial.println( "CPU is T_3.6");
#endif
  Serial.print( "F_CPU =");   Serial.println( F_CPU );
  Serial.print( "ARDUINO =");   Serial.println( ARDUINO );
  Serial.print( "F_PLL =");   Serial.println( F_PLL );
  Serial.print( "F_BUS =");   Serial.println( F_BUS );
  Serial.print( "F_MEM =");   Serial.println( F_MEM );
  Serial.print( "NVIC_NUM_INTERRUPTS =");   Serial.println( NVIC_NUM_INTERRUPTS );
  Serial.print( "DMA_NUM_CHANNELS =");   Serial.println( DMA_NUM_CHANNELS );
  Serial.print( "CORE_NUM_TOTAL_PINS =");   Serial.println( CORE_NUM_TOTAL_PINS );
  Serial.print( "CORE_NUM_DIGITAL =");   Serial.println( CORE_NUM_DIGITAL );
  Serial.print( "CORE_NUM_INTERRUPT =");   Serial.println( CORE_NUM_INTERRUPT );
  Serial.print( "CORE_NUM_ANALOG =");   Serial.println( CORE_NUM_ANALOG );
  Serial.print( "CORE_NUM_PWM =");   Serial.println( CORE_NUM_PWM );
}

That's a good summary. You should post this on the Tips and Tricks thread.
 
Had my wifi wig out there for a moment...

The F_BUS is 96 MHz when I set 96 MHz for the CPU speed and 72 MHz when I set the CPU to 72 MHz. Interestingly, when I set the CPU speed to 96 MHz the 400 kHz (400 kHz) I2C setting causes the sensor to stop during the first data reads, but when I set it to 72 MHz CPU speed the 400 kHz (409.09 kHz) I2C bus speed works; the sensor data is read and the device functions normally. Something odd about the 96 Mhz clock speed, I usually don't use it, preferring the 72 MHz. but I guess I got lazy and just kept the default and tripped up on this "feature"

This isn't right. F_CPU should not equal F_BUS, except maybe 48MHz and below. Default 96MHz F_CPU should be 48MHz F_BUS.

I'll take a look at the 96MHz F_CPU setting for 400k. A 48MHz F_BUS with 400k I2C is a 120 divide. There are probably multiple ways to set 120, so one of the other settings might work better. I'll try to put together some code for you to test tomorrow.

Just out of curiosity, can you compile at 72MHz F_CPU with a 300kHz I2C setting and tell me if that works?
 
Back
Top