New I2C library for Teensy3

I'm interested in the topic, my new Teensy 4.0 cannot access I2C buses to control devices I already tested with 3.2 and 3.6.
Any news about development?
Any suggestion about how to add some modification to the last library version to make it work (even modification not very efficient) for T4.0?

Thank you anyway

Sorry, I don't have anything running on T4 at the moment. I acquired some parts, but I haven't had time to work on it. For now you will have to utilize the Wire library.
 
Not working for me; the #include <wire.h> line in the main sketch still picks up the file in C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Wire\Wire.h
 
Not working for me; the #include <wire.h> line in the main sketch still picks up the file in C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Wire\Wire.h

To use this library you need to use #include <i2c_t3.h>, not #include <wire.h>. The example files that are included demonstrate usage.
 
nox771,

Hmm, This is what I tried, something from an earlier post of yours.

Annotation 2020-05-22 103901.jpg

I have used your fine i2c_t3.h library in many other Teensy projects, but can't in this one because the various V53L0X libraries use Wire.h

Regards,

Frank
 
You can't include both <i2c_t3.h> and <Wire.h>. Include <i2c_t3.h> only.
If other libraries include <Wire.h>, the only way is replacing every Wire.h with i2c_t3.h across every source of the project/library.
 
I have used your fine i2c_t3.h library in many other Teensy projects, but can't in this one because the various V53L0X libraries use Wire.h

Here's a dirty hack that might help you to test in the short-term:

- if you're on a Windows machine, rename the offending "Wire.h" file (to something else, maybe oldWire.h")
- in place of the previous "Wire.h", create a shortcut named "Wire.h" that points to "i2c_t3.h"
- if you're on a linux machine, do a similar thing, creating a soft link instead

Mark J Culross
KD5RXT
 
Here's a dirty hack that might help you to test in the short-term:

- if you're on a Windows machine, rename the offending "Wire.h" file (to something else, maybe oldWire.h")
- in place of the previous "Wire.h", create a shortcut named "Wire.h" that points to "i2c_t3.h"
- if you're on a linux machine, do a similar thing, creating a soft link instead

Mark J Culross
KD5RXT

At least in the past you needed to define TwoWire also:
Code:
typedef i2c_t3 TwoWire;

 
Thanks for the information - that sounds a whole lot easier than trying to track down all the library references.

So, for my Windows 10 setup:

rename 'C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Wire\Wire.h' to 'C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Wire\OldWire.h'

then, in an elevated command prompt:

C:\Windows\system32>mklink /h "C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Wire\Wire.h" "C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\i2c_t3\i2c_t3.h"

Is that correct?


What happens the next time the Arduino IDE and or TeensyDuino gets updated? Does the hard link disappear and have to be re-done?
 
I would expect if you reinstall Arduino over the same files it will overwrite the link with the Wire.h file. There are many variations of this idea, including altering the contents of the file, or the file itself with a link as suggested, or somehow altering the build system. But they don't survive getting overwritten.

I don't think there is an ideal solution to trivially swapping libraries. Creating some tool to do this is a reasonable project idea though, because there are always things like display libraries and such that have a dozen variants which would be nice to pick and choose what gets used.
 
Hello,

first of all: Merry Chrismas to all :) Hope your fine.

My problem: I like to use a chip which takes it's firmware via I2C I/F. This firmware is long, longer than the buffer in the lib of i2c_t3. When I increase the buffer of the lib to 1kB and send a FW package which is about 900 bytes, everything is fine. But I need also to send FW images which are longer (about 500kB). Yes it takes a while but this is not problem. The problem is, I do not have success to send larger files than the internal buffer of the lib is.
I have no idea but I guess the chip I'm using is not handle the repeated start correctly.

Sample code (not the code I'm using):
Code:
do
{
  Wire.beginTransmission(address);
  status = Wire.write( &buf[completedLen], wrLenToSend);
  // evaluete sendStop: I2C_NOSTOP or I2C_STOP
  Wire.endTransmission(sendStop);  // sendStop is set correct, I have checked this
  status = Wire.finish(1000000L);
  if(status==0)
  {
    PRINT_ERR("i2c finish error\n");
  }
}
while(sendStop==I2C_NOSTOP);

When I send a package with 900 bytes and the lib internal buffer is 1kB, everything is fine. When I decrease the lib internal buffer to the original values (259 bytes), the loop is running 4 times. On the logic analyzer I
found the correct data, e.g.:
Code:
START,addr, <data bytes>, ACK
repeated START,addr, <data bytes>, ACK
repeated START,addr, <data bytes>, ACK
repeated START,addr, <data bytes>, ACK, STOP

But this is not working. Only this is working:
Code:
START,addr, <complete data bytes>, ACK, STOP
Now my question: how to use the lib, sending a large amount of data (longer then the internal buffer is) without the repeted start? The lib should not use it's internal buffer, send data immediatly.
I guess it is not possible in the moment but may be there is a solution (may be without this lib)?

Thank you very much for helping :)

Edit: The chip documentation does not describe the "protocol" in detail using I2C, only states, I may use the I2C IF to load and command.
Edit2: The chip I'm using has no address to initiate the FW download. Only a command "Load FW" without a target address. So on the I2C bus you see:
START, device address, n bytes of data (without target/register address), ACK, STOP.
 
Last edited:
It is a FM/DAB receiver chip SI4688 from Silabs. After reset a firmware download must made. I can only perform a complete write to the chip, the complete FW package between START and STOP without repeated START. Smaller writes are failed, the FW is not booting after.
 
You should post your actual code. I don't know much about it, but possibly use wait_idle() between partial writes.
 
Existing i2c_t3 doesn't support continuous spooling of data into the transmit buffer. It's probably not that difficult, but it would require some low level modifications.

To transmit data which exceeds the buffer size would require a customized transmit and ISR routine. Transmit would need to only preload part of the data into the buffer, and would need some mechanism to know where to get more data. Also it would require maintaining a total data count separate from the buffer index (currently the index is compared against the data count loaded in the buffer to know when to end).

It may be as simple as using a separate data count, and if the buffer index equals the buffer end, then send last byte, reset index to zero, refill buffer with new data (next ISR will then send from the beginning of the buffer). Continue for full data count.

This may be easier done using a non-interrupt based routine, like the old Wire code. That is a straightforward polling loop. As long as you can pull data from someplace you can loop as long as you want.
 
Below is the comlete function as I use it. It is working as written, the short FW package I send has about 900 bytes. I have also increased the buffer of the lib i2c_t3.
But when I change the define in my function to I2C_PACKET_LENGTH to 256 then the FW is not booting and I got no errors from I2C send functions. Then the data are send in 4 packets.
wait_idle() is nt available in this function, at least I didn't found it ;)

Code:
int32_t shieldTwi::writeTest(uint8_t address, uint8_t *buf, uint32_t writeLen )
{
#define I2C_PACKET_LENGTH (1020)
  uint8_t e=0;
  uint32_t status=0;
  uint32_t packetLen;
  uint32_t lenAlreadySend=0;
  i2c_stop sendStop;

  if(writeLen > 0)
  {
    do
    {
      packetLen= (writeLen - lenAlreadySend) > I2C_PACKET_LENGTH ? I2C_PACKET_LENGTH : writeLen - lenAlreadySend;
      if( lenAlreadySend + packetLen >= writeLen )
        sendStop = I2C_STOP;
      else
        sendStop = I2C_NOSTOP;

      Wire.beginTransmission(address);
      PRINT_MSG(1,"wrLen = %ld, complLen=%ld, sendStop=%ld, data=0x%02X\n", packetLen, lenAlreadySend, sendStop, buf[lenAlreadySend]);
      // fill up I2C buffer
      status = Wire.write( &buf[lenAlreadySend], packetLen);
      if(status != packetLen)
      {
        PRINT_ERR("i2c write error, status=%ld\n", status);
      }

      // transmit buffer
      Wire.endTransmission(sendStop);

      // update completed length
      lenAlreadySend += packetLen;

      // check for errors
      if( (e=Wire.getError()) )
      {
        // 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error (timeout, arb lost)
        switch(e)
        {
        case 1:
          PRINT_ERR("i2c wr error: data too long\n");
          break;
        case 2:
          PRINT_ERR("i2c wr error: recv addr NACK, addr: 0x%02X\n", address);
          break;
        case 3:
          PRINT_ERR("i2c wr error: recv data NACK\n");
          break;
        case 4:
          PRINT_ERR("i2c wr error: other error (timeout, arb lost)\n");
          break;
        default:
          PRINT_ERR("i2c wr error: unknown");
          break;
        }
      }
    }
    while( sendStop == I2C_NOSTOP );

  }

  return lenAlreadySend;
}
 
nox771, you wrote what I had assumed, it is not possible with the lib to send data longer than the internal buffer without a repeated start.
I need to take a look in the source further to decide if I will implement one of your proposed solutions. I do not know if the original lib for I2C does habdle the data as I want. I do not need the interrupt/DMA driven solution for my case.
Yes it's nice but.... ;)

Does the original lib using a buffer? If yes, it doesn't help :) But I will see. At least I want to nknow if I'm doing something wrong or if it is not posssible what I like to do.
Thank very much you so far :)
 
The normal Wire library also uses a fixed size buffer.

Not sure which Teensy you are using. Guessing not T4.x as last time I checked, T4 support had not yet been added to I2C_t3.

I believe by default it defaults to buffer of 32... You can probably change to larger.
However it would take more surgery to go beyond 255 as it looks like all of the counters and the like are stored in uint8_t member variables.

I wish that some of these classes would have members like: Wire.setTXBuffer(my_buffer, my_buffer_size);
It would be semi trivial to add. Alternatively could do like we did for Serial objects with the addMemory... Makes the code very slightly more complicated but not really too difficult as it is not a ring type buffer.
 
I have take a look into the "normal" Wire librray, yes it is using also a buffer. I'm using a Teensy 3.2 not the 4. But now I have verified that I can use a buffer of a few bytes more than 4kB in the i2c_t3 lib. This fits all needs as the biggest packet to send is 4kB. To upload a FW with 500kB this must be split into 4kB packets. The 900 byte packet is a bootloader patch. And I can live with a buffer of 4Kb in the lib.
 
Good that you found something that works. As I see it, your application could use less buffer space if it had something like this for all but the first and last portions:

endTransmission(omitStart, omitStop);
 
endTransmission(sendStop) is existing. But for the next transmission a beginTransmission must be used and this is sending a repeated Start on the bus. And this the chip don't like as it seems.
And the repeated START is necessary as the bus is released after the transmission for the case there is a multimaster system. So another master can request the bus.
I'm not sure if my understanding is correct in this case ;)

Of course, it is possible implementing all this things but I have a solution.
 
My understanding is that if you omit the stop, then the bus isn't released and, with your slave chip/application, the following start isn't needed/tolerated.
But the libraries don't provide a way to do this.
 
Back
Top