Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 28 1 2 3 11 ... LastLast
Results 1 to 25 of 696

Thread: New I2C library for Teensy3

  1. #1
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429

    New I2C library for Teensy3

    Hello all,

    December 2, 2018:: As below see github for the latest download and details - the ZIP below is old …
    Quote Originally Posted by nox771 View Post
    All - … uploaded a new release on GitHub:
    https://github.com/nox771/i2c_t3 … It applies some fixes and changes the license to MIT.


    This thread details an enhanced I2C library for the Teensy 3.x, and LC devices (it does not support AVR based Teensy devices). The historical content of this post has been moved to the i2c_t3_history.txt file, which is linked below. This post details usage of the library below. If anyone has problems or requests please post to this thread.

    Have fun,
    - Brian (nox771)

    ----------------------------------------------------------------------------------------------------------------------
    Download

    This library is available from GitHub at the following link, or via the attached zip download at the bottom of this post.
    https://github.com/nox771/i2c_t3

    Older releases can be found in the following archive folder on GitHub, or inside the archive folder of the attached zip download below.
    https://github.com/nox771/i2c_t3/tree/master/archive

    ----------------------------------------------------------------------------------------------------------------------
    Description

    This library is designed to operate from the Arduino/Teensyduino development system. However this is not strictly required as the files can be used independently. Recent releases of the library are bundled with the Teensyduino software available here. Follow the instructions on that page for installation.

    The library can also be downloaded separately (eg. for updates), and used by unpacking the library contents into your sketchbook/libraries folder.

    To use with existing Arduino sketches, simply change the #include <Wire.h> to #include <i2c_t3.h>

    Example sketches can be found in the Arduino menus at: File->Examples->i2c_t3

    The latest version of the library provides the following:

    • For Teensy 3.0, there is one I2C interface: Wire
    • For Teensy 3.1, 3.2, LC, there are two I2C interfaces: Wire, Wire1
    • For Teensy 3.5, there are three I2C interfaces: Wire, Wire1, Wire2
    • For Teensy 3.6, there are four I2C interfaces: Wire, Wire1, Wire2, Wire3

    ----------------------------------------------------------------------------------------------------------------------
    Pins

    Some interfaces have multiple sets of pins that they can utilize. For a given interface only one set of pins can be used at a time, but for a device configured as a bus Master the pins can be changed on-the-fly when the bus is idle.

    In functions that require a pin specification there are two ways to specify it. One is to use the pin enum as shown in the table below under "Pin Name". This will restrict the pin choices to the listed pin pairings. The other method is to specify the SCL, SDA pins directly (in that order), using any valid SCL or SDA pin given the device type and interface used. If pins are not given on initial setup then defaults are used as indicated below (based on device type and bus).

    As an example the following functions are all valid:
    Code:
    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000); // Wire bus, SCL pin 19, SDA pin 18, ext pullup, 400kHz
    Wire.begin(I2C_MASTER, 0x00, 19, 18); // equivalent to above, will default to ext pullup at 400kHz 
    Wire.begin(I2C_MASTER, 0x00, 16, 18); // similar to above, but using SCL pin 16 and SDA pin 18
    The mapping of device types, available pins, and interfaces is as follows. Note that these are not physical pin numbers, they refer to the Teensy pin assignments, which can be viewed here: https://www.pjrc.com/teensy/pinout.html

    Code:
    Interface  Devices     Pin Name      SCL    SDA   Default
    ---------  -------  --------------  -----  -----  -------
       Wire      All    I2C_PINS_16_17    16     17
       Wire      All    I2C_PINS_18_19    19*    18      +  
       Wire    3.5/3.6  I2C_PINS_7_8       7      8
       Wire    3.5/3.6  I2C_PINS_33_34    33     34
       Wire    3.5/3.6  I2C_PINS_47_48    47     48
      Wire1       LC    I2C_PINS_22_23    22     23      +
      Wire1    3.1/3.2  I2C_PINS_26_31    26     31
      Wire1    3.1/3.2  I2C_PINS_29_30    29     30      +
      Wire1    3.5/3.6  I2C_PINS_37_38    37     38      +
      Wire2    3.5/3.6  I2C_PINS_3_4       3      4      +
      Wire3      3.6    I2C_PINS_56_57    57*    56      +
    Note: in almost all cases SCL is the lower pin #, except cases marked *

    On some devices the pins for the 2nd and higher number buses (Wire1, Wire2, Wire3) may reside on surface mount backside pads. It is recommended to use a breakout expansion board to access those, as the pads are likely not mechanically robust, with respect to soldered wires pulling on them. There are a number of breakout boards for this purpose such as these:


    ----------------------------------------------------------------------------------------------------------------------
    Pullups

    The I2C bus is a two-wire interface where the SDA and SCL are active pulldown and passive pullup (resistor pullup). When the bus is not communicating both line voltages should be at the high level pullup voltage.

    The pullup resistor needs to be low-enough resistance to pull the line voltage up given the capacitance of the wire and the transfer speed used. For a given line capacitance, higher speed transfers will necessitate a lower resistance pullup in order to make the rising-edge rate faster. Generally the falling-edge rates are not a problem since the active pulldowns (typically NMOS) are usually quite strong. This article illustrates the effect of varying pullup resistance:
    http://dsscircuits.com/articles/86-a...l-up-resistors

    However, if an excessively low resistance is used for the pullups then the pulldown devices may not be able to pull the line voltage low enough to be recognized as an low-level input signal. This can sometimes occur if multiple devices are connected on the bus, each with its own internal pullup. TI has a whitepaper on calculating pullup resistance here:
    http://www.ti.com/lit/an/slva689/slva689.pdf

    In general, for a majority of simple I2C bus configurations a pullup resistance value in the range of 2k to 5k Ohms should work fine.

    Teensy Pullups

    Due to the situation with internal pullups, it is recommended to use external pullups for all devices in all cases (except in special cases for the 3.0/3.1/3.2 devices).

    Regarding the Teensy devices, the library provides an option to use either internal pullups or external pullups (by specifiying I2C_PULLUP_INT or I2C_PULLUP_EXT on the bus configuration functions). For most cases external pullups, I2C_PULLUP_EXT, is the preferred connection simply because it is easier to configure the bus for a particular resistance value, and for a particular pullup voltage (not necessarily the same as the device voltages, more below). Note, when using external pullups all devices should be configured for external.

    That said, sometimes internal pullups, I2C_PULLUP_INT, are used to simplify wiring or for simple test scenarios. When using internal pullups, generally only one device is configured for internal (typically the Master), and Slave devices are configured for external (since they rely on the Master device to pullup). It is possible to have multiple devices configured for internal on the same bus, as long as the aggregate pullup resistance does not become excessively low (the resistances will be in parallel so the aggregate will be less than the lowest value).

    The internal pullup resistances of the Teensy devices are as follows:
    • Teensy LC - ~44k Ohms
    • Teensy 3.0/3.1/3.2 - ~190 Ohms (this is believed to be a HW bug)
    • Teensy 3.5 - ~150 Ohms (this is believed to be a HW bug)
    • Teensy 3.6 - ~25 Ohms (this is believed to be a HW bug)

    None of these internal pullups is a particularly good value.

    The Teensy 3.0/3.1/3.2 value of ~190 Ohms is very strong (it is believed to be a HW bug), however in most cases it can work fine on a short bus with a few devices. It will work at most any speed, including the max library speeds (eg. breadboard with 3.0/3.1/3.2 device and a few Slave devices usually works fine with internal pullups). That said, multiple devices configured for internal pullups on the same bus will not work well, as the line impedance will be too low. If using internal pullups make sure at most one device is internal and the rest are external.

    On the other hand, the Teensy LC value of ~44k Ohms is very weak. An LC configured for internal will have trouble running at high speeds in all configurations.

    The Teensy 3.6 internal pullup is essentially a short, and is unusable.

    Pullup Voltages

    Some consideration should be given when connecting 3.3V and 5V devices together on a common I2C bus. The bus voltage should be one or the other, and there should not be multiple pullups connecting to different voltages on a single line.

    The voltage tolerance is as follows:
    Code:
    Voltage    Devices
    -------  -----------
      3.3V   3.0, 3.6, LC
      5.0V   3.1, 3.2, 3.5
    Sometimes devices supplied at 5V will communicate fine if the I2C bus is at 3.3V, because the logic high/low thresholds are biased towards ground more than supply. However if a 5V device truly requires a 5V I2C signal, whereas other devices on the bus require 3.3V signal, there is a method to accomplish this.

    To connect 5V devices to 3.3V tolerant Teensy or to connect multiple voltage level I2C buses, refer to the following app note by NXP:
    http://www.nxp.com/documents/applica...te/AN10441.pdf

    There are also many bidirectional I2C level-shifter ICs and breakout boards on the market which can simplify building such connections. Many implement exactly what is shown in the NXP app note.

    ----------------------------------------------------------------------------------------------------------------------
    Clocking

    The library now supports arbitrary I2C clock rate frequencies, which can be specified directly, eg. 400000 for 400kHz. The I2C clock rate is set via a divide ratio from the F_BUS frequency (except for Wire1 bus on LC device which uses F_CPU). There is a fixed list of divide ratios available, and the library will choose the nearest available ratio when attempting to produce a requested I2C rate.

    The maximum I2C rate is 1/20th of F_BUS. Some examples relating F_CPU, F_BUS, and max I2C rate are below (actual device configuration depends on compile settings):
    Code:
         F_CPU      F_BUS     Max I2C
         (MHz)      (MHz)       Rate
     -------------  -----    ----------
        240/120      120        6.0M    bus overclock
          216        108        5.4M    bus overclock
         192/96       96        4.8M    bus overclock
          180         90        4.5M    bus overclock
          240         80        4.0M    bus overclock
       216/144/72     72        3.6M    bus overclock
          192         64        3.2M    bus overclock
      240/180/120     60        3.0M
          168         56        2.8M
          216         54        2.7M
     192/144/96/48    48        2.4M
           72         36        1.8M
           24         24        1.2M
           16         16        800k
            8          8        400k
            4          4        200k
            2          2        100k
    Previous library releases used I2C_RATE_xxxx enums. This is still supported, but is now deprecated, and specifying the frequency directly (as a uint32_t value) is now the preferred method.

    Allowable I2C_RATE_xxxx enum list is as follows:
    • I2C_RATE_100, I2C_RATE_200, I2C_RATE_300, I2C_RATE_400, I2C_RATE_600, I2C_RATE_800, I2C_RATE_1000, I2C_RATE_1200, I2C_RATE_1500, I2C_RATE_1800, I2C_RATE_2000, I2C_RATE_2400, I2C_RATE_2800, I2C_RATE_3000

    Note that at high speeds the specified clock is not necessarily equivalent to actual SCL clock speeds. The peripheral limits the actual SCL speeds to well below the theoretical speeds (both in terms of actual bit clock frequency and throughput rates).

    To get a better idea of throughput the transfer time for a 128 byte transfer across different F_CPU/F_BUS/I2C Rate combinations has been measured on a Teensy 3.1 device. This behavior generally applies to all devices. This is shown below.

    Click image for larger version. 

Name:	screenshot.391.jpg 
Views:	7809 
Size:	106.4 KB 
ID:	3343

    ----------------------------------------------------------------------------------------------------------------------
    Operational Modes

    There are three modes of operation: Interrupt, DMA, and Immediate. The operating mode of the I2C can be set in the begin() or setOpMode() functions, using the opMode parameter which can have the following values:
    • I2C_OP_MODE_ISR - Interrupt
    • I2C_OP_MODE_DMA - DMA
    • I2C_OP_MODE_IMM - Immediate

    Interrupt mode is the normal default mode (it was the only mode in library versions prior to v7). It supports both Master and Slave operation. The two other modes, DMA and Immediate, are for Master operation only.

    DMA mode requires an available DMA channel to operate. In cases where DMA mode is specified, but there are no available channels, then the I2C will revert to operating in Interrupt mode.

    Similarly, for Interrupt mode to work the I2C ISRs must run at a higher priority than the calling function. Where this is not the case, the library will first attempt to elevate the priority of the I2C ISR to a higher priority than the calling function. If that is not possible then it will revert to operating in Immediate mode.

    ----------------------------------------------------------------------------------------------------------------------
    Example List

    Examples are divided into two categories, basic and advanced. Basic examples are demonstrate basic "Arduino-like" function of the library. Advanced examples demonstrate more complex scenarios, such as multi-bus, concurrent Master/Slave, and background transfer (ISR or DMA) operations.

    • basic_master - this creates a Master device which is setup to talk to the Slave device given in the basic_slave sketch.
    • basic_master_mux - this creates a Master device which can communicate using the Wire bus on two sets of pins, and change pins on-the-fly. This type of operation is useful when communicating with Slaves with fixed, common addresses (allowing one common-address Slave on each set of pins).
    • basic_master_callback - this creates a Master device which acts similar to the basic_master sketch, but it uses callbacks to handle transfer results and errors.
    • basic_slave - this creates a Slave device which responds to the basic_master sketch.
    • basic_slave_range - this creates a Slave device which will respond to a range of I2C addresses. A function exists to obtain the Rx address, therefore it can be used to make a single device act as multiple I2C Slaves.
    • basic_scanner - this creates a Master device which will scan the address space and report all devices which ACK. It only scans the Wire bus.
    • basic_interrupt - this creates a Master device which is setup to periodically read/write from a Slave device using a timer interrupt.
    • basic_echo - this creates a device which listens on Wire1 and then echos that incoming data out on Wire. It demonstrates non-blocking nested Wire calls (calling Wire inside Wire1 ISR).
    • advanced_master - this creates a Master device which is setup to talk to the Slave device given in the advanced_slave sketch. It adds a protocol layer on-top of basic I2C communication and has a series of more complex tests.
    • advanced_slave - this creates a Slave device which responds to the advanced_master sketch. It responds to a protocol layer on-top of basic I2C communication.
    • advanced_scanner - this creates a Master device which will scan the address space and report all devices which ACK. It scans all existing I2C buses.
    • advanced_loopback - this creates a device using one bus as a Master (Wire) and all other buses as Slaves. When all buses are wired together (loopback) it creates a closed test environment, which is particularly useful for Master/Slave development on a single device.

    ----------------------------------------------------------------------------------------------------------------------
    Header Defines

    These defines can be modified at the top of the i2c_t3.h file.

    I2C_BUS_ENABLE n - this controls how many buses are enabled. When set as "I2C_BUS_ENABLE 1" only Wire will be active and code/ram size will be reduced. When set as "I2C_BUS_ENABLE 2" then both Wire and Wire1 will be active and code/ram usage will be increased. Specifying a higher number of buses than exists is allowed, as it will be automatically limited by what is available on the device. The default is "I2C_BUS_ENABLE 4", to enable all buses on all devices by default.

    I2C_TX_BUFFER_LENGTH n
    I2C_RX_BUFFER_LENGTH n
    - these two defines control the buffers allocated to transmit/receive functions. When dealing with Slaves which don't need large communication (eg. sensors or such), these buffers can be reduced to a smaller size. Buffers should be large enough to hold: Target Addr + Data payload. Default is: 259 bytes = 1 byte Addr + 258 byte Data, as that is what some examples use.

    I2Cx_INTR_FLAG_PIN p - these defines make the specified pin high whenever the I2C interrupt occurs (I2C0 == Wire, I2C1 == Wire1, and so on). This is useful as a trigger signal when using a logic analyzer. By default they are undefined (commented out).

    I2C_AUTO_RETRY - this define is used to make the library automatically call resetBus() if it has a timeout while trying to send a START. This is useful for clearing a hung Slave device from the bus. If successful it will try again to send the START, and proceed normally. If not then it will exit with a timeout. Note - this option is NOT compatible with multi-master buses. By default it is disabled.

    I2C_ERROR_COUNTERS - uncomment to make the library track error counts. Error counts can be retrieved or zeroed using the getErrorCount() and zeroErrorCount() functions respectively. When included, errors will be tracked on the following (Master-mode only): Reset Bus (auto-retry only), Timeout, Addr NAK, Data NAK, Arb Lost, Bus Not Acquired, DMA Errors. By default error counts are enabled.

    I2C_DISABLE_PRIORITY_CHECK - uncomment to entirely disable auto priority escalation. Normally priority escalation occurs to ensure I2C ISR operates at a higher priority than the calling function (to prevent ISR stall if the calling function blocks). Uncommenting this will disable the check and cause I2C ISR to remain at default priority. It is recommended to disable this check and manually set ISR priority levels when using complex configurations. By default priority checks are enabled (this define is commented out).

    ----------------------------------------------------------------------------------------------------------------------
    Function Summary

    The functions are divided into two classifications:
    • Black functions are compatible with the original Arduino Wire API. This allows existing Arduino sketches to compile without modification.
    • Green functions are the added enhanced functions. They utilize the advanced capabilities of the Teensy 3.0/3.1 hardware. The library provides the greatest benefit when utilizing these functions (versus the standard Wire library).
    • '^' indicates optional function arguments. When not specified default values will be used.

    Wire.begin(); - initializes I2C as Master mode, external pullups, 100kHz rate, and default pin setting
    return: none
    • default pin setting SCL/SDA:
    • - Wire: 19/18
    • - Wire1: 29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)
    • - Wire2: 3/4 (3.5/3.6)
    • - Wire3: 57/56 (3.6)

    Wire.begin(address); - initializes I2C as Slave mode using address, external pullups, 100kHz rate, and default pin setting

    return: none
    parameters:
    • address = 7bit slave address of device
    • default pin setting SCL/SDA:
    • - Wire: 19/18
    • - Wire1: 29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)
    • - Wire2: 3/4 (3.5/3.6)
    • - Wire3: 57/56 (3.6)

    Wire.begin(mode, address1, ^(pins_enum | pinSCL,pinSDA), ^pullup, ^rate, ^opMode);
    Wire.begin(mode, address1, ^address2, ^(pins_enum | pinSCL,pinSDA), ^pullup, ^rate, ^opMode);
    - these various forms initialize I2C as a Master or Slave device. When two addresses are used it will initialize an address-range Slave. Addresses are ignored for Master mode (however Master-mode must specify at least one 0x00 address placeholder to also specify pins/pullup/rate/opMode options).
    return: none
    parameters:
    • mode = I2C_MASTER, I2C_SLAVE
    • address1 = 1st 7bit address for specifying Slave address (ignored for Master mode)
    • ^address2 = 2nd 7bit address for specifying Slave address range (ignored for Master mode)
    • ^pins = pin setting to use, refer to Pins Section above. Can be specified as either of the following:
    • - pins_enum
    • - pinSCL, pinSDA
    • ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)
    • ^rate = frequency of I2C clock to use in Hz, eg. 400000 for 400kHz. Can also be specified as a I2C_RATE_xxxx enum (deprecated), refer to Clocking Section above. (default 400kHz)
    • ^opMode = I2C_OP_MODE_ISR, I2C_OP_MODE_DMA, I2C_OP_MODE_IMM. Optional setting to specify operating mode (ignored for Slave mode, defaults ISR mode)

    Wire.setOpMode(opMode); - this configures operating mode of the I2C as either Immediate, ISR, or DMA. By default Arduino-style begin() calls will initialize to ISR mode. This can only be called when the bus is idle (no changing mode in the middle of Tx/Rx). Note that Slave mode can only use ISR operation.
    return: 1=success, 0=fail (bus busy)
    parameters:
    • opMode = I2C_OP_MODE_ISR, I2C_OP_MODE_DMA, I2C_OP_MODE_IMM

    Wire.setClock(i2cFreq); - reconfigures I2C frequency divider to get desired I2C frequency.
    return: none
    parameters:
    • i2cFreq = i2cFreq = desired I2C frequency in Hz, eg. 400000 for 400kHz

    Wire.getClock(); - return current I2C clock setting (may differ from set frequency due to divide ratio quantization)
    return: bus frequency in Hz

    Wire.setRate(busFreq, rate);
    - reconfigures I2C frequency divider based on supplied bus freq and desired rate. Rate is specified as a direct frequency value in Hz. The function will accept I2C_RATE_xxxx enums, but that form is now deprecated.
    return: 1=success, 0=fail (function can no longer fail, it will auto limit at min/max bounds)
    parameters:
    • busFreq = bus frequency, typically F_BUS unless reconfigured
    • rate = frequency of I2C clock to use in Hz, eg. 400000 for 400kHz. Can also be specified as a I2C_RATE_xxxx enum (deprecated), refer to Clocking Section above

    Wire.pinConfigure( (pins_enum | pinSCL,pinSDA), ^pullup); - reconfigures active I2C pins on-the-fly (only works when bus is idle). Inactive pins will switch to input mode.
    return: 1=success, 0=fail
    parameters:
    • pins = pin setting to use, refer to Pins Section above. Can be specified as either of the following:
    • - pins_enum
    • - pinSCL, pinSDA
    • ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)

    Wire.setSCL(pin); - change the SCL pin
    Wire.setSDA(pin); - change the SDA pin
    return: none
    parameters:
    • pin - pin setting to use, refer to Pins Section above.

    Wire.getSCL(); - get the current SCL pin
    Wire.getSDA();
    - get the current SDA pin
    return: pin used

    Wire.getClock(); - return current I2C clock setting (may differ from set frequency due to divide ratio quantization)
    return: bus frequency in Hz

    Wire.setDefaultTimeout(timeout); - sets the default timeout applied to all function calls which do not explicitly set a timeout. The default is initially zero (infinite wait). Note that timeouts do not currently apply to background transfers, sendTransmission() and sendRequest().
    return: none
    parameters:
    • timeout = timeout in microseconds

    Wire.resetBus(); - this is used to try and reset the bus in cases of a hung Slave device (typically a Slave which is stuck outputting a low on SDA due to a lost clock). It will generate up to 9 clocks pulses on SCL in an attempt to get the Slave to release the SDA line. Once SDA is released it will restore I2C functionality.
    return: none

    Wire.beginTransmission(address); - initialize Tx buffer for transmit to Slave at address
    return: none
    parameters:
    • address = target 7bit slave address

    Wire.endTransmission(^i2c_stop, ^timeout); - blocking routine, transmits Tx buffer to Slave. i2c_stop parameter can be optionally specified to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). timeout parameter can also be optionally specified.
    return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error
    parameters:
    • ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)
    • ^timeout = timeout in microseconds (default 0 = infinite wait)

    Wire.sendTransmission(^i2c_stop); - non-blocking routine, starts transmit of Tx buffer to slave. i2c_stop parameter can be optionally specified to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use done(), finish(), or onTransmitDone() callback to determine completion and status() to determine success/fail. Note that sendTransmission() does not currently support timeouts (aside from initial bus acquisition which does support it).
    return: none
    parameters:
    • ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)

    Wire.requestFrom(address, length, ^i2c_stop, ^timeout); - blocking routine with timeout, requests length bytes from Slave at address. Receive data will be placed in the Rx buffer. i2c_stop parameter can be optionally specified to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). timeout parameter can also be optionally specified.
    return: #bytes received = success, 0=fail
    parameters:
    • address = target 7bit slave address
    • length = number of bytes requested
    • ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)
    • ^timeout = timeout in microseconds (default 0 = infinite wait)

    Wire.sendRequest(address, length, ^i2c_stop); - non-blocking routine, starts request for length bytes from slave at address. Receive data will be placed in the Rx buffer. i2c_stop parameter can be optionally specified to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use done(), finish() or onReqFromDone() callback to determine completion and status() to determine success/fail.
    return: none
    parameters:
    • address = target 7bit slave address
    • length = number of bytes requested
    • ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)

    Wire.getError(); - returns "Wire" error code from a failed Tx/Rx command
    return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error

    Wire.status(); - returns current status of I2C (enum return value)
    return:
    • I2C_WAITING
    • I2C_TIMEOUT
    • I2C_ADDR_NAK
    • I2C_DATA_NAK
    • I2C_ARB_LOST
    • I2C_BUF_OVF
    • I2C_NOT_ACQ
    • I2C_DMA_ERR
    • I2C_SENDING
    • I2C_SEND_ADDR
    • I2C_RECEIVING
    • I2C_SLAVE_TX
    • I2C_SLAVE_RX

    Wire.done(); - returns simple complete/not-complete value to indicate I2C status
    return: 1=Tx/Rx complete (with or without errors), 0=still running

    Wire.finish(^timeout); - blocking routine, loops until Tx/Rx is complete. timeout parameter can be optionally specified.
    return: 1=Tx/Rx complete (Tx or Rx completed, no error), 0=fail (NAK, timeout or Arb lost)
    parameters:
    • ^timeout = timeout in microseconds (default 0 = infinite wait)

    Wire.write(data); - write data byte to Tx buffer
    return: #bytes written = success, 0=fail
    parameters:
    • data = data byte

    Wire.write(data_array, count); - write count number of bytes from data array to Tx buffer
    return: #bytes written = success, 0=fail
    parameters:
    • data_array = pointer to uint8_t (or char) array of data
    • count = number of bytes to write

    Wire.available(); - returns number of remaining available bytes in Rx buffer
    return: #bytes available

    Wire.read(); - returns next data byte (signed int) from Rx buffer
    return: data, -1 if buffer empty

    Wire.read(data_array, count); - read count number of bytes from Rx buffer to data array
    return: #bytes read
    parameters:
    • data_array = pointer to uint8_t (or char) array of data
    • count = number of bytes to read

    Wire.peek(); - returns next data byte (signed int) from Rx buffer without removing it from Rx buffer
    return: data, -1 if buffer empty

    Wire.readByte(); - returns next data byte (uint8_t) from Rx buffer
    return: data, 0 if buffer empty

    Wire.peekByte(); - returns next data byte (uint8_t) from Rx buffer without removing it from Rx buffer
    return: data, 0 if buffer empty

    Wire.flush(); - does nothing

    Wire.getRxAddr(); - returns target address of incoming I2C command. Used for Slaves operating over an address range.
    return: rxAddr of last received command

    Wire.onTransmitDone(function); - used to set Master Tx complete callback. Function must be of the form void function(void), refer to code examples

    Wire.onReqFromDone(function); - used to set Master Rx complete callback. Function must be of the form void function(void), refer to code examples

    Wire.onReceive(function); - used to set Slave Rx callback. Function must be of the form void function(size_t len), refer to code examples

    Wire.onRequest(function); - used to set Slave Tx callback. Function must be of the form void function(void), refer to code examples

    Wire.onError(function); - used to set callback for bus Tx/Rx errors (Master-mode only). Function must be of the form void function(void), refer to code examples

    Wire.getErrorCount(counter); - Get error count from specified counter.
    Wire.zeroErrorCount(counter); - Zero error count of specified counter.
    return: error count / none
    parameters:
    • counter
      • I2C_ERRCNT_RESET_BUS
      • I2C_ERRCNT_TIMEOUT
      • I2C_ERRCNT_ADDR_NAK
      • I2C_ERRCNT_DATA_NAK
      • I2C_ERRCNT_ARBL
      • I2C_ERRCNT_NOT_ACQ
      • I2C_ERRCNT_DMA_ERR


    ----------------------------------------------------------------------------------------------------------------------
    Compatible Libraries

    These are libraries which are known to be compatible with this I2C library. They may have been possibly modified to utilize enhanced functions (higher speed, timeouts, etc), or perhaps for general compatibility. Please contact their respective authors for questions regarding their usage.


    ----------------------------------------------------------------------------------------------------------------------
    Edits/Changelog

    Uploaded i2c_t3_lib_and_sketch_v2.zip
    • It adds a pinConfigure() function for reconfiguring pins on-the-fly (only possible when bus is not busy).

    Uploaded i2c_t3_lib_and_sketch_v3.zip
    • Adds timeout functions for endTransmission(), requestFrom(), finish() and additional baud rates for 200kHz and 300kHz.

    Uploaded i2c_t3_lib_and_sketch_v4.zip
    • Reworked ISR timeout code to better handle ending slave communication in the middle of Rx

    Uploaded i2c_t3_lib_and_sketch_v5.zip
    • Zip file structure changed to Arduino standard format. Unpack zip contents to sketchbook/libraries folder. Example sketches can be found from Arduino menus at: File->Examples->i2c_t3
    • Debug routines now use IntervalTimer and are completely defined in library code
    • New Slave mode added to support address ranges, and new getRxAddr() function added for use in that mode
    • New example sketches added: slave_range and scanner
    • Fixed bugs in ISR timeout code and Slave-mode sda_rising_isr attach

    Uploaded i2c_t3_lib_and_sketch_v6.zip
    • Added Teensy 3.1 support, including Wire1 (I2C1) interface on pins 29/30 and 26/31.
    • All new code structure used to maximize function sharing between the two buses. For single bus configuration the code/ram size change is minimal relative to v5 library on Teensy 3.0.
    • Added new header defines to control number of enabled buses and interrupt flags.
    • Fixed some bugs in ISR code with respect to very high speed transfers.
    • Added new example sketches for Teensy 3.1: quad_master and dual_bus_master_slave

    Uploaded i2c_t3_lib_and_sketch_v6b.zip
    • Fixed i2c_t3.h header - commented out interrupt pin defines (I2Cx_INTR_FLAG_PIN)

    Uploaded i2c_t3_lib_and_sketch_v7.zip
    • Added support for F_BUS frequencies: 60MHz, 56MHz, 48MHz, 36MHz, 24MHz, 16MHz, 8MHz, 4MHz, 2MHz
    • Added new rates: I2C_RATE_1800, I2C_RATE_2800, I2C_RATE_3000
    • Added new priority escalation - in cases where I2C ISR is blocked by having a lower priority than calling function, the I2C will either adjust I2C ISR to a higher priority, or switch to Immediate mode as needed.
    • Added new operating mode control - I2C can be set to operate in ISR mode, DMA mode (Master only), or Immediate Mode (Master only)
    • Added new begin() functions to allow setting the initial operating mode:
    • - begin(i2c_mode mode, uint8_t address, i2c_pins pins, i2c_pullup pullup, i2c_rate rate, i2c_op_mode opMode)
    • - begin(i2c_mode mode, uint8_t address1, uint8_t address2, i2c_pins pins, i2c_pullup pullup, i2c_rate rate, i2c_op_mode opMode)
    • Added new functions:
    • - uint8_t setOpMode(i2c_op_mode opMode) - used to change operating mode on the fly (only when bus is idle)
    • - void sendTransmission() - non-blocking Tx with implicit I2C_STOP, added for symmetry with endTransmission()
    • - uint8_t setRate(uint32_t busFreq, i2c_rate rate) - used to set I2C clock dividers to get desired rate, i2c_rate argument
    • - uint8_t setRate(uint32_t busFreq, uint32_t i2cFreq) - used to set I2C clock dividers to get desired SCL freq, uint32_t argument (quantized to nearest i2c_rate)
    • Added new Wire compatibility functions:
    • - void setClock(uint32_t i2cFreq) - (note: degenerate form of setRate() with busFreq == F_BUS)
    • - uint8_t endTransmission(uint8_t sendStop)
    • - uint8_t requestFrom(uint8_t addr, uint8_t len)
    • - uint8_t requestFrom(uint8_t addr, uint8_t len, uint8_t sendStop)
    • Fixed bug in Slave Range code whereby onRequest() callback occurred prior to updating rxAddr instead of after
    • Removed I2C1 defines (now included in kinetis.h)
    • Removed all debug code (eliminates rbuf dependency)

    Uploaded i2c_t3_lib_and_sketch_v8.zip
    • Added support for Teensy LC:
    • - fully supported (Master/Slave modes, IMM/ISR/DMA operation)
    • - Wire: pins 16/17 or 18/19 (rate limited to I2C_RATE_1200)
    • - Wire1: pins 22/23 (rate limited to I2C_RATE_2400)
    • Added timeout on acquiring bus (prevents lockup when bus cannot be acquired, eg. stuck Slave)
    • Added setDefaultTimeout() function for setting default timeout to apply to all commands
    • Added resetBus() function for toggling SCL to release a stuck Slave device
    • Added setRate(rate) function, does not require specifying bus frequency
    • Added I2C_AUTO_RETRY user define

    Uploaded i2c_t3_lib_and_sketch_v8.1.zip
    • Patched setOpMode() function for T3.0 device

    Uploaded i2c_t3_lib_v9.zip
    • Added support for Teensy 3.5/3.6:
    • - fully supported (Master/Slave modes, IMM/ISR/DMA operation)
    • - supports all available pin/bus options on Wire/Wire1/Wire2/Wire3
    • Fixed LC slave bug, whereby it was incorrectly detecting STOPs directed to other slaves
    • I2C rate is now set by directly specifying frequency. I2C rate enums are no longer needed and their use is now deprecated.
    • Archive folder has been added which contains all prior releases

    Uploaded i2c_t3_lib_v9_1.zip
    • Bugfixes:
    • - Removed I2C_F_DIV120 setting
    • - I2C_AUTO_RETRY disabled by default

    Uploaded i2c_t3_lib_v9_2.zip
    • Improved resetBus() function to reset C1 state

    Uploaded i2c_t3_lib_v9_3.zip
    • Fixed Slave ISR bug on LC/3.5/3.6 devices

    Uploaded i2c_t3_lib_v9_4.zip
    • Fixed Slave ISR for LC/3.5/3.6 not properly recognizing RepSTART
    • Fixed nested Wire calls during Slave ISR receive (calling Wire inside Wire1 Slave ISR)
    • Added uint8_t and char array read functions - Wire.read(databuf, count);
    • Updated examples to demonstrate read/write array functions
    • Added basic_echo example

    Uploaded i2c_t3_lib_v10_0.zip
    • Unbound SCL/SDA pin assignment. Pins can be specified with either i2c_pins enum or by direct SCL,SDA pin definition (using any valid SCL and SDA pin). New function summary is:
    • - begin(mode, address1, pinSCL, pinSDA, i2c_pullup, rate, i2c_op_mode)
    • - pinConfigure(pinSCL, pinSDA, pullup)
    • - setSCL(pin)
    • - setSDA(pin)
    • - getSCL()
    • - getSDA()
    • Note: internal to i2c structure, currentPins has been replaced by currentSCL and currentSDA
    • Added Master callback functions (works for sendTransmission/sendRequest, and also endTransmission/requestFrom):
    • - onTransmitDone(function) - where function() is called when Master Transmit is complete
    • - onReqFromDone(function) - where function() is called when Master Receive is complete
    • - onError(function) - where function() is called upon any I2C bus error
    • Added error counters which may be optionally enabled via I2C_ERROR_COUNTERS define.
    • - i2c_err_count enum, getErrorCount(), and zeroErrorCount() functions added
    • Default assignments have been added to many functions for pins/pullup/rate/op_mode, so many parameters are now optional
    • Fixed blocking conditions that could occur in immediate mode

    Uploaded i2c_t3_lib_v10_1.zip
    • Added User #define to disable priority checks entirely
    • Added flag to dynamically disable priority checks during ISR & callbacks
    Attached Files Attached Files
    Last edited by defragster; 12-02-2018 at 09:09 PM. Reason: edited to note github Update

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    28,461
    Nice. I've added a link to this topic on the Wire library page.

    http://www.pjrc.com/teensy/td_libs_Wire.html

    Hopefully that will help people find this and use your version. Maybe at some point it should have a dedicated page?

  3. #3
    Member
    Join Date
    Dec 2012
    Location
    Adelaide, SA
    Posts
    70
    Thanks for this.

    I'm using I2C to 'network' two Teensy3s in my project, and I have been manually changing the pins and speed, but this will be much cleaner.

    Async transfers will be nice, also.

  4. #4
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    Sure, hope it works for everyone. Originally I also wanted to make it use DMA, but I ran out of time. Maybe in the future I can get that into it.

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    Good library!

    The library is called i2c_t3
    For a better name that users can relate to "FastWire.h" After all, you did increase the bit-rate up pass the normal bit-rate values.

    What size pull-ups did you use for your high speed testing?

  6. #6
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    When I ran my debug tests, I was using just the internal pullups (approx 190 ohms). I wasn't sure the Teensy3 pulldown capability would be strong enough to work with that, but in fact on the scope I was getting around 3Vpp swings (IIRC, maybe even a bit more), and the edges were pretty square. There is a cost of course, when the bus lines are low, each wire is dumping 15mA or so, but unless it gets stuck in that state it is just transient.

    As far as the name I used i2c_t3 just because it is Teensy3 specific. There is no AVR code in it, so a generic name didn't seem appropriate. I'm not familiar with Arduino library conventions though, so maybe it doesn't matter.

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    I was using just the internal pullups (approx 190 ohms).
    So the I2C recommended pullups are from 4.7K to 10K. (10k used for the higher bit-rates) And you are only using 190 ohms pullups? Something is not quite right!
    Last edited by t3andy; 03-15-2013 at 08:05 PM.

  8. #8
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    The I2C internal pullups are messed up in this part. This was noted on the original TwoWire code also. In non-I2C mode if the pins are configured for pullups they have reasonably high impedance, but when you switch on I2C it becomes a low impedance.

    The resistance amount is kind of weird, it's really too high for just the on-resistance of the I/O FET and perhaps some ESD series R. You can actually get it even lower than 190 ohms using the high drive option. But even then it's still too high for a I/O driver on-resistance. It looks to me like someone used the wrong doping on the pullup resistors for that block (eg. they used silicided poly instead of high-R poly, perhaps a mask screwup).

    In any event the bus can run with low resistance pullups just fine, as long as the current drain isn't a problem and the slave pulldowns are strong enough.

  9. #9
    Senior Member Constantin's Avatar
    Join Date
    Nov 2012
    Location
    In the yard with a 17' Dia. Ferris Wheel
    Posts
    1,406
    Quote Originally Posted by t3andy View Post
    So the I2C recommended pullups are from 4.7K to 10K. (10k used for the higher bit-rates) And you are only using 190 ohms pullups? Something is not quite right!
    I thought smaller resistors were needed for faster pullups. See the research Nick Gammon posted near the bottom of his I2C page. I regularly use 2k2 resistors on my I2C buses based on this research. By comparison, the 10K 'square' pulses are look more like shark fins!

  10. #10
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    Yep, the lower the better.
    A much better explanation...
    http://dsscircuits.com/articles/effe...resistors.html
    Last edited by t3andy; 03-17-2013 at 01:59 PM.

  11. #11
    Junior Member
    Join Date
    Mar 2013
    Posts
    5
    I have an application where I need to use both I2C buses (interfacing two I2C devices that have the same address, so I assume they can't be on the same bus). Looking at the number of static private variables in the Wire/i2c_t3 classes, I'm guessing it was written when there was only one I2C bus. Is there some way to make this work, e.g. adding a method to set the currentPins member, or maybe calling begin() before reading, or would this involve moving all the stuff that's static into instance variables?

  12. #12
    Senior Member
    Join Date
    Nov 2012
    Posts
    412
    I have an application where I need to use both I2C buses (interfacing two I2C devices that have the same address
    What you need is a I2C multiplexer ...
    Attached Files Attached Files

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    28,461
    If you're going to use a mux, a 74HC4052 might be cheapest option...

  14. #14
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    Quote Originally Posted by ggood View Post
    Looking at the number of static private variables in the Wire/i2c_t3 classes, I'm guessing it was written when there was only one I2C bus. Is there some way to make this work, e.g. adding a method to set the currentPins member, or maybe calling begin() before reading, or would this involve moving all the stuff that's static into instance variables?
    It's important to understand there is only one I2C block in the part. The different pin configurations are only internal muxing to the same I2C. Understanding that however, it seems possible to do this by reconfiguring the pins, but you have to be a bit clever about it. Since the I2C hardware partially knows the state of the bus (busy, not busy, Tx/Rx, etc), you should only do this while the bus is idle (not busy).

    I've managed to get a test of this working. I've added a function to the code:
    Code:
    //
    // Configure I2C pins - only works when the bus is in a non-busy state
    // return: 1=success, 0=fail (bus busy)
    //
    uint8_t i2c_t3::pinConfigure(i2c_pins pins, i2c_pullup pullup)
    That checks to see if the bus is busy, and if not reconfigures the I2C output on the indicated pins with the indicated pullup method. When the switch happens the other pins get configured as inputs using the same indicated pullup method. I've also included my test sketch - i2c_multi_master_t3. You can refer to that for an example, but it's very simple, just make sure to reconfigure between completed I2C commands (not in the middle of a command).

    I've uploaded the new code, a link to it is in the top of the thread.

  15. #15
    Junior Member
    Join Date
    Mar 2013
    Posts
    5
    Ah, I was afraid that the part might behave like that. But thanks a million for finding a workaround. I'll give it a whirl tonight. I'll bet it'll work for me, since the devices are just Wii Nunchucks and I'm just polling them periodically.

    And if all else fails, I'm pretty sure I have a 74HC4052 in my parts box. Thanks for the suggestion, Paul.
    Last edited by ggood; 03-19-2013 at 09:34 PM.

  16. #16
    Junior Member
    Join Date
    Mar 2013
    Posts
    5
    Seems to work correctly with my two Nunchucks. Thanks, Brian!

  17. #17
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    Quote Originally Posted by ggood View Post
    Seems to work correctly with my two Nunchucks. Thanks, Brian!
    Sure, good to hear it worked

  18. #18
    Junior Member
    Join Date
    Mar 2013
    Posts
    5
    Quote Originally Posted by nox771 View Post
    Sure, good to hear it worked
    Here's what I was able to make with your help: https://www.youtube.com/watch?v=j1emiN2XLCU

  19. #19
    Senior Member Wozzy's Avatar
    Join Date
    Jan 2013
    Location
    Philadelphia, Pennsylvania USA
    Posts
    354
    Quote Originally Posted by ggood View Post
    Here's what I was able to make...
    That's awesome!
    Last edited by Wozzy; 04-08-2013 at 12:34 PM.

  20. #20
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,134
    Quote Originally Posted by ggood View Post
    Here's what I was able to make with your help: https://www.youtube.com/watch?v=j1emiN2XLCU
    Excellent! This is an interesting project and there are lots of Freescale Pressure Sensors so why not start another thread describing it in more detail? With the Yamaha BC3A being discontinued, people are looking for alrernatives for breath controllers.

  21. #21
    Junior Member
    Join Date
    Mar 2013
    Posts
    5
    Quote Originally Posted by Nantonos View Post
    Excellent! This is an interesting project and there are lots of Freescale Pressure Sensors so why not start another thread describing it in more detail? With the Yamaha BC3A being discontinued, people are looking for alrernatives for breath controllers.
    I'm partway through writing a series of blog posts about that subject: http://gordophone.blogspot.com/2013/...ntrollers.html

    And this post directly discusses one of the Freescale pressure sensors that I've found that works well (Freescale MPXV4006GP): http://gordophone.blogspot.com/2013/...nsing-101.html

    In general, you're going to want a sensor that maxes out at about 6 kPa (kiloPascals), which is 0.87 psi. Any higher pressure and you're likely to have an anyeurism trying to make the sensor go full-scale.

  22. #22
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    This library is excellent! Given the range of frequencies the I2C bus can be configure to run at I am guessing the I2C hardware on the Teensy3 is a lot more capable of than the one on the Teensy++2 boards.

    A question: Is if there is a timeout/reset feature in case of bus lockups ? With the Teensy++2 boards I have previously worked with the I2CMaster library from DSS circuits and it has such a feature. When I started wit my 1st I2C project I encountered problems and this was a god send feature that helped me get my project on its feet - albeit a little shaky - until I had the means in terms of knowledge and analyze and fix the problem.

  23. #23
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    The timeouts are a good idea. I had a recent email exchange with someone who needed something similar. It is not a difficult thing to do since the library already has background Tx/Rx capability. It did require a little cleanup to prevent hanging the ISR though. I've augmented the endTransmission(), requestFrom() and finish() functions to incorporate timeouts. To use this requires the long form of the function calls, where timeout will be specified in microseconds:

    1) Blocking transmit with timeout:
    Wire.endTransmission(i2c_stop, timeout);

    2) Blocking receive with timeout:
    Wire.requestFrom(address, length, i2c_stop, timeout);

    3) Non-blocking Tx/Rx followed sometime later by finish() with timeout:
    Wire.finish(timeout);

    To test it I wrote an example sketch. I've uploaded a "v3" revision library, see the original post (inside it refer to the i2c_timeout_t3 sketch). It runs through the methods above.

    Note that timeouts are not foolproof, if you abort a READ in the middle and a slave gets stuck outputting a low on the SDA line it will hang the bus no matter what you do, since the master cannot transmit a START or STOP (since SDA is held low). Timeouts can however help diagnose a problem if you dump messages when they occur.

    Regarding that here is how to check for the timeout error condition on exit. In this case I did not append to the Arduino Wire library's idiotic and inconsistent error codes. There are various methods to do this, but a simple one is to directly do a status check after the call:
    Code:
    ...
    Wire.endTransmission(I2C_STOP, 100); // 100us timeout
    if(Wire.status() == I2C_TIMEOUT) { 
        // print error message, try again, whatever
    }
    ...
    Alternatively you can also just ignore the timeout errors, and it will function to prevent blocks (for instance when hot plugging/removing something on the bus).

  24. #24
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    Thank you very much for supporting this. Outstanding, really!

  25. #25
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    429
    Well v3 was short lived. It turns out my method of ending the communication, particularly in the middle of Rx with a slave, was a bit too crude. When receiving from a slave the ISR needs to NAK the slave to get it to reliably release the bus, but this can't be done in a single receive byte (sending a NAK occurs on the next receive byte).

    I reworked the ISR code to better handle that case. I've uploaded a v4 version, attached to the top post. If anyone runs into bugs let me know.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •