Richard-Gemmell / teensy4_i2c

An I2C library for the Teensy 4. Provides slave and master mode.
MIT License
92 stars 19 forks source link

teensy4_i2c

An I2C library for the Teensy 4 microcontroller.

The Teensy 4.0 uses the NXP i.MXRT 1062 microcontroller with an ARM Corex-M7 core.

This library can be used as a drop in replacement for the Wire library in Teensyduino. It has native APIs that are more flexible than Wire and simpler to use in some cases.

The driver implementations, IMX_RT1060_I2CMaster and IMX_RT1060_I2CSlave, have relatively few dependencies on Arduino or the main Teensy libraries. This means that it should be possible to port them to other devices based on the NXP i.MXRT 1060 series of MPUs.

Features

Version 2

Version 2 is currently a work in progress. It's available on the dev branch. You're welcome to use it but expect it to change without notice.

The goal of version 2 is to make the driver more reliable and to support a few more features. See below for a full list of v2 changes.

Please let me know ASAP if your project works Ok with v1 but breaks if you update to v2. This definitely shouldn't happen!

Installation

GitHub Help

If you're wondering how to get code out of GitHub then you're not alone! Here are some instructions for downloading or cloning this library. The page also explains how to download a different branch.

Usage

Use I2C Register Wrappers

I2CDevice and I2CRegisterSlave classes make it very simple to follow the standard I2C pattern of reading or writing to "registers". I recommend that you use this interface if it's suitable.

  1. Download the code and put it in your include path.
  2. #include "i2c_device.h" if you have a master and wish to read from a slave device.
  3. #include "i2c_register_slave.h" if you want to implement a slave device to be read by a master.
  4. See the examples in the examples/simple directory

Use the Driver Directly

The driver interfaces are defined in i2c_driver.h. These provide everything you need to use I2C without the limitations of the Wire library. The key classes are I2CMaster and I2CSlave.

  1. Download the code and put it in your include path.
  2. #include "imx_rt1060_i2c_driver.h"
  3. See the examples in the examples/raw directory

Replacing Wire.h

Follow these instructions if you have already written code to use Wire.h and don't want to change it. I don't recommend using the Wire API unless you have to.

  1. Download the code and put it in your include path.
  2. Change all #includes from Wire.h to i2c_driver_wire.h.
  3. If any of your dependencies use Wire.h you'll have to modify them to use i2c_driver_wire.h instead.
  4. If you depend on any libraries that use Wire.h then you'll have to replace all references to Wire.h to i2c_driver_wire.h in that library. This is because Arduino compiles all .cpp files in a library whether you reference them or not.
  5. See the examples in the examples/wire directory

If you miss a reference to Wire.h then you'll see compilation errors like this:-

... Wire/WireIMXRT.cpp:10: multiple definition of 'Wire'

You may also see linker errors like this:-

... bin/ld.exe: Warning: size of symbol 'Wire' changed from 116 in ... teensy4_i2c\i2c_driver_wire.cpp.o to 112 in ... libraries\Wire\WireIMXRT.cpp.o

Ports and Pins

This table lists the objects that you should use to handle each I2C port.

Port Pins imx_rt1060_i2c_driver.h i2c_driver_wire.h
0 SCL0(19), SDA0(18) Master or Slave Wire
1 SCL1(16), SDA1(17) Master1 or Slave1 Wire1
2 SCL2(24), SDA2(25) Master2 or Slave2 Wire2

Pull Up Resistors

The I2C protocol uses open drain pins. The pins can pull signal voltages low, but they cannot pull them high. The system relies on pull up resistors to do this.

This library enables the Teensy's 22 kΩ internal pull up resistor by default. Many breakout boards with I2C have internal pullups as well.

These internal pullups may or may not be sufficient for your application. It depends entirely on the bus capacitance. The more devices you connect to the bus and the longer the wires, the higher the bus capacitance. The only way to be sure is to measure the rise times for your circuit.

See this I2C Underneath article for information about measuring and tuning rise times.

Common Problems

Here are some of the common problems that will can break the I2C connection or just make it very unreliable.

Data Sheets and References

Project Documents and Tools

Not Tested

I haven't been able to test some features because of hardware and time restrictions. These features should work but don't be surprised if they don't. Please contact me if you encounter any problems.

Not Implemented

The following features are supported by the NXP i.MXRT 1062 processor but I haven't implemented them in this driver. Please contact me if you need any of these features.

Version History

Version Release Date Comment
v2.0.0-beta.1 19th Feb 2023 Added automated test suite. Tuned electrical settings and timings. See below for details.
v1.1.0 12th Aug 2020 I2C slave can now have many I2C addresses.
v1.0.1 11th Aug 2020 Adjusted timings to improve responsiveness.
v1.0.0 19th May 2020 Promoted v0.9.5 to 1.0 as it seems stable.
v0.9.5 19th May 2020 Improved pad control configuration to reduce errors from noise. (Changed default config from 0xF0B0 to 0x1F830)
v0.9.4 15th May 2020 Added function overloads to I2CDriverWire to avoid ambiguous calls from existing code.
v0.9.3 17th February 2020 I2CDriverWire::requestFrom() now reports correct number of bytes.
v0.9.2 9th January 2020 Can now probe for active slaves.
v0.9.1 7th January 2020 Fixed bug in i2c_driver_wire.h
v0.9.0 7th November 2019 Initial Version

Version 2

Breaking Changes

Changes

Remaining Work (not likely before 2024)