New I2C library for Teensy3

In order to spoof the libraries into using i2c_t3 instead of Wire, without editing anything, you would probably need to either modify the build process, or rely on directory ordering, or simply swap in the i2c_t3 in place of the default Wire library.

Thank you very much for this explanation and verification!

Based on your inspiration I tried the following but I failed FAILED:

1) Create a Wire directory in <sketchbook>/libraries:

2 ) Create a Wire.h file in it with the following contents:
Code:
#ifndef _WIRE_SPOOF_I2C_T3_
#define _WIRE_SPOOF_I2C_T3_

#include <i2c_t3.h>

typedef i2c_t3 TwoWire;

#endif

The idea being that I don't need to modify your i2c_t3 library as well.

But it failed:
Code:
C:\Users\Markus\Documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp: In member function 'void Adafruit_INA219::wireWriteRegister(uint8_t, uint16_t)':
C:\Users\Markus\Documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp:38:3: error: 'Wire' was not declared in this scope
   Wire.beginTransmission(ina219_i2caddr);
   ^
C:\Users\Markus\Documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp: In member function 'void Adafruit_INA219::wireReadRegister(uint8_t, uint16_t*)':
C:\Users\Markus\Documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp:59:3: error: 'Wire' was not declared in this scope
   Wire.beginTransmission(ina219_i2caddr);
   ^
C:\Users\Markus\Documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp: In member function 'void Adafruit_INA219::begin()':
C:\Users\Markus\Documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp:364:3: error: 'Wire' was not declared in this scope
   Wire.begin();    
   ^
Multiple libraries were found for "Wire.h"
 Used: C:\Users\Markus\Documents\Arduino\libraries\Wire
 Not used: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire
Error compiling.

Well I guess I'll stick to your solution.

Thanks again!

__Mark
 
Ok, I did some testing, there is a simple (but rather odd looking) way to do this even easier than above:

1) First create a Wire library in your sketchbook folder, with a Wire.h file in it:
Code:
<sketchbook>/libraries/Wire/Wire.h
2) Put the following contents in the Wire.h file:
Code:
#include <i2c_t3.h>
3) In your main sketch, setup the includes exactly like this:
Code:
#include <i2c_t3.h>
#include <Wire.h>             // fake include - points back to i2c_t3
#include <Adafruit_INA219.h>

This looks strange, like it is using both i2c_t3 and Wire, but Wire in this case will be the one from <sketchbook>/libraries due to Arduino build prioritization (which points to i2c_t3 and instantiates a Wire object). The #include <i2c_t3.h> is needed to force the linker to include it in the build even though it is not used directly (only indirectly via Wire.h).

See if that can work for you. It does not require duplicating the library or base install, but it does require the headers to be included as shown.
 
I've added a section to the top-post regarding resistor pullup configurations. It should cover the most common questions.
 
Last edited:
Ok, I did some testing, there is a simple (but rather odd looking) way to do this even easier than above

That's exactly what I tried, but stupid me forgot to select the Teensy 3.1 board in the Arduino IDE. I usually work with Visual Micro for Arduino inside Visual Studio (where the spoofing worked anyway).

Note the additional typedef I use in the spoofing Wire.h
Code:
#ifndef _WIRE_SPOOF_I2C_T3_
#define _WIRE_SPOOF_I2C_T3_

#include <i2c_t3.h>

typedef i2c_t3 TwoWire;

#endif

This allows for code that handles I2C buses as objects (i.e. multi bus capable libs such as the ones I am currently developping).

I think this is a feasible pattern after all that works without touching any third party libs.

Thanks again,
Mark
 
Start and stop

Is there a way to control start and stop bit through the library ?

I want to use it to read values from smart batteries on SMBus.

I need to repeat the start bit and avoid the stop one.
 
Is there a way to control start and stop bit through the library ?

I want to use it to read values from smart batteries on SMBus.

I need to repeat the start bit and avoid the stop one.

Yes repeated STARTs are possible (use I2C_NOSTOP on the command which should not end with a STOP). IIRC, the hardware has more low-level support for SMBus, but I haven't had a chance to study it.
 
The version of i2c_t3 included in Teensyduino 1.25 appears to be broken with the Teensy 3.0.

Code:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\i2c_t3\i2c_t3.cpp: In static member function 'static uint8_t i2c_t3::setOpMode_(i2cStruct*, uint8_t, i2c_op_mode)':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\i2c_t3\i2c_t3.cpp:289:84: error: 'DMAMUX_SOURCE_I2C1' was not declared in this scope
i2c->DMA->triggerAtHardwareEvent((bus == 0) ? DMAMUX_SOURCE_I2C0 : DMAMUX_SOURCE_I2C1);
^
Error compiling.

This line should probably be wrapped with a preprocessor if.
 
The version of i2c_t3 included in Teensyduino 1.25 appears to be broken with the Teensy 3.0.

Code:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\i2c_t3\i2c_t3.cpp: In static member function 'static uint8_t i2c_t3::setOpMode_(i2cStruct*, uint8_t, i2c_op_mode)':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\i2c_t3\i2c_t3.cpp:289:84: error: 'DMAMUX_SOURCE_I2C1' was not declared in this scope
i2c->DMA->triggerAtHardwareEvent((bus == 0) ? DMAMUX_SOURCE_I2C0 : DMAMUX_SOURCE_I2C1);
^
Error compiling.

This line should probably be wrapped with a preprocessor if.

Ah thanks, I'll look into it.
 
Hello.

Would it be possible to connect Teensy 3.1 to I2C bus which contains only 5V devices without level-shifters?

Since Teensy 3.1 is 5V tolerant, the plan is to connect pullup resistors for SDL and SCL to 5V (instead of 3.3V). Are there any significant downsides of this method?
Teensy will have slightly lower threshold values for high and low levels. For 5V device VH=3.5, VL=1.75 and for Teensy VH=2.31, VL=1.15 (assuming VH=0.7*Vdd, VL=0.35*Vdd). But I could not figure out what effect it will have on I2C performance.
 
Hello,

thanks a lot for this library. Is the best one I found in the last month.

At the address 0x00 i2c_t3.h Library returns an ACK even when the unit is powered off.

Im using a device with a broadcast address 0x00 which addresses a group of up to 8 units each with their own I2C addresses (two per unit: Controller and EEPROM). All units respones to Braodcast adress 0x00.
How can one check, if i2c on 0x00 is active and how can I use this address?

On arduino with wire.h or with Peter Fleurys i2cmaster.h this works fine.
 
Hello.

Would it be possible to connect Teensy 3.1 to I2C bus which contains only 5V devices without level-shifters?

Since Teensy 3.1 is 5V tolerant, the plan is to connect pullup resistors for SDL and SCL to 5V (instead of 3.3V). Are there any significant downsides of this method?
Teensy will have slightly lower threshold values for high and low levels. For 5V device VH=3.5, VL=1.75 and for Teensy VH=2.31, VL=1.15 (assuming VH=0.7*Vdd, VL=0.35*Vdd). But I could not figure out what effect it will have on I2C performance.

Sorry for the huge delay in response, completely didn't see the notice on this. In theory this should work ok because it is on a 5V tolerant I/O. Moreover because the pullup is resistive it is inherently a current-limited connection. The lower switch threshold of the Teensy shouldn't be a problem as long as your pullup resistance is not excessively low. It should not affect the performance.

Problems come up when you have a non-current-limited connection (eg. hard-tie to say 5V if a 3.3V device is on the bus with a supply-connected ESD diode, then the diode will hard clamp the voltage to ~4V at whatever current it can take - until it blows).

I have in the past connected differing voltage devices using just series resistors (specifically different voltage shift-registers), and they ran fine (but they had dual-diode ESD). The ESD was probably mildly forward-biased, but the series R keeps it away from damaging current levels. Although I should mention some devices now use entirely ground-referenced ESD (referred to as ggNMOS - grounded-gate-NMOS), so that's not always a workable idea (ggNMOS will trip at a high-voltage, above supply, and then snapback).

So all that said, this is a try at your own risk type of thing, but for your specific case I think it can work.
 
Hello,

thanks a lot for this library. Is the best one I found in the last month.

At the address 0x00 i2c_t3.h Library returns an ACK even when the unit is powered off.

Im using a device with a broadcast address 0x00 which addresses a group of up to 8 units each with their own I2C addresses (two per unit: Controller and EEPROM). All units respones to Braodcast adress 0x00.
How can one check, if i2c on 0x00 is active and how can I use this address?

On arduino with wire.h or with Peter Fleurys i2cmaster.h this works fine.

Sorry for the delay, 0x00 is not a valid Slave address, it is the General Call address. Refer to the I2C spec here, page 17 specifically:
http://www.nxp.com/documents/user_manual/UM10204.pdf

The Teensy I2C hardware can be configured to recognize it. The library is not configured to use it at the moment. If you look at the Freescale documentation here:
http://pjrc.com/teensy/K20P64M72SF1RM.pdf

Refer to Chapter 46, pg 1178, the GCAEN bit controls the feature. It should be disabled by default. There is additional info in Chapter 46 regarding that bit. If a GC is received the library would probably need to be modified to parse the 2nd byte after the GC to determine what to do. I haven't worked with this feature yet as I don't have any Slaves which support it.
 
I2C LCD to working correctly

I can't seem to get I2C to work correctly

I tried the standard "wire.h" but I can not get the i2C LCD to work.

I have used the Serial LCD Module 20x4 Blue with White Backlight 5v version for years with 324/1284 based avr boards with no issue. I bought the 3.3V version to work the Teensy.

Product Datasheet: http://media.nkcelectronics.com/datashe ... -BBW-33V33
Arduino Sample program: http://media.nkcelectronics.com/downloa ... Serial.ino
Arduino 1.0 library: http]s://github.com/downloads/nkcelectronics/SerialLCD/SerialLCD.zip

I used the standard Arduino library but used:

Code:
"#include <i2c_t3.h>"
instead of the standard wire library.

The board has 10K resistors. I another 10K pull up in parallel.

The display starts working out find but eventual decays as if missing messages.

Any ideas why?

Thanks

Bruce
 
I can't seem to get I2C to work correctly
The display starts working out find but eventual decays as if missing messages.
Any ideas why?

I wasn't able to access any of those links, I just get server error. Perhaps try uploading your code example to the forum.

It is difficult to speculate on a cause, it would be just random guessing. If initial messages work, but later ones don't then perhaps there is some other overriding cause in the code (eg. messages too fast, other devices on the bus, insufficient timing on slow bus, etc). There could also be hardware issues, power supply fluctuating (particularly if a backlight is involved), pullup resistance, etc.

You may need to incorporate a more rigorous error-checking methodology in your code. For instance, send an I2C message, then check the return value from the calls. For i2c_t3 this would be Wire.status() and Wire.getError() calls. Print the return codes after each transmission to the Serial window.

EDIT: your links are entered wrong - use the "Link" button on the text entry form to set them up.
 
I can't seem to get I2C to work correctly

Arduino 1.0 library: https://github.com/downloads/nkcelectronics/SerialLCD/SerialLCD.zip

Code:
/*
  NKC Electronics serial display - Demo
 
 Demonstrates different functions of the Serial LCD module
 
  The circuit:
 * LCD SCL pin to Arduino SCL pin or Analog 5
 * LCD SDA pin to Arduino SDA pin or Analog 4
 * LCD VSS pin to GND
 * LCD VDD pin to +5V
 */
 
#include <SerialLCD.h>
//#include <Wire.h>
#include <i2c_t3.h>
 
// make some custom characters:
byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};

byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b10001,
  0b01110,
  0b00000
};

byte frownie[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b00000,
  0b01110,
  0b10001
};

byte armsDown[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b00100,
  0b01110,
  0b10101,
  0b00100,
  0b01010
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};

// Constructor.  Parameters: rows, columns, baud/i2c_address, interface (RS232, I2C, SPI)
SerialLCD lcd(2,16,0x28,I2C);

void setup() {
  
  // Initialize LCD module
  lcd.init();
  
  // create a new character
  lcd.createChar(0, heart);
  // create a new character
  lcd.createChar(1, smiley);
  // create a new character
  lcd.createChar(2, frownie);
  // create a new character
  lcd.createChar(3, armsDown);
  // create a new character
  lcd.createChar(4, armsUp);
    
  // Set Contrast
  lcd.setContrast(40);
  // Set Backlight
  lcd.setBacklightBrightness(8);
}

void loop() {
  int i;
  
  lcd.home();
  lcd.displayVersion();
  delay(2000);
  lcd.clear();
  lcd.displayBaudRate();
  delay(2000);
  lcd.clear();
  lcd.displayI2CAddress();
  delay(2000);
  lcd.clear();
  
  // Write some text to the display.  Show custom characters
  lcd.home();
  lcd.setCursor(1, 1);
  lcd.print("CustomChars");
  lcd.write((byte)0);
  lcd.write(1);
  lcd.write(2);
  lcd.write(3);
  lcd.write(4);
  
  // blinking cursor, move cursor and change text
  lcd.setCursor(2, 1);
  lcd.print("This is original");
  
  delay(2000);
  
  lcd.setCursor(2, 1);
  lcd.blinkOn();
  
  for (i=0; i<8; i++) {
    lcd.right();
    delay(100);
  }
  lcd.print("modified");
    
  lcd.blinkOff();

  delay(2000);
  
  lcd.setCursor(2, 1);
  lcd.print("scrolling text..");
  lcd.setCursor(1,6);
  for (i=0; i<15; i++) {
    delay(100);
    lcd.shiftRight();
  }
  for (i=0; i<15; i++) {
    delay(100);
    lcd.shiftLeft();
  }
  
  delay(2000);
  
  for (i=0; i<MAX_CONTRAST; i++) {
    lcd.setContrast(i);
    delay(100);
  }
  
  delay(2000);
  
  for (i=0; i<MAX_BRIGHTNESS; i++) {
    lcd.setBacklightBrightness(i);
    delay(100);
  }
  
  delay(2000);
  
    // Set Contrast
  lcd.setContrast(40);
  // Set Backlight
  lcd.setBacklightBrightness(8);
  
  delay(2000);
}

http://media.nkcelectronics.com/datasheet/NKC2004SD-NSW-BBW-33V33.pdf

I am presently using the USB power supply.

The display is by itself.

Pull ups are 10K on the board. I tried adding another 10K (so actually 5K) in parallel and it did not help.

The display work fine at 400K with the UNO and the 1284P I am using (5V version).

I will follow up on the more rigorous error checking.

Thanks

Bruce
 
Can this library handle multimaster --- by that I mean handle multiple masters on a single bus, and allow the masters to address one another? I have done this previously with Wire by initializing them to be addressed slaves, but then using the master-send routines.
Thanks.
David
PS This library is a tour de force!
 
Pull ups are 10K on the board. I tried adding another 10K (so actually 5K) in parallel and it did not help.

I believe 10K pull-ups are TOO HIGH for 3.3v systems. For example a google search brings up from Phil Pilgrim: http://forums.parallax.com/discussion/143727/pull-up-resistors-on-scl-and-sda
Phil Pilgrim said:
My recommendation is 4.7K on both lines. 10K -- especially in 3.3V systems -- is too high a value, particularly for high-speed operation.

And this from an Adafruit forum: http://forums.adafruit.com/viewtopic.php?f=8&t=45373:
frank26080115 said:
I usually find that 400KHz I2C busses will malfunction using 10K resistors at 3.3V, it's safer to start with 4.7K, and move down to 2.7K if you experience any errors.

This datasheet mentions how to calculate the appropriate resistors based on the capacitive load on the i2c lines: http://www.ti.com/lit/an/slva689/slva689.pdf
 
4k7 , or 5k in your case should be ok at 3v3,
with a following wind etc.

some I2C chips need 5v on the power, even if they are 3v3 'compatible' and if your using usb power, that can be well below the 5v level.

for 3v3 I'd normally go for 2K2 to get any speed out of I2C

Its out with the scope to check the actual signal levels / shape.

I2C is real easy, thats to get write and wrong, there are so many variants of it now.
sorry on small screen device here, did you say what the I2C device you have a slave is
 
One of the better Chinese data sheets I have seen,

You seem to be in happy position of having a scope and a demo working with a 5v uno to compare with.
so at least you know the LCD works.

so out with scope.

What I2C levels are you getting on the I2C on the teensy and the UNO.

You might want to look at pulse timing also , assuming any are on the I2C lines.

A few things concerned me with the data sheet, the fact the I2C address can be set to 'anything', and the same pins supporting RS232, SPI and I2C.
also the ambiguity about the 5v and 3v3 status of the LCD.

When you ran the LCD with the UNO, what did you do for the 3v3 logic and power levels the LCD wants.
 
Back
Top