New I2C library for Teensy3

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

My previous experience are using the 5V version of this LCD with the UNO/Mega/Mega Junior, not the 3.3V version.

Address Ack.jpg

Sometimes ACK is OK

Address NAK.jpg

Sometimes it is not.

Only 0x28 is acknowledged by the LCD when it is working.
 
Ok
looks like you have a logic analyser there, not a scope,
so the logic analyser is showing 1 or 0, depending what it thinks is the threshold.

Do yo have a scope ? so that you can see the actual wave shape and voltage,
I have feeling here this is to do with wave shape / voltage levels.
 
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!

I have not ever vetted multi-master for proper arbitration resolution. I would not be surprised if it needed some fixes in that regard. For multi-master you will want to comment out the I2C_AUTO_RETRY in the header file (i2c_t3.h). It is enabled by default and will almost certainly make things worse if a master tries to send on top of an ongoing message.

In-use the library is configured as either Master or Slave, so if you want to use only a single bus you would probably need to reconfigure as Slave when not actively transmitting. Other option is to configure one bus as Master (Wire), and other as Slave (Wire1) then tie them both to the same bus lines.
 
"When you ran the LCD with the UNO, what did you do for the 3v3 logic and power levels the LCD wants."

My previous experience are using the 5V version of this LCD with the UNO/Mega/Mega Junior, not the 3.3V version.

View attachment 5424

Sometimes ACK is OK

View attachment 5423

Sometimes it is not.

Only 0x28 is acknowledged by the LCD when it is working.

This is odd, the signaling doesn't look wrong. It is not obvious why it doesn't ACK.

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

So does the one you are having a problem with work with the UNO? And if so, is it 5V or 3.3V? What about a different rate, say 100k? Any change?
 
I have tried it on the Uno because fo the 3.3V vs 5V ratings. I need to check if this is 5V tolerant.

I also tried lower 200K and 100K but still had the same problem.

Thanks

Bruce
 
Cranky LCD

I got home and got a hold of my scope. Please see below.
Teensy SCL.JPG



Teensy SDA.JPG

Let me know if you have any ideas why this may be happening.
 
well

good news , is the signals look clean,
but they only make 3v from what I can see, is the power supply at 3v or 3v3 ?

one thing does look strange, is the scl should be high at the end of the transaction,
my best guess is that the I2C slave is using clock stretching to slow the transmission down,

would be interesting to capture the working one to contrast / compare.

also the I2C timing is critical between the scl and the sda , both on one trace would be good,
I'm sort of guessing from the glitch on the SDA that the scl is going low at the right time, but would be good to know.

The SDA is obviously going high at some point, how long is that after the last scl ?
 
one thing does look strange, is the scl should be high at the end of the transaction,
my best guess is that the I2C slave is using clock stretching to slow the transmission down,

SCL can stay low if the Master does not issue a STOP at the end (eg. I2C_NOSTOP). It allows the current Master device to keep control of the bus. IIRC clock stretching would be if the Slave device held SDA low. Although it makes me wonder, perhaps the Slave device is waiting for the STOP in order to do something (some Slaves queue up data until the STOP arrives).

Signals do look clean, try ending with a STOP. If you're not sure how to make it issue the STOP, then I'll take a more detailed look at the code later (sorry no time just at the moment).
 
IIRC clock stretching would be if the Slave device held SDA low.

Sorry I remembered that wrong. It is Slave pulling SCL low on 9th clock: http://stackoverflow.com/questions/24862372/i2c-slave-clock-stretching

This could be that. Perhaps the Slave device is confused somehow. I looked at the library code here: https://github.com/nkcelectronics/SerialLCD/blob/master/SerialLCD.cpp and there is not any code related to STOP. In fact there must be something missing. In that code, line 276, is the Wire.begin() call, just like that with no arguments, so that should default to Master and 100k mode. Where exactly are you setting 400k mode?
 
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 <i2c_t3.h> 
#include <SerialLCD.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(4,20,0x28,I2C);

void setup() {
  
  // Initialize LCD module
  Wire.setRate(I2C_RATE_400);
  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(MAX_CONTRAST);
  // Set Backlight
  lcd.setBacklightBrightness(MAX_BRIGHTNESS);
}

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(MAX_CONTRAST);
  // Set Backlight
  lcd.setBacklightBrightness(MAX_BRIGHTNESS);
  
  delay(2000);
}

It is in the Set Up code.
 
Teensy 100K_Ack.JPG

Teensy at 100K with both SCL and SDA
Teensy 400K_Ack.JPG

Teensy at 400K with both SCL and SDA

100K will acknowledge but will not display demo sketch.

Still just spinning my wheels here.

Thanks

Bruce
 
Last edited:
I'm really surprised you can even get 400k to work. The Wire.setRate() and lcd.init() are backwards. The lcd.init() is going to call Wire.begin() and undo the previous setRate() command. Try swapping the order on those two commands.

Otherwise the only suspect thing I see is that the SCL falling-edge and SDA rising-edge are very close to each other on the 9th clock. If the device internally has a lag on SCL it could be interpreting that as a STOP. It would be good to have a comparison of the UNO signal timing if that was workable (can the UNO work with a 3.3V pullup on SDA/SCL? I'm not familiar enough with it).
 
Could be your scope calibration,

but the blue scl line never reaches zero.
looks like it only makes about 0.3 volts.

if thats the case, something is seriously wrong with the wiring / pull ups.
those signals should be a hard zero.

Th arrows on the left of the plot are showing where the ground reference of each trace is as far as the scope thinks,
so they should be on top of each other.

and your only just making 3 volts, which is again strange,
its a hard pull up I can see that, but it should be making Vcc of 3v3.
again it could be the scope calibration, but your voltages look wrong to me.

if you have a DVM, measure a dc source like a battery with your scope and DVM at the same time,
ensure they both read the same voltage ,
 
I just found this thread on the MCP23017 chip. I'm new to Teensy programming but would like to use the MCP in my project to control 12 buttons. I'm starting with 4 buttons on my breadboard.

I have a Teensy 3.2 and several LC's, with an LC currently plugged into my board.

I installed the library referenced in this thread and looked at the examples, but there isn't a basic (simple) one showing how to control a button via the MCP.

I was using the code below I found in this tutorial here: http://learning.grobotronics.com/2013/07/mcp23017-input-using-i2c/

...but I could not get it to work. Nothing displays in the serial monitor when I press a button. I'm sure because of the differences in using the Teensy LC.

I am using the LC now but my project will end up using the 3.2 board, should I switch over to the 3.2 now or will MCP code work with both the LC and the 3.2? I bought several LC's to leave on my prototyping breadboards but maybe that wasn't a good idea?

Is there a reference to a basic button example for the Teensy that I can study and hopefully follow?

Thanks...

Code:
#include "Wire.h"
byte inputs=0;
void setup()
{
 Serial.begin(9600);
 Serial.println("setup");
 Wire.begin(); // wake up I2C bus
 Wire.write((byte)0x01); // set all of bank B to inputs
}
void loop()
{
 Serial.println("loop");  
 Wire.beginTransmission(0x20);
 Wire.write(0x13); // set MCP23017 memory pointer to GPIOB address
 Wire.endTransmission();
 Wire.requestFrom(0x20, 1); // request one byte of data from MCP20317
 inputs=Wire.read(); // store the incoming byte into "inputs"
 if (inputs>0) // if a button was pressed
 {
 Serial.println(inputs, BIN); // display the contents of the GPIOB register in binary
 delay(200); // for debounce
 }
}

MCP3.jpgMCP2.jpgMCP1.jpg
 
From the pictures, it does not look like you have pull-up resistors between both A4 and A5 and the power grid. On the Teensy platform you need separate pull-up resistors between the 2 i2c pins and 3.3v. 4.7K is usual amount suggested for resistors, but if you were wanting to go to higher i2c speeds, I've seen recommendations that you drop the resistance value to 2.7K. For button pressing, speed is not as big of a deal, since you are limited to human reaction times.

Other microprocessors like the Arduino Uno do not need the resistors, because their internal pull-up resistors are powerful enough, but on the Teensy, you generally need to add resistors.
 
I believe I have them there already...or is my thinking wrong? (Very good chance of that!!).

See two red arrows on left side and two red arrows on same wire on the right side with circles around the resistors.

And I need to be on the 3.3v pin, right?

MCP4.jpg
 
A number of things are wrong in the original code (eg. Wire.write() in setup() is doing nothing, no rep-START on the read, etc).

Try this code:

Code:
#include <i2c_t3.h>
uint8_t inputA=0;
uint8_t inputB=0;
uint8_t count=0;
uint8_t slave_addr = 0x20; // The address depends on the pin A2/A1/A0 connection, 0x20 assumes A2=A1=A0=GND

//
// print I2C status
//
void print_i2c_status(void)
{
    switch(Wire.status())
    {
    case I2C_WAITING:  Serial.print("I2C waiting, no errors\n"); break;
    case I2C_ADDR_NAK: Serial.print("Slave addr not acknowledged\n"); break;
    case I2C_DATA_NAK: Serial.print("Slave data not acknowledged\n"); break;
    case I2C_ARB_LOST: Serial.print("Bus Error: Arbitration Lost\n"); break;
    case I2C_TIMEOUT:  Serial.print("I2C timeout\n"); break;
    case I2C_BUF_OVF:  Serial.print("I2C buffer overflow\n"); break;
    default:           Serial.print("I2C busy\n"); break;
    }
}

//
// Init device
//
void setup()
{
    Serial.begin(9600);
    Serial.println("setup");

    // Init I2C bus
    //Wire.begin();  // this is the short form, it is functionally the same as below (using Arduino defaults for Teensy3)
    Wire.begin(I2C_MASTER, 0, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_100);  // this is the long form which shows explicitly the pins used, ext pullup, and rate 100kHz

    Wire.beginTransmission(slave_addr);  
    Wire.write(0x00);  // reg address IODIRA
    Wire.write(0xFF);  // set all pins input on BANKA
    Wire.endTransmission();  // write to Slave
    print_i2c_status();

    Wire.beginTransmission(slave_addr);
    Wire.write(0x01);  // reg address IODIRB
    Wire.write(0xFF);  // set all pins input on BANKB
    Wire.endTransmission();  // write to Slave
    print_i2c_status();
}

void loop()
{
    Wire.beginTransmission(slave_addr);  
    Wire.write(0x12);  // set MCP23017 memory pointer to GPIOA address
    Wire.endTransmission(I2C_NOSTOP);   // Write to Slave (specify I2C_NOSTOP so Read uses Repeated-START)
    Wire.requestFrom(slave_addr,2);  // request two bytes of data from MCP20317  
    if(Wire.available() >= 2)
    {
        inputA=Wire.read();  // store the incoming byte for GPIOA (Slave automatically increments addr reg)
        inputB=Wire.read();  // store the incoming byte for GPIOB
        Serial.printf("Count: %d  GPIOA: 0x%02X   GPIOB: 0x%02X\n", count, inputA, inputB);
    }
    else
    {    
        print_i2c_status();                 // print I2C final status
    }
    delay(200);
}

Note: I didn't check this other than it compiles, I do get a couple warnings on the ambiguous requestFrom() being int or uint8_t, but just ignore that (for that you can thank original Arduino libs for defining something as ambiguous 16/32 bit int which is never more than 8-bits...). I'll have to see if I can fix that warning somehow.
 
Thanks very much for the help.

Which Lib should I be using?

My compile shows:

Used: C:\Users\fresh1011\Documents\Arduino\libraries\i2c_t3
Not used: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\i2c_t3

I copied your ver 8 .zip lib file into my C:\Users\fresh1011\Documents\Arduino\libraries folder. I went to Sketch->Include Libraries and now that is what is being used. I guess that's the best one to use.

It compiles with those warnings you mentioned however nothing displays in the serial window.

I'm attaching some pics of my breadboard wiring...maybe its not wired up correctly.

I'm pretty new at using Teensy so I appreciate your patience with a newbie.
 

Attachments

  • MCP4.jpg
    MCP4.jpg
    188.7 KB · Views: 173
  • MCP1.jpg
    MCP1.jpg
    120.5 KB · Views: 227
  • MCP2.jpg
    MCP2.jpg
    185.8 KB · Views: 190
  • MCP3.jpg
    MCP3.jpg
    107.8 KB · Views: 176
It compiles with those warnings you mentioned however nothing displays in the serial window.

What do you mean by nothing? It should have displayed something, in particular something like:

Code:
setup
I2C waiting, no errors
I2C waiting, no errors
...
The first three lines are just from the setup() initialization. If you don't see that then something is wrong with your Serial window. Maybe try a different baud rate instead:
Code:
Serial.begin(115200);
 
Actually try changing the setup() like this:

Code:
void setup()
{
    Serial.begin(9600);
    while(!Serial);  // wait until serial monitor opened
    Serial.println("setup");
    ...

It might be the messages are going by before the monitor opens.
 
Unless I'm missing something, according to your picture I don't see where your pullups or device (pin9) connect to the power supply. Pullups connect to device, but there is no power connection from pin9 to 3.3V.
 
I moved my power wire over to 3.3v.

I guess this is part of my/the confusion...in searching the internet for MCP examples, everyone seems to be doing things a little bit differently, most using an Ardunio and a few using Teensy, etc.

I was using 5v because that's what I've seen in some of the examples I found online. But you're saying I have to use 3.3v?

I'm attaching a close up of my MCP pin9 and resistors. Is this what you mean?

MCP4.jpg
 
Arduino UNO uses 5v because it runs at 5v. Teensy 3.x/LC runs at 3.3v. You want to run your i2c bus at the appropriate voltage level.

If your devices can run at both 3.3v and 5v, it is simplest to just run your i2c bus at 3.3v. The raw MCP chip can run at either voltage level, but it can depend on what you hook up to the MCP.

If you have devices on the i2c bus that can only run at 5v, you need to do level shifting so that the 3.3v signals that the Teensy puts out can be read by the device, and 5v signals emitted by the device can be handled by the Teensy. The i2c bus is a bi-directional bus, so you need level shifters that can automatically deal with this. There are many level shifters out there that claim to with with i2c devices, and some actually work. Two that I've used include:


Similarly, on a 5v Arduino, if you have i2c devices that can only run at 3.3v, you would need to use the level shift to shift 5v down to 3.3v.

One of my i2c devices (a 16x2 character display) only runs at 5v, and it runs on the Teensy if I do the level shifting.
 
Last edited:
Back
Top