[
  {
    "path": "README.md",
    "content": "# i2c_t3\nEnhanced I2C library for Teensy 3.x & LC devices\n\nThis is an enhanced I2C library for [Teensy 3.x/LC devices](http://pjrc.com/teensy/index.html).\n\nRecent discussion and a usage summary can be found in the [PJRC forums here](https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3).\n\n---\n---\n## **Description**\n\nThis 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](http://pjrc.com/teensy/td_download.html).  Follow the instructions on that page for installation.\n\nThe library can also be downloaded separately (eg. for updates), and used by unpacking the library contents into your **sketchbook/libraries** folder.  \n\nTo use with existing Arduino sketches, simply change the **#include \\<Wire.h\\>** to **#include \\<i2c_t3.h\\>**\n\nExample sketches can be found in the Arduino menus at: **File->Examples->i2c_t3**\n\nThe latest version of the library provides the following:\n\n* For **Teensy 3.0**, there is one I2C interface: **Wire**\n* For **Teensy 3.1, 3.2, LC**, there are two I2C interfaces: **Wire**, **Wire1**\n* For **Teensy 3.5**, there are three I2C interfaces: **Wire**, **Wire1**, **Wire2**\n* For **Teensy 3.6**, there are four I2C interfaces: **Wire**, **Wire1**, **Wire2**, **Wire3**\n\n---\n---\n## **Pins**\n\nSome 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.  \n\nIn 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).  \n\nAs an example the following functions are all valid:\n```\nWire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000); // Wire bus, SCL pin 19, SDA pin 18, ext pullup, 400kHz \nWire.begin(I2C_MASTER, 0x00, 19, 18); // equivalent to above, will default to ext pullup at 400kHz\nWire.begin(I2C_MASTER, 0x00, 16, 18); // similar to above, but using SCL pin 16 and SDA pin 18\n```\n\nThe 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\n```\nInterface  Devices     Pin Name      SCL    SDA   Default\n---------  -------  --------------  -----  -----  -------  \n   Wire      All    I2C_PINS_16_17    16     17             \n   Wire      All    I2C_PINS_18_19    19*    18      +\n   Wire    3.5/3.6  I2C_PINS_7_8       7      8\n   Wire    3.5/3.6  I2C_PINS_33_34    33     34\n   Wire    3.5/3.6  I2C_PINS_47_48    47     48\n  Wire1       LC    I2C_PINS_22_23    22     23      +\n  Wire1    3.1/3.2  I2C_PINS_26_31    26     31\n  Wire1    3.1/3.2  I2C_PINS_29_30    29     30      +\n  Wire1    3.5/3.6  I2C_PINS_37_38    37     38      +\n  Wire2    3.5/3.6  I2C_PINS_3_4       3      4      +\n  Wire3      3.6    I2C_PINS_56_57    57*    56      +\n```\nNote: in almost all cases SCL is the lower pin #, except cases marked *\n\nOn 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:\n\n* Clever slotted board: https://www.oshpark.com/shared_projects/ttl7D5iT\n* Full kit board: https://www.tindie.com/products/loglow/teensy-32-breakout/\n\n---\n---\n## **Pullups**\n\nThe 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.\n\nThe 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:\nhttp://dsscircuits.com/articles/86-articles/47-effects-of-varying-i2c-pull-up-resistors\n\nHowever, 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:\nhttp://www.ti.com/lit/an/slva689/slva689.pdf\n\nIn general, for a majority of simple I2C bus configurations a pullup resistance value in the range of **2k to 5k** Ohms should work fine.\n\n### **Teensy Pullups**\n\n**_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)._**\n\nRegarding 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.\n\nThat 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).\n\nThe internal pullup resistances of the Teensy devices are as follows:\n\n* Teensy LC - ~44k Ohms\n* Teensy 3.0/3.1/3.2 - ~190 Ohms (this is believed to be a HW bug)\n* Teensy 3.5 - ~150 Ohms (this is believed to be a HW bug)\n* Teensy 3.6 - ~25 Ohms (this is believed to be a HW bug)\n\nNone of these internal pullups is a particularly good value.  \n\nThe 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.\n\nOn 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. \n\nThe Teensy 3.6 internal pullup is essentially a short, and is unusable.\n\n### **Pullup Voltages**\n\nSome 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.\n\nThe voltage tolerance is as follows:\n```\nVoltage    Devices\n-------  -----------\n  3.3V   3.0, 3.6, LC\n  5.0V   3.1, 3.2, 3.5\n```\n\nSometimes 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. \n\nTo connect 5V devices to 3.3V tolerant Teensy or to connect multiple voltage level I2C buses, refer to the following app note by NXP:\nhttp://www.nxp.com/documents/application_note/AN10441.pdf\n\nThere 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.\n\n---\n---\n## **Clocking**\n\nThe 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.\n\nThe 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):\n```\n     F_CPU      F_BUS     Max I2C\n     (MHz)      (MHz)       Rate\n -------------  -----    ----------\n    240/120      120        6.0M    bus overclock\n      216        108        5.4M    bus overclock\n     192/96       96        4.8M    bus overclock\n      180         90        4.5M    bus overclock\n      240         80        4.0M    bus overclock\n   216/144/72     72        3.6M    bus overclock\n      192         64        3.2M    bus overclock\n  240/180/120     60        3.0M\n      168         56        2.8M\n      216         54        2.7M\n 192/144/96/48    48        2.4M\n       72         36        1.8M\n       24         24        1.2M\n       16         16        800k\n        8          8        400k\n        4          4        200k\n        2          2        100k\n```\n\nPrevious 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.\n\nAllowable I2C_RATE_xxxx enum list is as follows: \t\n* 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\n\nNote 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). \n\nTo 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.\n\n![I2C Speed Test](speedtest.jpg)\n\n---\n---\n## **Operational Modes**\n\nThere 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:\n\n* **I2C_OP_MODE_ISR** - Interrupt\n* **I2C_OP_MODE_DMA** - DMA\n* **I2C_OP_MODE_IMM** - Immediate \n\n**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.\n\nDMA 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.\n\nSimilarly, 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.\n\n---\n---\n## **Example List**\n\nExamples 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.\n\n* **basic_master** - this creates a Master device which is setup to talk to the Slave device given in the **basic_slave** sketch.\n* **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).\n* **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.\n* **basic_slave** - this creates a Slave device which responds to the **basic_master** sketch.\n* **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.\n* **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.\n* **basic_interrupt** - this creates a Master device which is setup to periodically read/write from a Slave device using a timer interrupt.\n* **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).\n* **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.\n* **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.\n* **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.\n* **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.\n\n---\n---\n## **Header Defines**\n\nThese defines can be modified at the top of the **i2c_t3.h** file.\n\n* **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.\n\n* **I2C_TX_BUFFER_LENGTH n** \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.\n\n* **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).\n\n* **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.\n\n* **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.\n\n* **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).\n\n---\n---\n## **Function Summary**\n\nThe functions are divided into the following classifications:\n\n* _**Italic**_ functions are compatible with the original Arduino Wire API. This allows existing Arduino sketches to compile without modification.\n* **Bold** functions are the added enhanced functions. They utilize the advanced capabilities of the Teensy hardware. The library provides the greatest benefit when utilizing these functions (versus the standard Wire library).\n* **'^'** indicates optional function arguments.  When not specified default values will be used.\n\n---\n_**Wire.begin();**_ - initializes I2C as Master mode, external pullups, 100kHz rate, and default pin setting\n\n* default pin setting SCL/SDA: \n    * Wire:   19/18 \n    * Wire1:  29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)\n    * Wire2:   3/4  (3.5/3.6)\n    * Wire3:  57/56 (3.6)\n* return: none\n\n---\n_**Wire.begin(address);**_ - initializes I2C as Slave mode using address, external pullups, 100kHz rate, and default pin setting\n\n* default pin setting SCL/SDA:\n    * Wire:   19/18 \n    * Wire1:  29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)\n    * Wire2:   3/4  (3.5/3.6)\n    * Wire3:  57/56 (3.6)\n* return: none\n* parameters:\n    * address = 7bit slave address of device \n\n---\n**Wire.begin(mode, address1, ^(pins_enum | pinSCL,pinSDA), ^pullup, ^rate, ^opMode);**     \n**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).\n\n* return: none\n* parameters:\n    * mode = I2C_MASTER, I2C_SLAVE\n    * address1 = 1st 7bit address for specifying Slave address (ignored for Master mode)\n    * ^address2 = 2nd 7bit address for specifying Slave address range (ignored for Master mode)\n    * ^pins - pin setting to use, refer to **Pins Section** above.  Can be specified as either of the following:\n        * pins_enum\n        * pinSCL, pinSDA\n    * ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)\n    * ^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)\n    * ^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)\n\n---\n**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.\n\n* return: 1=success, 0=fail (bus busy)\n* parameters:\n    * opMode = I2C_OP_MODE_ISR, I2C_OP_MODE_DMA, I2C_OP_MODE_IMM \n\n---\n_**Wire.setClock(i2cFreq);**_ - reconfigures I2C frequency divider to get desired I2C freq.\n\n* return: none\n* parameters:\n    * i2cFreq = desired I2C frequency in Hz, eg. 400000 for 400kHz. \n\n---\t\n**Wire.getClock();** - return current I2C clock setting (may differ from set frequency due to divide ratio quantization)\n\n* return: bus frequency in Hz\n\n---\n**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.\n\n* return: 1=success, 0=fail (function can no longer fail, it will auto limit at min/max bounds)\n* parameters:\n    * busFreq = bus frequency, typically F_BUS unless reconfigured\n    * 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\n\n---\n**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.\n\n* return: 1=success, 0=fail\n* parameters:\n    * pins - pin setting to use, refer to **Pins Section** above.  Can be specified as either of the following:\n        * pins_enum\n        * pinSCL, pinSDA\n    * ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)\n\n---\n**Wire.setSCL(pin);** - change the SCL pin      \n**Wire.setSDA(pin);** - change the SDA pin\n\n* return: none\n* parameters:\n    * pin - pin setting to use, refer to **Pins Section** above.  \n\n---\n**Wire.getSCL();** - get the current SCL pin      \n**Wire.getSDA();** - get the current SDA pin\n\n* return: pin used\n\n---\n**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()**.\n\n* return: none\n* parameters:\n    * timeout = timeout in microseconds \n\n---\n**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.\n\n* return: none\n\t\n---\n_**Wire.beginTransmission(address);**_ - initialize Tx buffer for transmit to Slave at address\n\n* return: none\n* parameters:\n    * address = target 7bit slave address \n\n---\n**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.\n\n* return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error\n* parameters:\n    * ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n    * ^timeout = timeout in microseconds (default 0 = infinite wait)\n\n---\n**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).\n\n* return: none\n* parameters:\n    * ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n\n---\n**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.\n\n* return: #bytes received = success, 0=fail\n* parameters:\n    * address = target 7bit slave address\n    * length = number of bytes requested\n    * ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n    * ^timeout = timeout in microseconds (default 0 = infinite wait)\n\n---\n**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.\n\n* return: none\n* parameters:\n    * address = target 7bit slave address\n    * length = number of bytes requested\n    * ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n\n---\n**Wire.getError();** - returns \"Wire\" error code from a failed Tx/Rx command\n\n* return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error\n\n---\n**Wire.status();** - returns current status of I2C (enum return value)\n\n* return: \n    * I2C_WAITING\n    * I2C_TIMEOUT\n    * I2C_ADDR_NAK\n    * I2C_DATA_NAK\n    * I2C_ARB_LOST\n    * I2C_BUF_OVF\n    * I2C_NOT_ACQ\n    * I2C_DMA_ERR\n    * I2C_SENDING\n    * I2C_SEND_ADDR\n    * I2C_RECEIVING\n    * I2C_SLAVE_TX\n    * I2C_SLAVE_RX\n\n---\n**Wire.done();** - returns simple complete/not-complete value to indicate I2C status\n\n* return: 1=Tx/Rx complete (with or without errors), 0=still running\n\n---\n**Wire.finish(^timeout);** - blocking routine, loops until Tx/Rx is complete.  **timeout** parameter can be optionally specified.\n\n* return: 1=Tx/Rx complete (Tx or Rx completed, no error), 0=fail (NAK, timeout or Arb lost)\n* parameters:\n    * ^timeout = timeout in microseconds (default 0 = infinite wait) \n\n---\n_**Wire.write(data);**_ - write data byte to Tx buffer\n\n* return: #bytes written = success, 0=fail\n* parameters:\n    * data = data byte \n\n---\n_**Wire.write(data_array, count);**_ - write count number of bytes from data array to Tx buffer\n\n* return: #bytes written = success, 0=fail\n* parameters:\n    * data_array = pointer to uint8_t (or char) array of data\n    * count = number of bytes to write \n\n---\n_**Wire.available();**_ - returns number of remaining available bytes in Rx buffer\n\n* return: #bytes available\n\n---\n_**Wire.read();**_ - returns next data byte (signed int) from Rx buffer\n\n* return: data, -1 if buffer empty\n\n---\n**Wire.read(data_array, count);** - read count number of bytes from Rx buffer to data array\n\n* return: #bytes read\n* parameters:\n    * data_array = pointer to uint8_t (or char) array of data\n    * count = number of bytes to read \n\n---\n_**Wire.peek();**_ - returns next data byte (signed int) from Rx buffer without removing it from Rx buffer\n\n* return: data, -1 if buffer empty\n\n---\n**Wire.readByte();** - returns next data byte (uint8_t) from Rx buffer\n\n* return: data, 0 if buffer empty\n\n---\n**Wire.peekByte();** - returns next data byte (uint8_t) from Rx buffer without removing it from Rx buffer\n\n* return: data, 0 if buffer empty\n\n---\n_**Wire.flush();**_ - does nothing\n\n---\n**Wire.getRxAddr();** - returns target address of incoming I2C command. Used for Slaves operating over an address range.\n\n* return: rxAddr of last received command\n\n---\n**Wire.onTransmitDone(function);** - used to set Master Tx complete callback.  Function must be of the form `void function(void)`, refer to code examples\n\n---\n**Wire.onReqFromDone(function);** - used to set Master Rx complete callback.  Function must be of the form `void function(void)`, refer to code examples\n\n---\n_**Wire.onReceive(function);**_ - used to set Slave Rx callback.  Function must be of the form `void function(size_t len)`, refer to code examples\n\n---\n_**Wire.onRequest(function);**_ - used to set Slave Tx callback.  Function must be of the form `void function(void)`, refer to code examples\n\n---\n**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\n\n---\n**Wire.getErrorCount(counter);** - Get error count from specified counter.      \n**Wire.zeroErrorCount(counter);** - Zero error count of specified counter.\n\n* return: error count / none\n* parameters:\n    * counter\n        * I2C_ERRCNT_RESET_BUS\n        * I2C_ERRCNT_TIMEOUT\n        * I2C_ERRCNT_ADDR_NAK\n        * I2C_ERRCNT_DATA_NAK\n        * I2C_ERRCNT_ARBL\n        * I2C_ERRCNT_NOT_ACQ\n        * I2C_ERRCNT_DMA_ERR\n\n---\n---\t\n## **Compatible Libraries**\n\nThese 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.\n\n* Arduino sketch for MPU-9250 9DoF with AHRS sensor fusion - https://github.com/kriswiner/MPU-9250\n* LSM9DS0 9DOF sensor AHRS sketch - https://github.com/kriswiner/LSM9DS0\n* Adafruit FRAM board - https://bitbucket.org/JezWeston/adafruit_fram_i2c_t3 \n* Adafruit BNO055 library - http://forums.adafruit.com/viewtopic.php?f=19&t=92153&sid=883bc291b6b08f4a51e018675e15dd69\n* Micro Crystal Real Time Clock Module RV-3029-C2 - https://mega.nz/#!NRsGBbwT!ImKEaTJhMQPQYlgDswXHYw7203Hw25h0yY6zY7MStmc\n* MPU-9250 - https://github.com/bolderflight/MPU9250\n* BME280 - https://github.com/bolderflight/BME280\n* AMS5812 - https://github.com/bolderflight/AMS5812\n* AMS5915 - https://github.com/bolderflight/AMS5915\n\n"
  },
  {
    "path": "archive/README.md",
    "content": "# i2c_t3 Archive\nThis folder contains all older releases of the library.\n"
  },
  {
    "path": "examples/advanced_loopback/advanced_loopback.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Loopback\n// -------------------------------------------------------------------------------------------\n//\n// This creates a device using one I2C bus as a Master and one or more I2C buses as Slaves.\n// When the buses are connected together in closed loopback, then it creates a closed test\n// environment which allows Master/Slave development on a single device.  \n//\n// Wire will act as the Master device, and Wire1/2/3 will act as the Slave device(s).\n//\n// Pulling pin12 low will initiate a WRITE then READ transfer between Master and Slave(s).\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n\n// -------------------------------------------------------------------------------------------\n// Defines - modify as needed for pin config\n//\n#define WIRE_PINS   I2C_PINS_18_19\n#if defined(__MKL26Z64__)               // LC\n#define WIRE1_PINS   I2C_PINS_22_23\n#endif\n#if defined(__MK20DX256__)              // 3.1-3.2\n#define WIRE1_PINS   I2C_PINS_29_30\n#endif\n#if defined(__MK64FX512__) || defined(__MK66FX1M0__)  // 3.5/3.6\n#define WIRE1_PINS   I2C_PINS_37_38\n#define WIRE2_PINS   I2C_PINS_3_4\n#endif\n#if defined(__MK66FX1M0__)              // 3.6\n#define WIRE3_PINS   I2C_PINS_56_57\n#endif\n\n\n// Function prototypes and variables\n//\nvoid rwSlave(uint8_t target);\nvoid printWireStatus(void);\nvoid printStatus(i2c_status status);\n#define MEM_LEN 16\nuint8_t mem[MEM_LEN];\n\n#if I2C_BUS_NUM >= 2\nvoid receiveEvent1(size_t len);\nvoid requestEvent1(void);\nvoid printWire1Status(void);\nuint8_t mem1[MEM_LEN];\n#define TARGET1 0x1A\n#endif\n\n#if I2C_BUS_NUM >= 3\nvoid receiveEvent2(size_t len);\nvoid requestEvent2(void);\nvoid printWire2Status(void);\nuint8_t mem2[MEM_LEN];\n#define TARGET2 0x2B\n#endif\n\n#if I2C_BUS_NUM >= 4\nvoid receiveEvent3(size_t len);\nvoid requestEvent3(void);\nvoid printWire3Status(void);\nuint8_t mem3[MEM_LEN];\n#define TARGET3 0x3C\n#endif\n\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    pinMode(12,INPUT_PULLUP);       // Control for Test1\n\n    // Wire - Setup for Master mode, external pullup, 400kHz, 200ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, WIRE_PINS, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(200000);\n    memset(mem, 0, sizeof(mem));\n\n    #if I2C_BUS_NUM >= 2\n    // Wire1 - Setup for Slave mode, external pullup, 400kHz\n    Wire1.begin(I2C_SLAVE, TARGET1, WIRE1_PINS, I2C_PULLUP_EXT, 400000);\n    Wire1.onReceive(receiveEvent1);\n    Wire1.onRequest(requestEvent1);\n    memset(mem1, 0, sizeof(mem1));\n    #endif\n    \n    #if I2C_BUS_NUM >= 3\n    // Wire2 - Setup for Slave mode, external pullup, 400kHz\n    Wire2.begin(I2C_SLAVE, TARGET2, WIRE2_PINS, I2C_PULLUP_EXT, 400000);\n    Wire2.onReceive(receiveEvent2);\n    Wire2.onRequest(requestEvent2);\n    memset(mem2, 0, sizeof(mem2));\n    #endif\n    \n    #if I2C_BUS_NUM >= 4\n    // Wire3 - Setup for Slave mode, external pullup, 400kHz\n    Wire3.begin(I2C_SLAVE, TARGET3, WIRE3_PINS, I2C_PULLUP_EXT, 400000);\n    Wire3.onReceive(receiveEvent3);\n    Wire3.onRequest(requestEvent3);\n    memset(mem3, 0, sizeof(mem3));\n    #endif\n\n    Serial.begin(115200);\n}\n\n\n//\n// Master Loop\n//\nvoid loop()\n{\n    if(digitalRead(12) == LOW)\n    {      \n        Serial.print(\"------------------------------------------------------------\\n\");\n        Serial.printf(\"Writing then reading a %d byte block from Slave device(s)\\n\", MEM_LEN);\n        Serial.print(\"------------------------------------------------------------\\n\");\n\n        digitalWrite(LED_BUILTIN,HIGH);         // LED on\n\n        #if I2C_BUS_NUM >= 2\n        rwSlave(TARGET1);\n        #endif\n        #if I2C_BUS_NUM >= 3\n        rwSlave(TARGET2);\n        #endif\n        #if I2C_BUS_NUM >= 4\n        rwSlave(TARGET3);\n        #endif\n        \n        delay(100);                             // delay to space out tests\n        digitalWrite(LED_BUILTIN,LOW);          // LED off\n    }\n}\n\n\n//\n// Write/Read to Slave\n//\nvoid rwSlave(uint8_t target)\n{\n    uint8_t fail=0, count, data;\n    \n    // Writing to Slave ------------------------------------------------------\n    Wire.beginTransmission(target);         // slave addr\n    Serial.printf(\"I2C WRITE %d bytes   to Slave 0x%0X : \", MEM_LEN, target);\n    for(count = 0; count < MEM_LEN; count++) // prepare data to send\n    {\n        mem[count] = random(0xFF);          // set random data\n        Serial.printf(\"%02X \",mem[count]);\n        Wire.write(mem[count]);\n    }\n    fail = Wire.endTransmission();          // blocking write\n    Serial.print(\"       \");\n    printWireStatus();                      // print I2C final status\n\n    // Reading from Slave ------------------------------------------------------\n    if(!fail)\n    {\n        Wire.requestFrom(target,(size_t)MEM_LEN);  // blocking read\n        fail = Wire.getError();\n\n        Serial.printf(\"I2C  READ %d bytes from Slave 0x%0X : \", Wire.available(), target);\n        for(count = 0; count < MEM_LEN && Wire.available(); count++) // verify block\n        {\n            data = Wire.readByte();\n            Serial.printf(\"%02X \", data);\n            if(mem[count] != data) fail++;\n        }\n        if(!fail)\n            Serial.print(\"  OK   \");\n        else\n            Serial.print(\" FAIL  \");\n        printWireStatus();                  // print I2C final status\n    }\n}\n\n\n//\n// Slave ISR handlers\n//\n#if I2C_BUS_NUM >= 2\nvoid receiveEvent1(size_t count)  // Handle Wire1 Slave Rx Event (incoming I2C request/data)\n{\n    Wire1.read(mem1, count);      // copy Rx data to databuf\n}\nvoid requestEvent1(void)          // Handle Wire1 Tx Event (outgoing I2C data)\n{\n    Wire1.write(mem1, MEM_LEN);   // fill Tx buffer (send full mem)\n}\n#endif\n\n#if I2C_BUS_NUM >= 3\nvoid receiveEvent2(size_t count)  // Handle Wire2 Slave Rx Event (incoming I2C request/data)\n{\n    Wire2.read(mem2, count);      // copy Rx data to databuf\n}\nvoid requestEvent2(void)          // Handle Wire2 Tx Event (outgoing I2C data)\n{\n    Wire2.write(mem2, MEM_LEN);   // fill Tx buffer (send full mem)\n}\n#endif\n\n#if I2C_BUS_NUM >= 4\nvoid receiveEvent3(size_t count)  // Handle Wire3 Slave Rx Event (incoming I2C request/data)\n{\n    Wire3.read(mem3, count);      // copy Rx data to databuf\n}\nvoid requestEvent3(void)          // Handle Wire3 Tx Event (outgoing I2C data)\n{\n    Wire3.write(mem3, MEM_LEN);   // fill Tx buffer (send full mem)\n}\n#endif\n\n\n//\n// print I2C status\n//\nvoid printWireStatus(void) { printStatus(Wire.status()); }\n#if I2C_BUS_NUM >= 2\nvoid printWire1Status(void) { printStatus(Wire1.status()); }\n#endif\n#if I2C_BUS_NUM >= 3\nvoid printWire2Status(void) { printStatus(Wire2.status()); }\n#endif\n#if I2C_BUS_NUM >= 4\nvoid printWire3Status(void) { printStatus(Wire3.status()); }\n#endif\nvoid printStatus(i2c_status status)\n{\n    switch(status)\n    {\n    case I2C_WAITING:  Serial.print(\"I2C waiting, no errors\\n\"); break;\n    case I2C_ADDR_NAK: Serial.print(\"Slave addr not acknowledged\\n\"); break;\n    case I2C_DATA_NAK: Serial.print(\"Slave data not acknowledged\\n\"); break;\n    case I2C_ARB_LOST: Serial.print(\"Bus Error: Arbitration Lost\\n\"); break;\n    case I2C_TIMEOUT:  Serial.print(\"I2C timeout\\n\"); break;\n    case I2C_BUF_OVF:  Serial.print(\"I2C buffer overflow\\n\"); break;\n    default:           Serial.print(\"I2C busy\\n\"); break;\n    }\n}\n\r\n"
  },
  {
    "path": "examples/advanced_master/advanced_master.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// I2C Advanced Master\n// -------------------------------------------------------------------------------------------\n//\n// This creates an I2C master device with simple read/write commands and a small\n// addressable memory.  Note that this communication adds a protocol layer on top of\n// normal I2C read/write procedures.  As such, it is meant to pair with the advanced_slave \n// sketch.  The read/write commands are described below.\n//\n// This code assumes the slave config has 256 byte memory and I2C addr is 0x44.\n//\n// Tests are as follows:\n// Pull pin12 input low to send/receive 256 bytes to/from slave in 32 byte blocks.\n// Pull pin11 input low to send/receive 256 bytes to/from slave in single block.\n// Pull pin10 input low to send/receive 256 bytes to/from slave in single block, using \n//            non-blocking commands.\n// Pull pin9 input low to send/receive 256 bytes to/from slave in single block, using \n//            non-blocking commands in DMA mode.\n// Pull pin8 input low to run I2C rate sweep test.  This sweeps the I2C rates on both master \n//            and slave and times the duration of a 256 byte transfer at each rate.\n//\n// For basic I2C communication only, refer to basic_master and basic_slave example sketches.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n// Slave protocol is as follows:\n// -------------------------------------------------------------------------------------------\n// WRITE - The I2C Master can write to the device by transmitting the WRITE command,\n//         a memory address to store to, and a sequence of data to store.\n//         The command sequence is:\n//\n// START|I2CADDR+W|WRITE|MEMADDR|DATA0|DATA1|DATA2|...|STOP\n//\n// where START     = I2C START sequence\n//       I2CADDR+W = I2C Slave address + I2C write flag\n//       WRITE     = WRITE command\n//       MEMADDR   = memory address to store data to\n//       DATAx     = data byte to store, multiple bytes are stored to increasing address\n//       STOP      = I2C STOP sequence\n// -------------------------------------------------------------------------------------------\n// READ - The I2C Master can read data from the device by transmitting the READ command,\n//        a memory address to read from, and then issuing a STOP/START or Repeated-START,\n//        followed by reading the data.  The command sequence is:\n//\n// START|I2CADDR+W|READ|MEMADDR|REPSTART|I2CADDR+R|DATA0|DATA1|DATA2|...|STOP\n//\n// where START     = I2C START sequence\n//       I2CADDR+W = I2C Slave address + I2C write flag\n//       READ      = READ command\n//       MEMADDR   = memory address to read data from\n//       REPSTART  = I2C Repeated-START sequence (or STOP/START if single Master)\n//       I2CADDR+R = I2C Slave address + I2C read flag\n//       DATAx     = data byte read by Master, multiple bytes are read from increasing address\n//       STOP      = I2C STOP sequence\n// -------------------------------------------------------------------------------------------\n// SETRATE - The I2C Master can adjust the Slave configured I2C rate with this command\n//           The command sequence is:\n//\n// START|I2CADDR+W|SETRATE|RATE0|RATE1|RATE2|RATE3|STOP\n//\n// where START     = I2C START sequence\n//       I2CADDR+W = I2C Slave address + I2C write flag\n//       SETRATE   = SETRATE command\n//       RATE0-3   = I2C frequency (uint32_t) LSB-to-MSB format\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Command definitions\n#define WRITE    0x10\n#define READ     0x20\n#define SETRATE  0x30\n\n// Function prototypes\nvoid print_i2c_setup(void);\nvoid print_i2c_status(void);\nvoid test_rate(uint8_t target, uint32_t rate);\n\n// Memory\n#define MEM_LEN 256\nuint8_t databuf[MEM_LEN];\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    digitalWrite(LED_BUILTIN,LOW);  // LED off\n    pinMode(12,INPUT_PULLUP);       // Control for Test1\n    pinMode(11,INPUT_PULLUP);       // Control for Test2\n    pinMode(10,INPUT_PULLUP);       // Control for Test3\n    pinMode(9,INPUT_PULLUP);        // Control for Test4\n    pinMode(8,INPUT_PULLUP);        // Control for Test5\n\n    Serial.begin(115200);\n    \n    // Setup for Master mode, pins 18/19, external pullups, 400kHz\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n\n    Wire.setDefaultTimeout(250000); // 250ms default timeout\n}\n\nvoid loop()\n{\n    size_t addr, len;\n    uint8_t target = 0x44; // slave addr\n    uint32_t count;\n\n    //\n    // A sequence of different read/write techniques.\n    // Pull respective control pin low to initiate sequence.\n    //\n    // All tests will first write values to the slave, then read back the values.\n    // The readback values should match.\n    //\n    // The LED is turned on during I2C operations.  If it gets stuck on then the\n    // ISR likely had a problem.  This can happen with excessive baud rate.\n    //\n    // Various forms of the Wire calls (blocking/non-blocking/STOP/NOSTOP) are\n    // used in the different tests.\n    //\n\n    if(digitalRead(12) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);         // LED on\n        Serial.print(\"---------------------------------------------------------\\n\");\n        Serial.print(\"Test1 : Using blocking commands:\\n\");\n        Serial.print(\"        1) WRITE memory in 32 byte blocks\\n\");\n        Serial.print(\"        2) READ back memory in 32 byte blocks\\n\");\n        Serial.print(\"---------------------------------------------------------\\n\");\n\n        // Writing to Slave --------------------------------------------------------\n        for(addr = 0; addr < 256; addr += 32)   // sweep addr in 32byte blocks\n        {\n            for(len = 0; len < 32; len++)       // prepare data to send\n                databuf[len] = (addr+len)^0xFF; // set data (equal to bit inverse of memory address)\n\n            Serial.printf(\"I2C WRITE 32 bytes to Slave 0x%0X at MemAddr %d\\n\", target, addr);\n            Serial.print(\"Writing: \");\n            for(len = 0; len < 32; len++) { Serial.printf(\"%d \",databuf[len]); }\n            Serial.print(\"\\n\");\n\n            Wire.beginTransmission(target);     // slave addr\n            Wire.write(WRITE);                  // WRITE command\n            Wire.write(addr);                   // memory address\n            Wire.write(databuf, 32);            // write 32 byte block\n            Wire.endTransmission();             // blocking write (when not specified I2C_STOP is implicit)\n\n            print_i2c_status();                 // print I2C final status\n        }\n\n        // Reading from Slave ------------------------------------------------------\n        for(addr = 0; addr < 256; addr += 32)   // sweep addr in 32byte blocks\n        {\n            Wire.beginTransmission(target);     // slave addr\n            Wire.write(READ);                   // READ command\n            Wire.write(addr);                   // memory address\n            Wire.endTransmission(I2C_NOSTOP);   // blocking write (NOSTOP triggers RepSTART on next I2C command)\n            Wire.requestFrom(target,32,I2C_STOP);// blocking read (request 32 bytes)\n\n            Serial.printf(\"I2C READ 32 bytes from Slave 0x%0X at MemAddr %d\\n\", target, addr);\n            Serial.print(\"Received: \");         // print received bytes\n            while(Wire.available()) { Serial.printf(\"%d \", Wire.readByte()); }\n            Serial.print(\"\\n\");\n            print_i2c_status();                 // print I2C final status\n        }\n\n        digitalWrite(LED_BUILTIN,LOW);          // LED off\n        delay(500);                             // delay to space out tests\n    }\n\n\n    if(digitalRead(11) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);         // LED on\n        Serial.print(\"---------------------------------------------------------\\n\");\n        Serial.print(\"Test2 : Using blocking commands:\\n\");\n        Serial.print(\"        1) WRITE entire memory in a single 256 byte block\\n\");\n        Serial.print(\"        2) READ back entire memory in a single 256 byte block\\n\");\n        Serial.print(\"---------------------------------------------------------\\n\");\n\n        // Writing to Slave --------------------------------------------------------\n        addr = 0;\n        for(len = 0; len < 256; len++)          // prepare data to send\n            databuf[len] = (addr+len)^0xFF;     // set data (equal to bit inverse of memory address)\n\n        Serial.printf(\"I2C WRITE 256 bytes to Slave 0x%0X at MemAddr %d\\n\", target, addr);\n        Serial.print(\"Writing: \");\n        for(len = 0; len < 256; len++) { Serial.printf(\"%d \",databuf[len]); }\n        Serial.print(\"\\n\");\n\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(WRITE);                      // WRITE command\n        Wire.write(addr);                       // memory address\n        Wire.write(databuf, 256);               // write 256 byte block\n        Wire.endTransmission(I2C_STOP);         // blocking write (using explicit I2C_STOP)\n\n        print_i2c_status();                     // print I2C final status\n\n        // Reading from Slave ------------------------------------------------------\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(READ);                       // READ command\n        Wire.write(addr);                       // memory address\n        Wire.endTransmission(I2C_NOSTOP);       // blocking write (NOSTOP triggers RepSTART on next I2C command)\n        Wire.requestFrom(target,256,I2C_STOP);  // blocking read (request 256 bytes)\n\n        Serial.printf(\"I2C READ %d bytes from Slave 0x%0X at MemAddr %d\\n\", Wire.available(), target, addr);\n        Serial.print(\"Received: \");             // print received bytes\n        while(Wire.available()) { Serial.printf(\"%d \", Wire.readByte()); }\n        Serial.print(\"\\n\");\n        print_i2c_status();                     // print I2C final status\n\n        Serial.printf(\"Rate (Hz): %d\\n\", Wire.i2c->currentRate);\n        \n        digitalWrite(LED_BUILTIN,LOW);          // LED off\n        delay(500);                             // delay to space out tests\n    }\n\n\n    if(digitalRead(10) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);         // LED on\n        Serial.print(\"---------------------------------------------------------\\n\");\n        Serial.print(\"Test3 : Using ISR NON-blocking commands:\\n\");\n        Serial.print(\"        1) WRITE a 256 byte block to Slave.  While block is\\n\");\n        Serial.print(\"           transferring, perform other commands.\\n\");\n        Serial.print(\"        2) READ back the 256 byte block from Slave.  While\\n\");\n        Serial.print(\"           block is transferring, perform other commands.\\n\");\n        Serial.print(\"---------------------------------------------------------\\n\");\n\n        // Set operating mode to ISR\n        Wire.setOpMode(I2C_OP_MODE_ISR);\n\n        // Writing to Slave --------------------------------------------------------\n        addr = 0;\n        for(len = 0; len < 256; len++)           // prepare data to send\n            databuf[len] = (addr+len)^0xFF;     // set data (equal to bit inverse of memory address)\n\n        Serial.printf(\"I2C WRITE 256 bytes to Slave 0x%0X at MemAddr %d\\n\", target, addr);\n        Serial.print(\"Writing: \");\n        for(len = 0; len < 256; len++) { Serial.printf(\"%d \",databuf[len]); }\n        Serial.print(\"\\n\");\n\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(WRITE);                      // WRITE command\n        Wire.write(addr);                       // memory address\n        Wire.write(databuf, 256);               // write 256 byte block\n        Wire.sendTransmission();                // NON-blocking write (when not specified I2C_STOP is implicit)\n\n        Serial.print(\"...write sent, counting while waiting for Wire.done()...\\n\");\n        count = 1;\n        while(!Wire.done()) count++; // Since write is non-blocking, do some counting while waiting\n        Serial.printf(\"Counted to: %d\\n\", count++);\n        print_i2c_status();                     // print I2C final status\n\n        // Reading from Slave ------------------------------------------------------\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(READ);                       // READ command\n        Wire.write(addr);                       // memory address\n        Wire.endTransmission(I2C_NOSTOP);       // blocking write (NOSTOP triggers RepSTART on next I2C command)\n        Wire.sendRequest(target,256,I2C_STOP);  // NON-blocking read (request 256 bytes)\n\n        // Since request is non-blocking, do some other things.\n        Serial.print(\"...request sent, doing one thing then waiting for Wire.finish()...\\n\");\n\n        // After doing something, use finish() to wait until I2C done\n        Wire.finish();\n\n        Serial.printf(\"I2C READ %d bytes from Slave 0x%0X at MemAddr %d\\n\", Wire.available(), target, addr);\n        Serial.print(\"Received: \");             // print received bytes\n        while(Wire.available()) { Serial.printf(\"%d \", Wire.readByte()); }\n        Serial.print(\"\\n\");\n        print_i2c_status();                     // print I2C final status\n\n        digitalWrite(LED_BUILTIN,LOW);          // LED off\n        delay(500);                             // delay to space out tests\n    }\n\n\n    if(digitalRead(9) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);         // LED on\n        Serial.print(\"---------------------------------------------------------\\n\");\n        Serial.print(\"Test4 : Using DMA NON-blocking commands:\\n\");\n        Serial.print(\"        1) WRITE a 256 byte block to Slave.  While block is\\n\");\n        Serial.print(\"           transferring, perform other commands.\\n\");\n        Serial.print(\"        2) READ back the 256 byte block from Slave.  While\\n\");\n        Serial.print(\"           block is transferring, perform other commands.\\n\");\n        Serial.print(\"---------------------------------------------------------\\n\");\n\n        // Set operating mode to DMA\n        Serial.print(\"Trying to set DMA mode : \");\n        Wire.setOpMode(I2C_OP_MODE_DMA);\n        if(Wire.i2c->opMode == I2C_OP_MODE_DMA)\n            Serial.printf(\"OK (Channel %d)\\n\",Wire.i2c->DMA->channel);\n        else\n            Serial.print(\"Failed, using ISR\\n\");\n\n        // Writing to Slave --------------------------------------------------------\n        addr = 0;\n        for(len = 0; len < 256; len++)           // prepare data to send\n            databuf[len] = (addr+len)^0xFF;     // set data (equal to bit inverse of memory address)\n\n        Serial.printf(\"I2C WRITE 256 bytes to Slave 0x%0X at MemAddr %d\\n\", target, addr);\n        Serial.print(\"Writing: \");\n        for(len = 0; len < 256; len++) { Serial.printf(\"%d \",databuf[len]); }\n        Serial.print(\"\\n\");\n\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(WRITE);                      // WRITE command\n        Wire.write(addr);                       // memory address\n        Wire.write(databuf, 256);               // write 256 byte block\n        Wire.sendTransmission();                // NON-blocking write (when not specified I2C_STOP is implicit)\n\n        Serial.print(\"...write sent, counting while waiting for Wire.done()...\\n\");\n        count = 1;\n        while(!Wire.done()) count++; // Since write is non-blocking, do some counting while waiting\n        Serial.printf(\"Counted to: %d\\n\", count++);\n        print_i2c_status();                     // print I2C final status\n\n        // Reading from Slave ------------------------------------------------------\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(READ);                       // READ command\n        Wire.write(addr);                       // memory address\n        Wire.endTransmission(I2C_NOSTOP);       // blocking write (NOSTOP triggers RepSTART on next I2C command)\n        Wire.sendRequest(target,256,I2C_STOP);  // NON-blocking read (request 256 bytes)\n\n        // Since request is non-blocking, do some other things.\n        Serial.print(\"...request sent, doing one thing then waiting for Wire.finish()...\\n\");\n\n        // After doing something, use finish() to wait until I2C done\n        Wire.finish();\n\n        Serial.printf(\"I2C READ %d bytes from Slave 0x%0X at MemAddr %d\\n\", Wire.available(), target, addr);\n        Serial.print(\"Received: \");             // print received bytes\n        while(Wire.available()) { Serial.printf(\"%d \", Wire.readByte()); }\n        Serial.print(\"\\n\");\n        print_i2c_status();                     // print I2C final status\n\n        digitalWrite(LED_BUILTIN,LOW);          // LED off\n        delay(500);                             // delay to space out tests\n    }\n\n\n    if(digitalRead(8) == LOW)\n    {\n        uint8_t fail=0;\n        \n        digitalWrite(LED_BUILTIN,HIGH);         // LED on\n        Serial.print(\"---------------------------------------------------------\\n\");\n        Serial.print(\"Test5 : Rate adjustment tests.  This sweeps the I2C rates\\n\");\n        Serial.print(\"        on both Master and Slave and times the duration \\n\");\n        Serial.print(\"        of a 256 byte transfer at each rate.\\n\");\n        Serial.print(\"---------------------------------------------------------\\n\");\n\n        for(uint8_t opMode = I2C_OP_MODE_IMM; opMode <= I2C_OP_MODE_DMA; opMode++)\n        {\n            Wire.setOpMode((i2c_op_mode)opMode); // set op mode\n            \n            test_rate(target, 10000, fail);\n            test_rate(target, 100000, fail);\n            test_rate(target, 200000, fail);\n            test_rate(target, 300000, fail);\n            test_rate(target, 400000, fail);\n            test_rate(target, 600000, fail);\n            test_rate(target, 800000, fail);\n            test_rate(target, 1000000, fail);\n            test_rate(target, 1200000, fail);\n            test_rate(target, 1500000, fail);\n            test_rate(target, 1800000, fail);\n            test_rate(target, 2000000, fail);\n            test_rate(target, 2400000, fail);\n            test_rate(target, 2800000, fail);\n            test_rate(target, 3000000, fail);\n            test_rate(target, 4000000, fail);\n            test_rate(target, 5000000, fail);\n            test_rate(target, 6000000, fail);\n\n            // Restore normal settings\n\n            // Change Slave rate\n            Wire.beginTransmission(target);         // slave addr\n            Wire.write(SETRATE);                    // SETRATE command\n            Wire.write((uint8_t)400000&0xFF);       // rate LSB\n            Wire.write((uint8_t)(400000>>8)&0xFF);\n            Wire.write((uint8_t)(400000>>16)&0xFF);\n            Wire.write((uint8_t)(400000>>24)&0xFF); // rate MSB\n            Wire.endTransmission();                 // blocking write\n\n            // Change Master rate\n            Wire.setClock(400000);\n\n            fail = 0;  // reset flag\n        }\n        Wire.setOpMode(I2C_OP_MODE_ISR);        // restore default ISR mode\n\n        print_i2c_status();                     // print I2C final status\n\n        // Restore normal settings (400kHz)\n\n        // Change Slave rate\n        Wire.beginTransmission(target);         // slave addr\n        Wire.write(SETRATE);                    // SETRATE command\n        Wire.write((uint8_t)400000&0xFF);       // rate LSB\n        Wire.write((uint8_t)(400000>>8)&0xFF);\n        Wire.write((uint8_t)(400000>>16)&0xFF);\n        Wire.write((uint8_t)(400000>>24)&0xFF); // rate MSB\n        Wire.endTransmission();                 // blocking write\n\n        // Change Master rate\n        Wire.setClock(400000);\n\n        digitalWrite(LED_BUILTIN,LOW);          // LED off\n        delay(500);                             // delay to space out tests\n    }\n}\n\n\n//\n// print current setup\n//\nvoid print_i2c_setup()\n{\n    Serial.print(\"Mode:\");\n    switch(Wire.i2c->opMode)\n    {\n    case I2C_OP_MODE_IMM: Serial.print(\"IMM    \"); break;\n    case I2C_OP_MODE_ISR: Serial.print(\"ISR    \"); break;\n    case I2C_OP_MODE_DMA: Serial.printf(\"DMA[%d] \",Wire.i2c->DMA->channel); break;\n    }\n    Serial.printf(\"Pins: %d/%d \", Wire.i2c->currentSCL, Wire.i2c->currentSDA);\n}\n\n\n//\n// print I2C status\n//\nvoid print_i2c_status(void)\n{\n    switch(Wire.status())\n    {\n    case I2C_WAITING:  Serial.print(\"I2C waiting, no errors\\n\"); break;\n    case I2C_ADDR_NAK: Serial.print(\"Slave addr not acknowledged\\n\"); break;\n    case I2C_DATA_NAK: Serial.print(\"Slave data not acknowledged\\n\"); break;\n    case I2C_ARB_LOST: Serial.print(\"Bus Error: Arbitration Lost\\n\"); break;\n    case I2C_TIMEOUT:  Serial.print(\"I2C timeout\\n\"); break;\n    case I2C_BUF_OVF:  Serial.print(\"I2C buffer overflow\\n\"); break;\n    default:           Serial.print(\"I2C busy\\n\"); break;\n    }\n}\n\n\n//\n// print I2C rate\n//\nvoid print_rate(uint32_t rate)\n{\n    Serial.printf(\"%d Hz    \", rate);\n}\n\n\n//\n// test rate\n//\nvoid test_rate(uint8_t target, uint32_t rate, uint8_t& fail)\n{\n    uint32_t deltatime=0;\n    size_t len;\n    \n    if(!fail)\n    {\n        for(len = 0; len < 256; len++)  // prepare data to send\n            databuf[len] = len;         // set data (equal to addr)\n    \n        // Change Slave rate\n        Wire.beginTransmission(target);       // slave addr\n        Wire.write(SETRATE);                  // SETRATE command\n        Wire.write((uint8_t)rate&0xFF);       // rate LSB\n        Wire.write((uint8_t)(rate>>8)&0xFF);\n        Wire.write((uint8_t)(rate>>16)&0xFF);\n        Wire.write((uint8_t)(rate>>24)&0xFF); // rate MSB\n        Wire.endTransmission();               // blocking write\n        fail = Wire.getError();\n    \n        if(!fail)\n        {\n            // Change Master rate\n            Wire.setClock(rate);\n        \n            // Setup write buffer\n            Wire.beginTransmission(target); // slave addr\n            Wire.write(WRITE);              // WRITE command\n            Wire.write(0);                  // memory address\n            Wire.write(databuf, 256);       // write 256 byte block\n        \n            // Write to Slave\n            elapsedMicros deltaT;\n            Wire.endTransmission();         // blocking write\n            deltatime = deltaT;\n            fail = Wire.getError();\n        \n            if(!fail)\n            {\n                Wire.beginTransmission(target);     // slave addr\n                Wire.write(READ);                   // READ command\n                Wire.write(0);                      // memory address\n                Wire.endTransmission(I2C_NOSTOP);   // blocking write (NOSTOP triggers RepSTART on next I2C command)\n                Wire.requestFrom(target,256,I2C_STOP);// blocking read\n                fail = Wire.getError();\n        \n                if(!fail)\n                {\n                    for(len = 0; len < 256; len++)  // verify block\n                        if(databuf[len] != Wire.readByte()) { fail=1; break; }\n                }\n            }\n        }\n\n        print_i2c_setup();\n        if(!fail)\n        {\n            // Print result\n            Serial.print(\"256 byte transfer at \");\n            print_rate(rate);\n            Serial.printf(\" (Actual Rate (Hz): %d) : %d us : \", Wire.getClock(), deltatime);\n            print_i2c_status();\n        }\n        else\n        {\n            Serial.printf(\"Transfer fail : %d us : \",deltatime);\n            print_i2c_status();\n        }\n    }\n}\r\n"
  },
  {
    "path": "examples/advanced_scanner/advanced_scanner.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// I2C Advanced Bus Scanner\n// -------------------------------------------------------------------------------------------\n//\n// This creates an I2C master device which will scan the address space and report all\n// devices which ACK.  It does not attempt to transfer data, it only reports which devices\n// ACK their address.\n//\n// This version will sweep all existing I2C buses (eg. Wire, Wire1, Wire2, Wire3).\n//\n// Pull the control pin low to initiate the scan.  Result will output to Serial.\n//\n// This example code is in the public domain.\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// -------------------------------------------------------------------------------------------\n// Defines - modify as needed for sweep range and bus pin config\n//\n#define TARGET_START 0x01\n#define TARGET_END   0x7F\n\n#define WIRE_PINS   I2C_PINS_18_19\n#if defined(__MKL26Z64__)               // LC\n#define WIRE1_PINS   I2C_PINS_22_23\n#endif\n#if defined(__MK20DX256__)              // 3.1-3.2\n#define WIRE1_PINS   I2C_PINS_29_30\n#endif\n#if defined(__MK64FX512__) || defined(__MK66FX1M0__)  // 3.5/3.6\n#define WIRE1_PINS   I2C_PINS_37_38\n#define WIRE2_PINS   I2C_PINS_3_4\n#endif\n#if defined(__MK66FX1M0__)              // 3.6\n#define WIRE3_PINS   I2C_PINS_56_57\n#endif\n\n// -------------------------------------------------------------------------------------------\n// Function prototypes\nvoid scan_bus(i2c_t3& Wire, uint8_t all);\nvoid print_bus_status(i2c_t3& Wire);\nvoid print_scan_status(struct i2cStruct* i2c, uint8_t target, uint8_t& found, uint8_t all);\n\n// -------------------------------------------------------------------------------------------\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    pinMode(12,INPUT_PULLUP);       // pull pin 12 low to show ACK only results\n    pinMode(11,INPUT_PULLUP);       // pull pin 11 low for a more verbose result (shows both ACK and NACK)\n\n    // Setup for Master mode, all buses, external pullups, 400kHz, 10ms default timeout\n    //\n    Wire.begin(I2C_MASTER, 0x00, WIRE_PINS, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(10000); // 10ms\n    #if I2C_BUS_NUM >= 2\n    Wire1.begin(I2C_MASTER, 0x00, WIRE1_PINS, I2C_PULLUP_EXT, 400000);\n    Wire1.setDefaultTimeout(10000); // 10ms\n    #endif\n    #if I2C_BUS_NUM >= 3\n    Wire2.begin(I2C_MASTER, 0x00, WIRE2_PINS, I2C_PULLUP_EXT, 400000);\n    Wire2.setDefaultTimeout(10000); // 10ms\n    #endif\n    #if I2C_BUS_NUM >= 4\n    Wire3.begin(I2C_MASTER, 0x00, WIRE3_PINS, I2C_PULLUP_EXT, 400000);\n    Wire3.setDefaultTimeout(10000); // 10ms\n    #endif\n\n    Serial.begin(115200);\n}\n\n// -------------------------------------------------------------------------------------------\nvoid loop()\n{\n    // Scan I2C addresses\n    //\n    if(digitalRead(12) == LOW || digitalRead(11) == LOW)\n    {\n        uint8_t all = (digitalRead(11) == LOW);\n\n        Serial.print(\"---------------------------------------------------\\n\");\n        Serial.print(\"Bus Status Summary\\n\");\n        Serial.print(\"==================\\n\");\n        Serial.print(\" Bus    Mode   SCL  SDA   Pullup   Clock\\n\");\n        print_bus_status(Wire);\n        #if I2C_BUS_NUM >= 2\n        print_bus_status(Wire1);\n        #endif\n        #if I2C_BUS_NUM >= 3\n        print_bus_status(Wire2);\n        #endif\n        #if I2C_BUS_NUM >= 4\n        print_bus_status(Wire3);\n        #endif\n\n        scan_bus(Wire, all);\n        #if I2C_BUS_NUM >= 2\n        scan_bus(Wire1, all);\n        #endif\n        #if I2C_BUS_NUM >= 3\n        scan_bus(Wire2, all);\n        #endif\n        #if I2C_BUS_NUM >= 4\n        scan_bus(Wire3, all);\n        #endif\n\n        Serial.print(\"---------------------------------------------------\\n\\n\\n\");\n\n        delay(500); // delay to space out tests\n    }\n}\n\n// -------------------------------------------------------------------------------------------\n// scan bus\n//\nvoid scan_bus(i2c_t3& Wire, uint8_t all)\n{\n    uint8_t target, found = 0;\n    \n    Serial.print(\"---------------------------------------------------\\n\");\n    if(Wire.bus == 0)\n        Serial.print(\"Starting scan: Wire\\n\");\n    else\n        Serial.printf(\"Starting scan: Wire%d\\n\",Wire.bus);\n    \n    digitalWrite(LED_BUILTIN,HIGH); // LED on\n    for(target = TARGET_START; target <= TARGET_END; target++) // sweep addr, skip general call\n    {\n        Wire.beginTransmission(target);       // slave addr\n        Wire.endTransmission();               // no data, just addr\n        print_scan_status(Wire.i2c, target, found, all);\n    }    \n    digitalWrite(LED_BUILTIN,LOW); // LED off\n    \n    if(!found) Serial.print(\"No devices found.\\n\");\n}\n\n// -------------------------------------------------------------------------------------------\n// print bus status\n//\nvoid print_bus_status(i2c_t3& Wire)\n{\n    struct i2cStruct* i2c = Wire.i2c;\n    if(Wire.bus == 0)\n        Serial.print(\"Wire   \");\n    else\n        Serial.printf(\"Wire%d  \",Wire.bus);\n    switch(i2c->currentMode)\n    {\n    case I2C_MASTER: Serial.print(\"MASTER  \"); break;\n    case I2C_SLAVE:  Serial.print(\" SLAVE  \"); break;\n    }\n    Serial.printf(\" %2d   %2d  \", Wire.i2c->currentSCL, Wire.i2c->currentSDA);\n    switch(i2c->currentPullup)\n    {\n    case I2C_PULLUP_EXT: Serial.print(\"External  \"); break;\n    case I2C_PULLUP_INT: Serial.print(\"Internal  \"); break;\n    }\n    Serial.printf(\"%d Hz\\n\",i2c->currentRate);\n}\n\n// -------------------------------------------------------------------------------------------\n// print scan status\n//\nvoid print_scan_status(struct i2cStruct* i2c, uint8_t target, uint8_t& found, uint8_t all)\n{\n    switch(i2c->currentStatus)\n    {\n    case I2C_WAITING:  Serial.printf(\"Addr: 0x%02X ACK\\n\",target); found=1; break;\n    case I2C_ADDR_NAK: if(all) { Serial.printf(\"Addr: 0x%02X\\n\",target); } break;\n    case I2C_TIMEOUT:  if(all) { Serial.printf(\"Addr: 0x%02X Timeout\\n\",target); } break;\n    default: break;\n    }\n}\n\r\n"
  },
  {
    "path": "examples/advanced_slave/advanced_slave.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// I2C Advanced Slave\n// -------------------------------------------------------------------------------------------\n//\n// This creates an I2C slave device with simple read/write commands and a small\n// addressable memory.  Note that this communication adds a protocol layer on top of\n// normal I2C read/write procedures.  As such, it is meant to pair with the advanced_master \n// sketch.  The read/write commands are described below.\n//\n// For basic I2C communication only, refer to basic_master and basic_slave example sketches.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n// WRITE - The I2C Master can write to the device by transmitting the WRITE command,\n//         a memory address to store to, and a sequence of data to store.\n//         The command sequence is:\n//\n// START|I2CADDR+W|WRITE|MEMADDR|DATA0|DATA1|DATA2|...|STOP\n//\n// where START     = I2C START sequence\n//       I2CADDR+W = I2C Slave address + I2C write flag\n//       WRITE     = WRITE command\n//       MEMADDR   = memory address to store data to\n//       DATAx     = data byte to store, multiple bytes are stored to increasing address\n//       STOP      = I2C STOP sequence\n// -------------------------------------------------------------------------------------------\n// READ - The I2C Master can read data from the device by transmitting the READ command,\n//        a memory address to read from, and then issuing a STOP/START or Repeated-START,\n//        followed by reading the data.  The command sequence is:\n//\n// START|I2CADDR+W|READ|MEMADDR|REPSTART|I2CADDR+R|DATA0|DATA1|DATA2|...|STOP\n//\n// where START     = I2C START sequence\n//       I2CADDR+W = I2C Slave address + I2C write flag\n//       READ      = READ command\n//       MEMADDR   = memory address to read data from\n//       REPSTART  = I2C Repeated-START sequence (or STOP/START if single Master)\n//       I2CADDR+R = I2C Slave address + I2C read flag\n//       DATAx     = data byte read by Master, multiple bytes are read from increasing address\n//       STOP      = I2C STOP sequence\n// -------------------------------------------------------------------------------------------\n// SETRATE - The I2C Master can adjust the Slave configured I2C rate with this command\n//           The command sequence is:\n//\n// START|I2CADDR+W|SETRATE|RATE0|RATE1|RATE2|RATE3|STOP\n//\n// where START     = I2C START sequence\n//       I2CADDR+W = I2C Slave address + I2C write flag\n//       SETRATE   = SETRATE command\n//       RATE0-3   = I2C frequency (uint32_t) LSB-to-MSB format\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Command definitions\n#define WRITE    0x10\n#define READ     0x20\n#define SETRATE  0x30\n\n// Function prototypes\nvoid receiveEvent(size_t count);\nvoid requestEvent(void);\n\n// Memory\n#define MEM_LEN 256\nuint8_t mem[MEM_LEN];\nvolatile uint8_t cmd;\nvolatile size_t addr;\nvolatile uint32_t rate;\n\n//\n// Setup\n//\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT); // LED\n\n    // Setup for Slave mode, address 0x44, pins 18/19, external pullups, 400kHz\n    Wire.begin(I2C_SLAVE, 0x44, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n\n    // init vars\n    cmd = 0;\n    addr = 0;\n    memset(mem, 0, sizeof(mem));\n    rate = 400000;\n\n    // register events\n    Wire.onReceive(receiveEvent);\n    Wire.onRequest(requestEvent);\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    digitalWrite(LED_BUILTIN,HIGH); // double pulse LED while waiting for I2C requests\n    delay(10);                      // if the LED stops the slave is probably stuck in an ISR\n    digitalWrite(LED_BUILTIN,LOW);\n    delay(100);\n    digitalWrite(LED_BUILTIN,HIGH);\n    delay(10);\n    digitalWrite(LED_BUILTIN,LOW);\n    delay(880);\n}\n\n//\n// handle Rx Event (incoming I2C request/data)\n//\nvoid receiveEvent(size_t count)\n{\n    if(count)\n    {\n        // grab command\n        cmd = Wire.readByte();\n        switch(cmd)\n        {\n        case WRITE:\n            addr = Wire.readByte();         // grab addr\n            Wire.read(&mem[addr], count-2); // copy Rx data to databuf\n            break;\n\n        case READ:\n            addr = Wire.readByte();                // grab addr\n            break;\n\n        case SETRATE:\n            if(Wire.available() >= 4)\n            {\n                rate = Wire.readByte();            // grab rate\n                rate |= Wire.readByte() << 8;\n                rate |= Wire.readByte() << 16;\n                rate |= Wire.readByte() << 24;\n                Wire.setClock(rate); // set rate\n            }\n            break;\n        }\n    }\n}\n\n//\n// handle Tx Event (outgoing I2C data)\n//\nvoid requestEvent(void)\n{\n    switch(cmd)\n    {\n    case READ:\n        Wire.write(&mem[addr], MEM_LEN-addr); // fill Tx buffer (from addr location to end of mem)\n        break;\n    }\n}\n\r\n"
  },
  {
    "path": "examples/basic_echo/basic_echo.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Basic Echo\n// -------------------------------------------------------------------------------------------\n//\n// This creates a simple I2C Slave device which will read whatever data is sent to it \n// on Wire1 and output that same data on Wire.  It will retain the data in memory and will \n// send it back to a Master device if requested. \n//\n// This code demonstrates non-blocking nested operation - calling Wire in a non-blocking way\n// inside of Wire1 receive ISR.\n//\n// Wire1 bus is intended to pair with a Master device running the basic_master sketch.\n// Wire bus is intended to pair with a Slave device running the basic_slave sketch.\n//\n// This code is setup for a Teensy 3.5/3.6 device.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Function prototypes\nvoid receiveEvent(size_t count);\nvoid requestEvent(void);\n\n// Memory\n#define MEM_LEN 256\nuint8_t databuf[MEM_LEN];\nvolatile uint8_t received;\n\n//\n// Setup\n//\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT); // LED\n\n    // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(200000); // 200ms\n\n    // Setup for Slave mode, address 0x66, pins 37/38, external pullups, 400kHz\n    Wire1.begin(I2C_SLAVE, 0x66, I2C_PINS_37_38, I2C_PULLUP_EXT, 400000);   // 3.5/3.6\n\n    // Data init\n    received = 0;\n    memset(databuf, 0, sizeof(databuf));\n\n    // register events\n    Wire1.onReceive(receiveEvent);\n    Wire1.onRequest(requestEvent);\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    // print received data - this is done in main loop to keep time spent in I2C ISR to minimum\n    if(received)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);\n        Serial.printf(\"Echoing data received: '%s'\\n\", databuf);\n        received = 0;\n        digitalWrite(LED_BUILTIN,LOW);\n    }\n}\n\n//\n// handle Rx Event (incoming I2C data)\n//\nvoid receiveEvent(size_t count)\n{\n    digitalWrite(LED_BUILTIN,HIGH); // LED on\n    \n    Wire1.read(databuf, count);     // copy Rx data to databuf\n    \n    Wire.finish();                  // finish any prev non-blocking Tx\n    Wire.beginTransmission(0x66);   // init for Tx send  \n    Wire.write(databuf, count);     // send to Tx buffer\n    Wire.sendTransmission();        // Send Tx data to Slave (non-blocking)\n    \n    received = count;               // set received flag to count, this triggers print in main loop\n\n    digitalWrite(LED_BUILTIN,LOW);  // LED off\n}\n\n//\n// handle Tx Event (outgoing I2C data)\n//\nvoid requestEvent(void)\n{\n    Wire1.write(databuf, MEM_LEN); // fill Tx buffer (send full mem)\n}\n\r\n"
  },
  {
    "path": "examples/basic_interrupt/basic_interrupt.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Interrupt\n// -------------------------------------------------------------------------------------------\n//\n// This creates an I2C master device which will issue I2C commands from inside a periodic\n// interrupt (eg. similar to reading a sensor at regular time intervals).  For this test the \n// Slave device will be assumed to be that given in the basic_slave sketch.\n//\n// The test will start when the Serial monitor opens.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Function prototypes\nvoid rwSlave(void);\n\n// Timer\nIntervalTimer slaveTimer;\n\n// Memory\n#define MEM_LEN 32\nchar databuf[MEM_LEN];\nsize_t count=0;\nuint8_t target=0x66;\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);        // LED\n\n    // Setup for Master mode, pins 18/19, external pullups, 400kHz, 10ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(10000);\n\n    // Data init\n    memset(databuf, 0, sizeof(databuf));\n    count = 0;\n\n    // setup Serial and wait for monitor to start\n    Serial.begin(115200);\n    while(!Serial);\n\n    // Start reading Slave device\n    slaveTimer.begin(rwSlave,1000000); // 1s timer\n}\n\nvoid loop()\n{\n    delay(1);\n}\n\nvoid rwSlave(void)\n{\n    digitalWrite(LED_BUILTIN,HIGH);         // pulse LED when reading\n\n    // Construct data message\n    sprintf(databuf, \"Msg #%d\", count++);\n    \n    // Transmit to Slave\n    Wire.beginTransmission(target);         // Slave address\n    Wire.write(databuf,strlen(databuf)+1);  // Write string to I2C Tx buffer (incl. string null at end)\n    Wire.endTransmission();                 // Transmit to Slave\n\n    // Check if error occured\n    if(Wire.getError())\n        Serial.print(\"Write FAIL\\n\");\n    else\n    {\n        // Read from Slave\n        Wire.requestFrom(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer)\n\n        // Check if error occured\n        if(Wire.getError())\n            Serial.print(\"Read FAIL\\n\");\n        else\n        {\n            // If no error then read Rx data into buffer and print\n            Wire.read(databuf, Wire.available());\n            Serial.printf(\"'%s' OK\\n\",databuf);\n        }\n    }\n\n    digitalWrite(LED_BUILTIN,LOW);\n}\r\n"
  },
  {
    "path": "examples/basic_master/basic_master.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Basic Master\n// -------------------------------------------------------------------------------------------\n//\n// This creates a simple I2C Master device which when triggered will send/receive a text \n// string to/from a Slave device.  It is intended to pair with a Slave device running the \n// basic_slave sketch.\n//\n// Pull pin12 input low to send.\n// Pull pin11 input low to receive.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Memory\n#define MEM_LEN 256\nchar databuf[MEM_LEN];\nint count;\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    digitalWrite(LED_BUILTIN,LOW);  // LED off\n    pinMode(12,INPUT_PULLUP);       // Control for Send\n    pinMode(11,INPUT_PULLUP);       // Control for Receive\n\n    // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(200000); // 200ms\n\n    // Data init\n    memset(databuf, 0, sizeof(databuf));\n    count = 0;\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    uint8_t target = 0x66; // target Slave address\n \n    // Send string to Slave\n    //\n    if(digitalRead(12) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);   // LED on\n\n        // Construct data message\n        sprintf(databuf, \"Data Message #%d\", count++);\n\n        // Print message\n        Serial.printf(\"Sending to Slave: '%s' \", databuf);\n        \n        // Transmit to Slave\n        Wire.beginTransmission(target);   // Slave address\n        Wire.write(databuf,strlen(databuf)+1); // Write string to I2C Tx buffer (incl. string null at end)\n        Wire.endTransmission();           // Transmit to Slave\n\n        // Check if error occured\n        if(Wire.getError())\n            Serial.print(\"FAIL\\n\");\n        else\n            Serial.print(\"OK\\n\");\n\n        digitalWrite(LED_BUILTIN,LOW);    // LED off\n        delay(100);                       // Delay to space out tests\n    }\n\n    // Read string from Slave\n    //\n    if(digitalRead(11) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);   // LED on\n\n        // Print message\n        Serial.print(\"Reading from Slave: \");\n        \n        // Read from Slave\n        Wire.requestFrom(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer)\n\n        // Check if error occured\n        if(Wire.getError())\n            Serial.print(\"FAIL\\n\");\n        else\n        {\n            // If no error then read Rx data into buffer and print\n            Wire.read(databuf, Wire.available());\n            Serial.printf(\"'%s' OK\\n\",databuf);\n        }\n\n        digitalWrite(LED_BUILTIN,LOW);    // LED off\n        delay(100);                       // Delay to space out tests\n    }\n}\n\r\n"
  },
  {
    "path": "examples/basic_master_callback/basic_master_callback.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Basic Master Callback\n// -------------------------------------------------------------------------------------------\n//\n// This creates a simple I2C Master device which when triggered will send/receive a text\n// string to/from a Slave device.  It is intended to pair with a Slave device running the\n// basic_slave sketch.  \n//\n// Functionally this sketch is similar to the basic_master sketch, except for three things:\n// 1) It uses callbacks to handle the results and errors, instead of explicitly coding such\n//    routines after each send/receive call.\n// 2) It can optionally demonstrate background transfers by setting the NONBLOCKING flag (from\n//    external observation these transfers will appear similar, but the LED duration will\n//    be shorter as they exit immediately after initiating the transfer).\n// 3) There is an added test to dump error diagnostics from the error counting system.\n//\n// Pull pin12 input low to send.\n// Pull pin11 input low to receive.\n// Pull pin10 input low to dump error diagnostics.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Memory\n#define MEM_LEN 256\nchar databuf[MEM_LEN];\nint count;\n\n#define NONBLOCKING\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    digitalWrite(LED_BUILTIN,LOW);  // LED off\n    pinMode(12,INPUT_PULLUP);       // Control for Send\n    pinMode(11,INPUT_PULLUP);       // Control for Receive\n    pinMode(10,INPUT_PULLUP);       // Control for Diagnostics\n\n    // Setup for Master mode, pins 18/19, external pullups, 400kHz, 50ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(50000); // 50ms\n\n    // Data init\n    memset(databuf, 0, sizeof(databuf));\n    count = 0;\n\n    Serial.begin(115200);\n\n    Wire.onTransmitDone(transmitDone);\n    Wire.onReqFromDone(requestDone);\n    Wire.onError(errorEvent);\n}\n\nvoid loop()\n{\n    uint8_t target = 0x66; // target Slave address\n\n    // Send string to Slave\n    //\n    if(digitalRead(12) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);   // LED on\n\n        // Construct data message\n        sprintf(databuf, \"Data Message #%d\", count++);\n\n        // Print message\n        Serial.printf(\"Sending to Slave: '%s' \", databuf);\n\n        // Transmit to Slave\n        Wire.beginTransmission(target);   // Slave address\n        Wire.write(databuf,strlen(databuf)+1); // Write string to I2C Tx buffer (incl. string null at end)\n        #if defined(NONBLOCKING)\n            Wire.sendTransmission();          // Transmit to Slave, non-blocking\n        #else\n            Wire.endTransmission();           // Transmit to Slave, blocking\n        #endif\n\n        // After send complete, callback will print result\n\n        digitalWrite(LED_BUILTIN,LOW);    // LED off\n        delay(100);                       // 100ms delay\n    }\n\n    // Read string from Slave\n    //\n    if(digitalRead(11) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);   // LED on\n\n        // Print message\n        Serial.print(\"Reading from Slave: \");\n\n        // Read from Slave\n        #if defined(NONBLOCKING)\n            Wire.sendRequest(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer), non-blocking\n        #else\n            Wire.requestFrom(target, (size_t)MEM_LEN); // Read from Slave (string len unknown, request full buffer), blocking\n        #endif\n\n        // After request complete, callback will print result\n\n        digitalWrite(LED_BUILTIN,LOW);    // LED off\n        delay(100);                       // 100ms delay\n    }\n\n    // Diagnostics - print error count summary\n    //\n    if(digitalRead(10) == LOW)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);   // LED on\n\n        // Print errors\n        Serial.print(\"\\n\");\n        Serial.printf(\"I2C_ERRCNT_RESET_BUS: %d\\n\", Wire.getErrorCount(I2C_ERRCNT_RESET_BUS));\n        Serial.printf(\"I2C_ERRCNT_TIMEOUT:   %d\\n\", Wire.getErrorCount(I2C_ERRCNT_TIMEOUT));\n        Serial.printf(\"I2C_ERRCNT_ADDR_NAK:  %d\\n\", Wire.getErrorCount(I2C_ERRCNT_ADDR_NAK));\n        Serial.printf(\"I2C_ERRCNT_DATA_NAK:  %d\\n\", Wire.getErrorCount(I2C_ERRCNT_DATA_NAK));\n        Serial.printf(\"I2C_ERRCNT_ARBL:      %d\\n\", Wire.getErrorCount(I2C_ERRCNT_ARBL));\n        Serial.printf(\"I2C_ERRCNT_NOT_ACQ:   %d\\n\", Wire.getErrorCount(I2C_ERRCNT_NOT_ACQ));\n        Serial.printf(\"I2C_ERRCNT_DMA_ERR:   %d\\n\", Wire.getErrorCount(I2C_ERRCNT_DMA_ERR));\n\n        // uncomment to zero all errors after dumping\n        //for(uint8_t i=0; i < I2C_ERRCNT_DMA_ERR; i++) Wire.zeroErrorCount((i2c_err_count)i);\n\n        digitalWrite(LED_BUILTIN,LOW);    // LED off\n        delay(100);                       // 100ms delay\n    }\n}\n\n//\n// Trigger after Tx complete (outgoing I2C data)\n//\nvoid transmitDone(void)\n{\n    Serial.print(\"OK\\n\");\n}\n\n//\n// Trigger after Rx complete (incoming I2C data)\n//\nvoid requestDone(void)\n{\n    Wire.read(databuf, Wire.available());\n    Serial.printf(\"'%s' OK\\n\",databuf);\n}\n\n//\n// Trigger on I2C Error\n//\nvoid errorEvent(void)\n{\n    Serial.print(\"FAIL - \");\n    switch(Wire.status())\n    {\n    case I2C_TIMEOUT:  Serial.print(\"I2C timeout\\n\"); Wire.resetBus(); break;\n    case I2C_ADDR_NAK: Serial.print(\"Slave addr not acknowledged\\n\"); break;\n    case I2C_DATA_NAK: Serial.print(\"Slave data not acknowledged\\n\"); break;\n    case I2C_ARB_LOST: Serial.print(\"Arbitration Lost, possible pullup problem\\n\"); Wire.resetBus(); break;\n    case I2C_BUF_OVF:  Serial.print(\"I2C buffer overflow\\n\"); break;\n    case I2C_NOT_ACQ:  Serial.print(\"Cannot acquire bus, possible stuck SDA/SCL\\n\"); Wire.resetBus(); break;\n    case I2C_DMA_ERR:  Serial.print(\"DMA Error\\n\"); break;\n    default:           break;\n    }\n}\r\n"
  },
  {
    "path": "examples/basic_master_mux/basic_master_mux.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Basic Master Multiplexed\n// -------------------------------------------------------------------------------------------\n//\n// This creates an I2C multiplexed master device which talks to the simple I2C slave device\n// given in the basic_slave sketch.  It is different than the basic_master sketch because it can\n// output I2C commands on either pins 18/19 or pins 16/17 (both using the same I2C bus - Wire), \n// and change pins on-the-fly.\n//\n// The purpose of this sketch is to demonstrate how the pins can be reconfigured on-the-fly \n// when the bus is idle.\n//\n// Pull pin12 low to send command to slave on bus1 (pins 16/17)\n// Pull pin11 low to send command to slave on bus2 (pins 18/19)\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Memory\n#define MEM_LEN 256\nchar databuf[MEM_LEN];\nint count;\nuint8_t pin12, pin11, target = 0x66; // target Slave address\nsize_t idx;\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    digitalWrite(LED_BUILTIN,LOW);  // LED off\n    pinMode(12,INPUT_PULLUP);       // Control for Test1\n    pinMode(11,INPUT_PULLUP);       // Control for Test2\n\n    // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(200000); // 200ms\n\n    // Data init\n    memset(databuf, 0, sizeof(databuf));\n    count = 0;\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    // Send string to Slave\n    //\n    pin12 = (digitalRead(12) == LOW); // latch pin values\n    pin11 = (digitalRead(11) == LOW);\n    if(pin12 || pin11)\n    {\n        // Construct data message\n        sprintf(databuf, \"Data Message #%d\", count++);\n\n        // Change pins\n        if(pin12)\n        {\n            Wire.pinConfigure(I2C_PINS_16_17, I2C_PULLUP_EXT);\n            Serial.printf(\"Sending to Slave 0x%02X on pins 16/17: '%s' \", target, databuf);\n        }\n        else\n        {\n            Wire.pinConfigure(I2C_PINS_18_19, I2C_PULLUP_EXT);\n            Serial.printf(\"Sending to Slave 0x%02X on pins 18/19: '%s' \", target, databuf);\n        }\n        \n        digitalWrite(LED_BUILTIN,HIGH);   // LED on\n        \n        // Transmit to Slave\n        Wire.beginTransmission(target);   // Slave address\n        Wire.write(databuf,strlen(databuf)+1); // Write string to I2C Tx buffer (incl. string null at end)\n        Wire.endTransmission();           // Transmit to Slave\n\n        // Check if error occured\n        if(Wire.getError())\n            Serial.print(\"FAIL\\n\");\n        else\n            Serial.print(\"OK\\n\");\n\n        digitalWrite(LED_BUILTIN,LOW);    // LED off\n        delay(100);                       // Delay to space out tests\n    }\n}\n\r\n"
  },
  {
    "path": "examples/basic_scanner/basic_scanner.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// I2C Bus Scanner\n// -------------------------------------------------------------------------------------------\n//\n// This creates an I2C master device which will scan the address space and report all\n// devices which ACK.  It does not attempt to transfer data, it only reports which devices\n// ACK their address.\n//\n// Pull the control pin low to initiate the scan.  Result will output to Serial.\n//\n// This example code is in the public domain.\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Function prototypes\nvoid print_scan_status(uint8_t target, uint8_t all);\n\nuint8_t found, target, all;\n\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT);    // LED\n    pinMode(12,INPUT_PULLUP);       // pull pin 12 low to show ACK only results\n    pinMode(11,INPUT_PULLUP);       // pull pin 11 low for a more verbose result (shows both ACK and NACK)\n\n    // Setup for Master mode, pins 18/19, external pullups, 400kHz, 10ms default timeout\n    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n    Wire.setDefaultTimeout(10000); // 10ms\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    // Scan I2C addresses\n    //\n    if(digitalRead(12) == LOW || digitalRead(11) == LOW)\n    {\n        all = (digitalRead(11) == LOW);\n        found = 0;\n        \n        Serial.print(\"---------------------------------------------------\\n\");\n        Serial.print(\"Starting scan...\\n\");\n        digitalWrite(LED_BUILTIN,HIGH); // LED on\n        for(target = 1; target <= 0x7F; target++) // sweep addr, skip general call\n        {\n            Wire.beginTransmission(target);       // slave addr\n            Wire.endTransmission();               // no data, just addr\n            print_scan_status(target, all);\n        }\n        digitalWrite(LED_BUILTIN,LOW); // LED off\n\n        if(!found) Serial.print(\"No devices found.\\n\");\n        \n        delay(500); // delay to space out tests\n    }\n}\n\n//\n// print scan status\n//\nvoid print_scan_status(uint8_t target, uint8_t all)\n{\n    switch(Wire.status())\n    {\n    case I2C_WAITING:  \n        Serial.printf(\"Addr: 0x%02X ACK\\n\", target);\n        found = 1;\n        break;\n    case I2C_ADDR_NAK: \n        if(all) Serial.printf(\"Addr: 0x%02X\\n\", target); \n        break;\n    default:\n        break;\n    }\n}\n\r\n"
  },
  {
    "path": "examples/basic_slave/basic_slave.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Basic Slave\n// -------------------------------------------------------------------------------------------\n//\n// This creates a simple I2C Slave device which will print whatever text string is sent to it.\n// It will retain the text string in memory and will send it back to a Master device if \n// requested.  It is intended to pair with a Master device running the basic_master sketch.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Function prototypes\nvoid receiveEvent(size_t count);\nvoid requestEvent(void);\n\n// Memory\n#define MEM_LEN 256\nchar databuf[MEM_LEN];\nvolatile uint8_t received;\n\n//\n// Setup\n//\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT); // LED\n\n    // Setup for Slave mode, address 0x66, pins 18/19, external pullups, 400kHz\n    Wire.begin(I2C_SLAVE, 0x66, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n\n    // Data init\n    received = 0;\n    memset(databuf, 0, sizeof(databuf));\n\n    // register events\n    Wire.onReceive(receiveEvent);\n    Wire.onRequest(requestEvent);\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    // print received data - this is done in main loop to keep time spent in I2C ISR to minimum\n    if(received)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);\n        Serial.printf(\"Slave received: '%s'\\n\", databuf);\n        received = 0;\n        digitalWrite(LED_BUILTIN,LOW);\n    }\n}\n\n//\n// handle Rx Event (incoming I2C data)\n//\nvoid receiveEvent(size_t count)\n{\n    Wire.read(databuf, count);  // copy Rx data to databuf\n    received = count;           // set received flag to count, this triggers print in main loop\n}\n\n//\n// handle Tx Event (outgoing I2C data)\n//\nvoid requestEvent(void)\n{\n    Wire.write(databuf, MEM_LEN); // fill Tx buffer (send full mem)\n}\n\r\n"
  },
  {
    "path": "examples/basic_slave_range/basic_slave_range.ino",
    "content": "// -------------------------------------------------------------------------------------------\n// Basic Slave with Address Range\n// -------------------------------------------------------------------------------------------\n//\n// This creates a simple I2C Slave device which will print whatever text string is sent to it.\n// It will retain the text string in memory and will send it back to a Master device if \n// requested.  It is intended to pair with a Master device running the basic_master sketch.\n//\n// The Slave will respond to a range of I2C addresses.  It demonstrates use of the getRxAddr() \n// function which can be used to obtain the Slave address.  This allows a single device to \n// act as multiple different Slave targets.\n//\n// This example code is in the public domain.\n//\n// -------------------------------------------------------------------------------------------\n\n#include <i2c_t3.h>\n\n// Function prototypes\nvoid receiveEvent(size_t len);\nvoid requestEvent(void);\n\n// Memory\n#define MEM_LEN 256\nuint8_t databuf[MEM_LEN];\nvolatile uint8_t target;\nvolatile uint8_t received;\n\n//\n// Setup\n//\nvoid setup()\n{\n    pinMode(LED_BUILTIN,OUTPUT); // LED\n\n    // Setup for Slave mode, addresses 0x08 to 0x77, pins 18/19, external pullups, 400kHz\n    Wire.begin(I2C_SLAVE, 0x08, 0x77, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);\n\n    // Data init\n    received = 0;\n    target = 0;\n    memset(databuf, 0, sizeof(databuf));\n\n    // register events\n    Wire.onReceive(receiveEvent);\n    Wire.onRequest(requestEvent);\n\n    Serial.begin(115200);\n}\n\nvoid loop()\n{\n    // print received data\n    if(received)\n    {\n        digitalWrite(LED_BUILTIN,HIGH);\n        Serial.printf(\"Slave 0x%02X received: '%s'\\n\", target, (char*)databuf);\n        received = 0;\n        digitalWrite(LED_BUILTIN,LOW);\n    }\n}\n\n//\n// handle Rx Event (incoming I2C data)\n//\nvoid receiveEvent(size_t count)\n{\n    target = Wire.getRxAddr();  // getRxAddr() is used to obtain Slave address\n    Wire.read(databuf, count);  // copy Rx data to databuf\n    received = count;           // set received flag to count, this triggers print in main loop\n}\n\n//\n// handle Tx Event (outgoing I2C data)\n//\nvoid requestEvent(void)\n{\n    Wire.write(databuf, MEM_LEN); // fill Tx buffer (send full mem)\n}\n\r\n"
  },
  {
    "path": "i2c_t3.cpp",
    "content": "/*\n    ------------------------------------------------------------------------------------------------------\n    i2c_t3 - I2C library for Teensy 3.x & LC\n\n    - (v11.0) Modified 01Dec18 by Brian (nox771 at gmail.com)\n\n    Full changelog at end of file\n    ------------------------------------------------------------------------------------------------------\n    Copyright (c) 2013-2018, Brian (nox771 at gmail.com)\n\n    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and \n    associated documentation files (the \"Software\"), to deal in the Software without restriction, \n    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, \n    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, \n    subject to the following conditions:\n\n    The above copyright notice and this permission notice shall be included in all copies or substantial \n    portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \n    LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION \n    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    ------------------------------------------------------------------------------------------------------\n*/\n\n#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || \\\n    defined(__MK64FX512__) || defined(__MK66FX1M0__) // 3.0/3.1-3.2/LC/3.5/3.6\n\n#include \"i2c_t3.h\"\n\n\n// ------------------------------------------------------------------------------------------------------\n// Static inits\n//\n#define I2C_STRUCT(a1,f,c1,s,d,c2,flt,ra,smb,a2,slth,sltl,scl,sda) \\\n    {a1, f, c1, s, d, c2, flt, ra, smb, a2, slth, sltl, {}, 0, 0, {}, 0, 0, I2C_OP_MODE_ISR, I2C_MASTER, scl, sda, I2C_PULLUP_EXT, 100000, \\\n     I2C_STOP, I2C_WAITING, 0, 0, 0, 0, I2C_DMA_OFF, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 0, {}, 0, 0 }\n\nstruct i2cStruct i2c_t3::i2cData[] =\n{\n    I2C_STRUCT(&I2C0_A1, &I2C0_F, &I2C0_C1, &I2C0_S, &I2C0_D, &I2C0_C2, &I2C0_FLT, &I2C0_RA, &I2C0_SMB, &I2C0_A2, &I2C0_SLTH, &I2C0_SLTL, 19, 18)\n#if (I2C_BUS_NUM >= 2) && defined(__MK20DX256__) // 3.1/3.2\n   ,I2C_STRUCT(&I2C1_A1, &I2C1_F, &I2C1_C1, &I2C1_S, &I2C1_D, &I2C1_C2, &I2C1_FLT, &I2C1_RA, &I2C1_SMB, &I2C1_A2, &I2C1_SLTH, &I2C1_SLTL, 29, 30)\n#elif (I2C_BUS_NUM >= 2) && defined(__MKL26Z64__) // LC\n   ,I2C_STRUCT(&I2C1_A1, &I2C1_F, &I2C1_C1, &I2C1_S, &I2C1_D, &I2C1_C2, &I2C1_FLT, &I2C1_RA, &I2C1_SMB, &I2C1_A2, &I2C1_SLTH, &I2C1_SLTL, 22, 23)\n#elif (I2C_BUS_NUM >= 2) && (defined(__MK64FX512__) || defined(__MK66FX1M0__))  // 3.5/3.6\n   ,I2C_STRUCT(&I2C1_A1, &I2C1_F, &I2C1_C1, &I2C1_S, &I2C1_D, &I2C1_C2, &I2C1_FLT, &I2C1_RA, &I2C1_SMB, &I2C1_A2, &I2C1_SLTH, &I2C1_SLTL, 37, 38)\n#endif\n#if (I2C_BUS_NUM >= 3) && (defined(__MK64FX512__) || defined(__MK66FX1M0__))  // 3.5/3.6\n   ,I2C_STRUCT(&I2C2_A1, &I2C2_F, &I2C2_C1, &I2C2_S, &I2C2_D, &I2C2_C2, &I2C2_FLT, &I2C2_RA, &I2C2_SMB, &I2C2_A2, &I2C2_SLTH, &I2C2_SLTL, 3, 4)\n#endif\n#if (I2C_BUS_NUM >= 4) && defined(__MK66FX1M0__) // 3.6\n   ,I2C_STRUCT(&I2C3_A1, &I2C3_F, &I2C3_C1, &I2C3_S, &I2C3_D, &I2C3_C2, &I2C3_FLT, &I2C3_RA, &I2C3_SMB, &I2C3_A2, &I2C3_SLTH, &I2C3_SLTL, 57, 56)\n#endif\n};\n\nvolatile uint8_t i2c_t3::isrActive = 0;\n\n\n// ------------------------------------------------------------------------------------------------------\n// Constructor/Destructor\n//\ni2c_t3::i2c_t3(uint8_t i2c_bus)\n{\n    bus = i2c_bus;\n    i2c = &i2cData[bus];\n}\ni2c_t3::~i2c_t3()\n{\n    // if DMA active, delete DMA object\n    if(i2c->opMode == I2C_OP_MODE_DMA)\n        delete i2c->DMA;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Initialize I2C - initializes I2C as Master or address range Slave\n// return: none\n// parameters (optional parameters marked '^'):\n//      mode = I2C_MASTER, I2C_SLAVE\n//      address1 = 7bit slave address when configured as Slave (ignored for Master mode)\n//    ^ address2 = 2nd 7bit address for specifying Slave address range (ignored for Master mode)\n//    ^ pins = pins to use, can be specified as 'i2c_pins' enum,\n//             or as 'SCL,SDA' pair (using any valid SCL or SDA), options are:\n//                                 Pin Name\n//          Interface  Devices   (deprecated)    SCL    SDA\n//          ---------  -------  --------------  -----  -----    (note: in almost all cases SCL is the\n//             Wire      All    I2C_PINS_16_17    16     17      lower pin #, except cases marked *)\n//             Wire      All    I2C_PINS_18_19    19     18  *\n//             Wire    3.5/3.6  I2C_PINS_7_8       7      8\n//             Wire    3.5/3.6  I2C_PINS_33_34    33     34\n//             Wire    3.5/3.6  I2C_PINS_47_48    47     48\n//            Wire1       LC    I2C_PINS_22_23    22     23\n//            Wire1    3.1/3.2  I2C_PINS_26_31    26     31\n//            Wire1    3.1/3.2  I2C_PINS_29_30    29     30\n//            Wire1    3.5/3.6  I2C_PINS_37_38    37     38\n//            Wire2    3.5/3.6  I2C_PINS_3_4       3      4\n//            Wire3      3.6    I2C_PINS_56_57    57     56  *\n//    ^ pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT\n//    ^ rate = I2C frequency to use, can be specified directly in Hz, eg. 400000 for 400kHz, or using one of the\n//             following enum values (deprecated):\n//             I2C_RATE_100, I2C_RATE_200, I2C_RATE_300, I2C_RATE_400,\n//             I2C_RATE_600, I2C_RATE_800, I2C_RATE_1000, I2C_RATE_1200,\n//             I2C_RATE_1500, I2C_RATE_1800, I2C_RATE_2000, I2C_RATE_2400,\n//             I2C_RATE_2800, I2C_RATE_3000\n//    ^ opMode = I2C_OP_MODE_IMM, I2C_OP_MODE_ISR, I2C_OP_MODE_DMA (ignored for Slave mode, defaults to ISR)\n//\nvoid i2c_t3::begin_(struct i2cStruct* i2c, uint8_t bus, i2c_mode mode, uint8_t address1, uint8_t address2,\n                    uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup, uint32_t rate, i2c_op_mode opMode)\n{\n    // Enable I2C internal clock\n    if(bus == 0)\n        SIM_SCGC4 |= SIM_SCGC4_I2C0;\n    #if I2C_BUS_NUM >= 2\n        if(bus == 1)\n            SIM_SCGC4 |= SIM_SCGC4_I2C1;\n    #endif\n    #if I2C_BUS_NUM >= 3\n        if(bus == 2)\n            SIM_SCGC1 |= SIM_SCGC1_I2C2;\n    #endif\n    #if I2C_BUS_NUM >= 4\n        if(bus == 3)\n            SIM_SCGC1 |= SIM_SCGC1_I2C3;\n    #endif\n\n    i2c->currentMode = mode; // Set mode\n    i2c->currentStatus = I2C_WAITING; // reset status\n\n    // Set Master/Slave address\n    if(i2c->currentMode == I2C_MASTER)\n    {\n        *(i2c->C2) = I2C_C2_HDRS; // Set high drive select\n        //*(i2c->A1) = 0;\n        //*(i2c->RA) = 0;\n    }\n    else\n    {\n        *(i2c->C2) = (address2) ? (I2C_C2_HDRS|I2C_C2_RMEN) // Set high drive select and range-match enable\n                                : I2C_C2_HDRS;              // Set high drive select\n        // set Slave address, if two addresses are given, setup range and put lower address in A1, higher in RA\n        *(i2c->A1) = (address2) ? ((address1 < address2) ? (address1<<1) : (address2<<1))\n                                : (address1<<1);\n        *(i2c->RA) = (address2) ? ((address1 < address2) ? (address2<<1) : (address1<<1))\n                                : 0;\n    }\n\n    // Setup pins - As noted in original TwoWire.cpp, internal 3.0/3.1/3.2 pullup is strong (about 190 ohms), \n    // but it can work if other devices on bus have strong enough pulldowns.\n    //\n    if(!pinSCL) pinSCL = i2c->currentSCL; // if either pin specified as 0, then use current settings\n    if(!pinSDA) pinSDA = i2c->currentSDA;\n    pinConfigure_(i2c, bus, pinSCL, pinSDA, pullup, i2c->configuredSCL, i2c->configuredSDA);\n\n    // Set I2C rate\n    #if defined(__MKL26Z64__) // LC\n        if(bus == 1)\n            setRate_(i2c, (uint32_t)F_CPU, rate); // LC Wire1 bus uses system clock (F_CPU) instead of bus clock (F_BUS)\n        else\n            setRate_(i2c, (uint32_t)F_BUS, rate);\n    #else\n        setRate_(i2c, (uint32_t)F_BUS, rate);\n    #endif\n\n    // Set config registers and operating mode\n    setOpMode_(i2c, bus, opMode);\n    if(i2c->currentMode == I2C_MASTER)\n        *(i2c->C1) = I2C_C1_IICEN; // Master - enable I2C (hold in Rx mode, intr disabled)\n    else\n        *(i2c->C1) = I2C_C1_IICEN|I2C_C1_IICIE; // Slave - enable I2C and interrupts\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Valid pin checks - verify if SCL or SDA pin is valid on given bus, intended for internal use only\n// return: alt setting, 0=not valid\n// parameters:\n//      bus = bus number\n//      pin = pin number to check\n//      offset = array offset\n//\nuint8_t i2c_t3::validPin_(uint8_t bus, uint8_t pin, uint8_t offset)\n{\n    for(uint8_t idx=0; idx < I2C_PINS_COUNT-1; idx++)\n        if(i2c_valid_pins[idx*4] == bus && i2c_valid_pins[idx*4+offset] == pin) return i2c_valid_pins[idx*4+3];\n    return 0;\n}\n\n\n// Set Operating Mode - this configures operating mode of the I2C as either Immediate, ISR, or DMA.\n//                      By default Arduino-style begin() calls will initialize to ISR mode.  This can\n//                      only be called when the bus is idle (no changing mode in the middle of Tx/Rx).\n//                      Note that Slave mode can only use ISR operation.\n// return: 1=success, 0=fail (bus busy)\n// parameters:\n//      opMode = I2C_OP_MODE_ISR, I2C_OP_MODE_DMA, I2C_OP_MODE_IMM\n//\nuint8_t i2c_t3::setOpMode_(struct i2cStruct* i2c, uint8_t bus, i2c_op_mode opMode)\n{\n    if(*(i2c->S) & I2C_S_BUSY) return 0; // return immediately if bus busy\n\n    *(i2c->C1) = I2C_C1_IICEN; // reset I2C modes, stop intr, stop DMA\n    *(i2c->S) = I2C_S_IICIF | I2C_S_ARBL; // clear status flags just in case\n\n    // Slaves can only use ISR\n    if(i2c->currentMode == I2C_SLAVE) opMode = I2C_OP_MODE_ISR;\n\n    if(opMode == I2C_OP_MODE_IMM)\n    {\n        i2c->opMode = I2C_OP_MODE_IMM;\n    }\n    if(opMode == I2C_OP_MODE_ISR || opMode == I2C_OP_MODE_DMA)\n    {\n        // Nested Vec Interrupt Ctrl - enable I2C interrupt\n        if(bus == 0)\n        {\n            NVIC_ENABLE_IRQ(IRQ_I2C0);\n            I2C0_INTR_FLAG_INIT; // init I2C0 interrupt flag if used\n        }\n        #if I2C_BUS_NUM >= 2\n            if(bus == 1)\n            {\n                NVIC_ENABLE_IRQ(IRQ_I2C1);\n                I2C1_INTR_FLAG_INIT; // init I2C1 interrupt flag if used\n            }\n        #endif\n        #if I2C_BUS_NUM >= 3\n            if(bus == 2)\n            {\n                NVIC_ENABLE_IRQ(IRQ_I2C2);\n                I2C2_INTR_FLAG_INIT; // init I2C2 interrupt flag if used\n            }\n        #endif\n        #if I2C_BUS_NUM >= 4\n            if(bus == 3)\n            {\n                NVIC_ENABLE_IRQ(IRQ_I2C3);\n                I2C3_INTR_FLAG_INIT; // init I2C3 interrupt flag if used\n            }\n        #endif\n        if(opMode == I2C_OP_MODE_DMA)\n        {\n            // attempt to get a DMA Channel (if not already allocated)\n            if(i2c->DMA == nullptr)\n                i2c->DMA = new DMAChannel();\n            // check if object created but no available channel\n            if(i2c->DMA != nullptr && i2c->DMA->channel == DMA_NUM_CHANNELS)\n            {\n                // revert to ISR mode if no DMA channels avail\n                delete i2c->DMA;\n                i2c->DMA = nullptr;\n                i2c->opMode = I2C_OP_MODE_ISR;\n            }\n            else\n            {\n                // DMA object has valid channel\n                if(bus == 0)\n                {\n                    // setup static DMA settings\n                    i2c->DMA->disableOnCompletion();\n                    i2c->DMA->attachInterrupt(i2c0_isr);\n                    i2c->DMA->interruptAtCompletion();\n                    i2c->DMA->triggerAtHardwareEvent(DMAMUX_SOURCE_I2C0);\n                }\n                #if I2C_BUS_NUM >= 2\n                    if(bus == 1)\n                    {\n                        // setup static DMA settings\n                        i2c->DMA->disableOnCompletion();\n                        i2c->DMA->attachInterrupt(i2c1_isr);\n                        i2c->DMA->interruptAtCompletion();\n                        i2c->DMA->triggerAtHardwareEvent(DMAMUX_SOURCE_I2C1);\n                    }\n                #endif\n                #if I2C_BUS_NUM >= 3\n                    // note: on T3.6 I2C2 shares DMAMUX with I2C1\n                    if(bus == 2)\n                    {\n                        // setup static DMA settings\n                        i2c->DMA->disableOnCompletion();\n                        i2c->DMA->attachInterrupt(i2c2_isr);\n                        i2c->DMA->interruptAtCompletion();\n                        i2c->DMA->triggerAtHardwareEvent(DMAMUX_SOURCE_I2C2);\n                    }\n                #endif\n                #if I2C_BUS_NUM >= 4\n                    // note: on T3.6 I2C3 shares DMAMUX with I2C0\n                    if(bus == 3)\n                    {\n                        // setup static DMA settings\n                        i2c->DMA->disableOnCompletion();\n                        i2c->DMA->attachInterrupt(i2c3_isr);\n                        i2c->DMA->interruptAtCompletion();\n                        i2c->DMA->triggerAtHardwareEvent(DMAMUX_SOURCE_I2C3);\n                    }\n                #endif\n                i2c->activeDMA = I2C_DMA_OFF;\n                i2c->opMode = I2C_OP_MODE_DMA;\n            }\n        }\n        else\n            i2c->opMode = I2C_OP_MODE_ISR;\n    }\n    return 1;\n}\n\n\n// Set I2C rate - reconfigures I2C frequency divider based on supplied bus freq and desired I2C freq.\n//                This will be done assuming an idealized I2C rate, even though at high I2C rates\n//                the actual throughput is much lower than theoretical value.\n//\n//                Since the division ratios are quantized with non-uniform spacing, the selected rate\n//                will be the one using the nearest available divider.\n// return: none\n// parameters:\n//      busFreq = bus frequency, typically F_BUS unless reconfigured\n//      freq = desired I2C frequency (will be quantized to nearest rate), or can be I2C_RATE_XXX enum (deprecated),\n//             such as I2C_RATE_100, I2C_RATE_400, etc...\n//\n// Max I2C rate is 1/20th F_BUS.  Some examples:\n//\n//     F_CPU      F_BUS     Max I2C\n//     (MHz)      (MHz)       Rate\n// -------------  -----    ----------\n//    240/120      120        6.0M    bus overclock\n//      216        108        5.4M    bus overclock\n//     192/96       96        4.8M    bus overclock\n//      180         90        4.5M    bus overclock\n//      240         80        4.0M    bus overclock\n//   216/144/72     72        3.6M    bus overclock\n//      192         64        3.2M    bus overclock\n//  240/180/120     60        3.0M\n//      168         56        2.8M\n//      216         54        2.7M\n// 192/144/96/48    48        2.4M\n//       72         36        1.8M\n//       24         24        1.2M\n//       16         16        800k\n//        8          8        400k\n//        4          4        200k\n//        2          2        100k\n//\nvoid i2c_t3::setRate_(struct i2cStruct* i2c, uint32_t busFreq, uint32_t i2cFreq)\n{\n    int32_t target_div = ((busFreq/1000)<<8)/(i2cFreq/1000);\n    size_t idx;\n    // find closest divide ratio\n    for(idx=0; idx < sizeof(i2c_div_num)/sizeof(i2c_div_num[0]) && (i2c_div_num[idx]<<8) <= target_div; idx++);\n    if(idx && abs(target_div-(i2c_div_num[idx-1]<<8)) <= abs(target_div-(i2c_div_num[idx]<<8))) idx--;\n    // Set divider to set rate\n    *(i2c->F) = i2c_div_ratio[idx];\n    // save current rate setting\n    i2c->currentRate = busFreq/i2c_div_num[idx];\n\n    // Set filter\n    if(busFreq >= 48000000)\n        *(i2c->FLT) = 4;\n    else\n        *(i2c->FLT) = busFreq/12000000;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Configure I2C pins - reconfigures active I2C pins on-the-fly (only works when bus is idle).  If reconfig\n//                      set then inactive pins will switch to input mode using same pullup configuration.\n// return: 1=success, 0=fail (bus busy or incompatible pins)\n// parameters:\n//      pins = pins to use, can be specified as 'i2c_pins' enum,\n//             or as 'SCL,SDA' pair (using any valid SCL or SDA), options are:\n//                                 Pin Name\n//          Interface  Devices   (deprecated)    SCL    SDA\n//          ---------  -------  --------------  -----  -----    (note: in almost all cases SCL is the\n//             Wire      All    I2C_PINS_16_17    16     17      lower pin #, except cases marked *)\n//             Wire      All    I2C_PINS_18_19    19     18  *\n//             Wire    3.5/3.6  I2C_PINS_7_8       7      8\n//             Wire    3.5/3.6  I2C_PINS_33_34    33     34\n//             Wire    3.5/3.6  I2C_PINS_47_48    47     48\n//            Wire1       LC    I2C_PINS_22_23    22     23\n//            Wire1    3.1/3.2  I2C_PINS_26_31    26     31\n//            Wire1    3.1/3.2  I2C_PINS_29_30    29     30\n//            Wire1    3.5/3.6  I2C_PINS_37_38    37     38\n//            Wire2    3.5/3.6  I2C_PINS_3_4       3      4\n//            Wire3      3.6    I2C_PINS_56_57    57     56  *\n//      pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT\n//      reconfig = 1=reconfigure old pins, 0=do not reconfigure old pins (base routine only)\n//\n#define PIN_CONFIG_ALT(name,alt) uint32_t name = (pullup == I2C_PULLUP_EXT) ? (PORT_PCR_MUX(alt)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE) \\\n                                                                            : (PORT_PCR_MUX(alt)|PORT_PCR_PE|PORT_PCR_PS)\n\nuint8_t i2c_t3::pinConfigure_(struct i2cStruct* i2c, uint8_t bus, uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup, \n                              uint8_t configuredSCL, uint8_t configuredSDA)\n{\n    uint8_t validAltSCL, validAltSDA;\n    volatile uint32_t* pcr;\n\n    if((configuredSCL && configuredSDA) && (*(i2c->S) & I2C_S_BUSY)) return 0; // if configured return immediately if bus busy\n\n    // Verify new SCL pin is different or not configured, and valid\n    //\n    validAltSCL = validPin_(bus, pinSCL, 1);\n    if((pinSCL != i2c->currentSCL || !configuredSCL) && validAltSCL)\n    {\n        // If configured, switch previous pin to non-I2C input\n        if(configuredSCL) pinMode(i2c->currentSCL, (i2c->currentPullup == I2C_PULLUP_EXT) ? INPUT : INPUT_PULLUP);\n        // Config new pin\n        PIN_CONFIG_ALT(configSCL, validAltSCL);\n        pcr = portConfigRegister(pinSCL);\n        *pcr = configSCL;\n        i2c->currentSCL = pinSCL;\n        i2c->currentPullup = pullup;\n        i2c->configuredSCL = 1;\n    }\n\n    // Verify new SDA pin is different or not configured, and valid\n    //\n    validAltSDA = validPin_(bus, pinSDA, 2);\n    if((pinSDA != i2c->currentSDA || !configuredSDA) && validAltSDA) \n    {\n        // If reconfig set, switch previous pin to non-I2C input\n        if(configuredSDA) pinMode(i2c->currentSDA, (i2c->currentPullup == I2C_PULLUP_EXT) ? INPUT : INPUT_PULLUP);\n        // Config new pin\n        PIN_CONFIG_ALT(configSDA, validAltSDA);\n        pcr = portConfigRegister(pinSDA);\n        *pcr = configSDA;\n        i2c->currentSDA = pinSDA;\n        i2c->currentPullup = pullup;\n        i2c->configuredSDA = 1;\n    }\n\n    return (validAltSCL && validAltSDA);\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Acquire Bus - acquires bus in Master mode and escalates priority as needed, intended\n//               for internal use only\n// return: 1=success, 0=fail (cannot acquire bus)\n// parameters:\n//      timeout = timeout in microseconds\n//      forceImm = flag to indicate if immediate mode is required\n//\nuint8_t i2c_t3::acquireBus_(struct i2cStruct* i2c, uint8_t bus, uint32_t timeout, uint8_t& forceImm)\n{\n    elapsedMicros deltaT;\n\n    // update timeout\n    timeout = (timeout == 0) ? i2c->defTimeout : timeout;\n\n    // TODO may need to check bus busy before issuing START if multi-master\n\n    // start timer, then take control of the bus\n    deltaT = 0;\n    if(*(i2c->C1) & I2C_C1_MST)\n    {\n        // we are already the bus master, so send a repeated start\n        *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX;\n    }\n    else\n    {\n        while(timeout == 0 || deltaT < timeout)\n        {\n            // we are not currently the bus master, so check if bus ready\n            if(!(*(i2c->S) & I2C_S_BUSY))\n            {\n                // become the bus master in transmit mode (send start)\n                i2c->currentMode = I2C_MASTER;\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;\n                break;\n            }\n        }\n        #if defined(I2C_AUTO_RETRY)\n            // if not master and auto-retry set, then reset bus and try one last time\n            if(!(*(i2c->C1) & I2C_C1_MST))\n            {\n                resetBus_(i2c,bus);\n                I2C_ERR_INC(I2C_ERRCNT_RESET_BUS);\n                if(!(*(i2c->S) & I2C_S_BUSY))\n                {\n                    // become the bus master in transmit mode (send start)\n                    i2c->currentMode = I2C_MASTER;\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;\n                }\n            }\n        #endif\n        // check if not master\n        if(!(*(i2c->C1) & I2C_C1_MST))\n        {\n            i2c->currentStatus = I2C_NOT_ACQ; // bus not acquired\n            I2C_ERR_INC(I2C_ERRCNT_NOT_ACQ);\n            if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if cannot acquire bus\n            return 0;\n        }\n    }\n\n    #ifndef I2C_DISABLE_PRIORITY_CHECK\n        // For ISR operation, check if current routine has higher priority than I2C IRQ, and if so\n        // either escalate priority of I2C IRQ or send I2C using immediate mode.\n        //\n        // This check is disabled if the routine is called during an active I2C ISR (assumes it is\n        // called from ISR callback).  This is to prevent runaway escalation with nested Wire calls.\n        //\n        int irqPriority, currPriority;\n        if(!i2c_t3::isrActive && (i2c->opMode == I2C_OP_MODE_ISR || i2c->opMode == I2C_OP_MODE_DMA))\n        {\n            currPriority = nvic_execution_priority();\n            switch(bus)\n            {\n            case 0:  irqPriority = NVIC_GET_PRIORITY(IRQ_I2C0); break;\n            #if defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.1/3.2/3.5/3.6\n            case 1:  irqPriority = NVIC_GET_PRIORITY(IRQ_I2C1); break;\n            #endif\n            #if defined(__MK64FX512__) || defined(__MK66FX1M0__) // 3.5/3.6\n            case 2:  irqPriority = NVIC_GET_PRIORITY(IRQ_I2C2); break;\n            #endif\n            #if defined(__MK66FX1M0__) // 3.6\n            case 3:  irqPriority = NVIC_GET_PRIORITY(IRQ_I2C3); break;\n            #endif\n            default: irqPriority = NVIC_GET_PRIORITY(IRQ_I2C0); break;\n            }\n            if(currPriority <= irqPriority)\n            {\n                if(currPriority < 16)\n                    forceImm = 1; // current priority cannot be surpassed, force Immediate mode\n                else\n                {\n                    switch(bus)\n                    {\n                    case 0:  NVIC_SET_PRIORITY(IRQ_I2C0, currPriority-16); break;\n                    #if defined(__MKL26Z64__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.1/3.2/3.5/3.6\n                    case 1:  NVIC_SET_PRIORITY(IRQ_I2C1, currPriority-16); break;\n                    #endif\n                    #if defined(__MK64FX512__) || defined(__MK66FX1M0__) // 3.5/3.6\n                    case 2:  NVIC_SET_PRIORITY(IRQ_I2C2, currPriority-16); break;\n                    #endif\n                    #if defined(__MK66FX1M0__) // 3.6\n                    case 3:  NVIC_SET_PRIORITY(IRQ_I2C3, currPriority-16); break;\n                    #endif\n                    default: NVIC_SET_PRIORITY(IRQ_I2C0, currPriority-16); break;\n                    }\n                }\n            }\n        }\n    #endif\n\n    return 1;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Reset Bus - toggles SCL until SDA line is released (9 clocks max).  This is used to correct\n//             a hung bus in which a Slave device missed some clocks and remains stuck outputting\n//             a low signal on SDA (thereby preventing START/STOP signaling).\n// return: none\n//\nvoid i2c_t3::resetBus_(struct i2cStruct* i2c, uint8_t bus)\n{\n    uint8_t scl = i2c->currentSCL;\n    uint8_t sda = i2c->currentSDA;\n\n    // change pin mux to digital I/O\n    pinMode(sda,((i2c->currentPullup == I2C_PULLUP_EXT) ? INPUT : INPUT_PULLUP));\n    digitalWrite(scl,HIGH);\n    pinMode(scl,OUTPUT);\n\n    for(uint8_t count=0; digitalRead(sda) == 0 && count < 9; count++)\n    {\n        digitalWrite(scl,LOW);\n        delayMicroseconds(5);       // 10us period == 100kHz\n        digitalWrite(scl,HIGH);\n        delayMicroseconds(5);\n    }\n\n    // reconfigure pins for I2C\n    pinConfigure_(i2c, bus, scl, sda, i2c->currentPullup, 0, 0);\n\n    // reset config and status\n    if(*(i2c->S) & 0x7F) // reset config if any residual status bits are set\n    {\n        *(i2c->C1) = 0x00; // disable I2C, intr disabled\n        delayMicroseconds(5);\n        *(i2c->C1) = I2C_C1_IICEN; // enable I2C, intr disabled, Rx mode\n        delayMicroseconds(5);\n    }\n    i2c->currentStatus = I2C_WAITING;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Setup Master Transmit - initialize Tx buffer for transmit to slave at address\n// return: none\n// parameters:\n//      address = target 7bit slave address\n//\nvoid i2c_t3::beginTransmission(uint8_t address)\n{\n    i2c->txBuffer[0] = (address << 1); // store target addr\n    i2c->txBufferLength = 1;\n    clearWriteError(); // clear any previous write error\n    i2c->currentStatus = I2C_WAITING; // reset status\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Master Transmit - blocking routine with timeout, transmits Tx buffer to slave. i2c_stop parameter can be used\n//                   to indicate if command should end with a STOP(I2C_STOP) or not (I2C_NOSTOP).\n// return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error\n// parameters:\n//      i2c_stop = I2C_NOSTOP, I2C_STOP\n//      timeout = timeout in microseconds\n//\nuint8_t i2c_t3::endTransmission(struct i2cStruct* i2c, uint8_t bus, i2c_stop sendStop, uint32_t timeout)\n{\n    sendTransmission_(i2c, bus, sendStop, timeout);\n\n    // wait for completion or timeout\n    finish_(i2c, bus, timeout);\n\n    return getError();\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Send Master Transmit - non-blocking routine, starts transmit of Tx buffer to slave. i2c_stop parameter can be\n//                        used to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use\n//                        done() or finish() to determine completion and status() to determine success/fail.\n// return: none\n// parameters:\n//      i2c_stop = I2C_NOSTOP, I2C_STOP\n//      timeout = timeout in microseconds (only used for Immediate operation)\n//\nvoid i2c_t3::sendTransmission_(struct i2cStruct* i2c, uint8_t bus, i2c_stop sendStop, uint32_t timeout)\n{\n    uint8_t status, forceImm=0;\n    size_t idx;\n\n    // exit immediately if sending 0 bytes\n    if(i2c->txBufferLength == 0) return;\n\n    // update timeout\n    timeout = (timeout == 0) ? i2c->defTimeout : timeout;\n\n    // clear the status flags\n    #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n        *(i2c->FLT) |= I2C_FLT_STOPF | I2C_FLT_STARTF;  // clear STOP/START intr\n        *(i2c->FLT) &= ~I2C_FLT_SSIE;                   // disable STOP/START intr (not used in Master mode)\n    #endif\n    *(i2c->S) = I2C_S_IICIF | I2C_S_ARBL; // clear intr, arbl\n\n    // try to take control of the bus\n    if(!acquireBus_(i2c, bus, timeout, forceImm)) return;\n\n    //\n    // Immediate mode - blocking\n    //\n    if(i2c->opMode == I2C_OP_MODE_IMM || forceImm)\n    {\n        elapsedMicros deltaT;\n        i2c->currentStatus = I2C_SENDING;\n        i2c->currentStop = sendStop;\n\n        for(idx=0; idx < i2c->txBufferLength && (timeout == 0 || deltaT < timeout); idx++)\n        {\n            // send data, wait for done\n            *(i2c->D) = i2c->txBuffer[idx];\n\n            // wait for byte\n            while(!(*(i2c->S) & I2C_S_IICIF) && (timeout == 0 || deltaT < timeout));\n            *(i2c->S) = I2C_S_IICIF;\n            if(timeout && deltaT >= timeout) break;\n\n            status = *(i2c->S);\n\n            // check arbitration\n            if(status & I2C_S_ARBL)\n            {\n                i2c->currentStatus = I2C_ARB_LOST;\n                *(i2c->S) = I2C_S_ARBL; // clear arbl flag\n                // TODO: this is clearly not right, after ARBL it should drop into IMM slave mode if IAAS=1\n                //       Right now Rx message would be ignored regardless of IAAS\n                *(i2c->C1) = I2C_C1_IICEN; // change to Rx mode, intr disabled (does this send STOP if ARBL flagged?)\n                I2C_ERR_INC(I2C_ERRCNT_ARBL);\n                if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if ARBL\n                return;\n            }\n            // check if slave ACK'd\n            else if(status & I2C_S_RXAK)\n            {\n                if(idx == 0)\n                {\n                    i2c->currentStatus = I2C_ADDR_NAK; // NAK on Addr\n                    I2C_ERR_INC(I2C_ERRCNT_ADDR_NAK);\n                }\n                else\n                {\n                    i2c->currentStatus = I2C_DATA_NAK; // NAK on Data\n                    I2C_ERR_INC(I2C_ERRCNT_DATA_NAK);\n                }\n                *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n                if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if NAK\n                return;\n            }\n        }\n\n        // send STOP if configured\n        if(i2c->currentStop == I2C_STOP)\n            *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n        else\n            *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; // no STOP, stay in Tx mode, intr disabled\n\n        // Set final status\n        if(idx < i2c->txBufferLength)\n        {\n            i2c->currentStatus = I2C_TIMEOUT; // Tx incomplete, mark as timeout\n            I2C_ERR_INC(I2C_ERRCNT_TIMEOUT);\n            if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if timeout\n        }\n        else\n        {\n            i2c->currentStatus = I2C_WAITING; // Tx complete, change to waiting state\n            if(i2c->user_onTransmitDone != nullptr) i2c->user_onTransmitDone(); // Call Master Tx complete callback\n        }\n    }\n    //\n    // ISR/DMA mode - non-blocking\n    //\n    else if(i2c->opMode == I2C_OP_MODE_ISR || i2c->opMode == I2C_OP_MODE_DMA)\n    {\n        // send target addr and enable interrupts\n        i2c->currentStatus = I2C_SENDING;\n        i2c->currentStop = sendStop;\n        i2c->txBufferIndex = 0;\n        if(i2c->opMode == I2C_OP_MODE_DMA && i2c->txBufferLength >= 5) // limit transfers less than 5 bytes to ISR method\n        {\n            // init DMA, let the hack begin\n            i2c->activeDMA = I2C_DMA_ADDR;\n            i2c->DMA->sourceBuffer(&i2c->txBuffer[2],i2c->txBufferLength-3); // DMA sends all except first/second/last bytes\n            i2c->DMA->destination(*(i2c->D));\n        }\n        // start ISR\n        *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX; // enable intr\n        *(i2c->D) = i2c->txBuffer[0]; // writing first data byte will start ISR\n    }\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Master Receive - blocking routine with timeout, requests length bytes from slave at address. Receive data will\n//                  be placed in the Rx buffer. i2c_stop parameter can be used to indicate if command should end\n//                  with a STOP (I2C_STOP) or not (I2C_NOSTOP).\n// return: #bytes received = success, 0=fail (0 length request, NAK, timeout, or bus error)\n// parameters:\n//      address = target 7bit slave address\n//      length = number of bytes requested\n//      i2c_stop = I2C_NOSTOP, I2C_STOP\n//      timeout = timeout in microseconds\n//\nsize_t i2c_t3::requestFrom_(struct i2cStruct* i2c, uint8_t bus, uint8_t addr, size_t len, i2c_stop sendStop, uint32_t timeout)\n{\n    // exit immediately if request for 0 bytes\n    if(len == 0) return 0;\n\n    sendRequest_(i2c, bus, addr, len, sendStop, timeout);\n\n    // wait for completion or timeout\n    if(finish_(i2c, bus, timeout))\n        return i2c->rxBufferLength;\n    else\n        return 0; // NAK, timeout or bus error\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Start Master Receive - non-blocking routine, starts request for length bytes from slave at address. Receive\n//                        data will be placed in the Rx buffer. i2c_stop parameter can be used to indicate if\n//                        command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use done() or finish()\n//                        to determine completion and status() to determine success/fail.\n// return: none\n// parameters:\n//      address = target 7bit slave address\n//      length = number of bytes requested\n//      i2c_stop = I2C_NOSTOP, I2C_STOP\n//      timeout = timeout in microseconds (only used for Immediate operation)\n//\nvoid i2c_t3::sendRequest_(struct i2cStruct* i2c, uint8_t bus, uint8_t addr, size_t len, i2c_stop sendStop, uint32_t timeout)\n{\n    uint8_t status, data, chkTimeout=0, forceImm=0;\n\n    // exit immediately if request for 0 bytes or request too large\n    if(len == 0) return;\n    if(len > I2C_RX_BUFFER_LENGTH) { i2c->currentStatus=I2C_BUF_OVF; return; }\n\n    i2c->reqCount = len; // store request length\n    i2c->rxBufferIndex = 0; // reset buffer\n    i2c->rxBufferLength = 0;\n    timeout = (timeout == 0) ? i2c->defTimeout : timeout;\n\n    // clear the status flags\n    #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n        *(i2c->FLT) |= I2C_FLT_STOPF | I2C_FLT_STARTF;  // clear STOP/START intr\n        *(i2c->FLT) &= ~I2C_FLT_SSIE;                   // disable STOP/START intr (not used in Master mode)\n    #endif\n    *(i2c->S) = I2C_S_IICIF | I2C_S_ARBL; // clear intr, arbl\n\n    // try to take control of the bus\n    if(!acquireBus_(i2c, bus, timeout, forceImm)) return;\n\n    //\n    // Immediate mode - blocking\n    //\n    if(i2c->opMode == I2C_OP_MODE_IMM || forceImm)\n    {\n        elapsedMicros deltaT;\n        i2c->currentStatus = I2C_SEND_ADDR;\n        i2c->currentStop = sendStop;\n\n        // Send target address\n        *(i2c->D) = (addr << 1) | 1; // address + READ\n\n        // wait for byte\n        while(!(*(i2c->S) & I2C_S_IICIF) && (timeout == 0 || deltaT < timeout));\n        *(i2c->S) = I2C_S_IICIF;\n        if(timeout && deltaT >= timeout)\n        {\n            *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n            i2c->currentStatus = I2C_TIMEOUT; // Rx incomplete, mark as timeout\n            I2C_ERR_INC(I2C_ERRCNT_TIMEOUT);\n            if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if timeout\n            return;\n        }\n\n        status = *(i2c->S);\n\n        // check arbitration\n        if(status & I2C_S_ARBL)\n        {\n            i2c->currentStatus = I2C_ARB_LOST;\n            *(i2c->S) = I2C_S_ARBL; // clear arbl flag\n            // TODO: this is clearly not right, after ARBL it should drop into IMM slave mode if IAAS=1\n            //       Right now Rx message would be ignored regardless of IAAS\n            *(i2c->C1) = I2C_C1_IICEN; // change to Rx mode, intr disabled (does this send STOP if ARBL flagged?)\n            I2C_ERR_INC(I2C_ERRCNT_ARBL);\n            if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if ARBL\n            return;\n        }\n        // check if slave ACK'd\n        else if(status & I2C_S_RXAK)\n        {\n            i2c->currentStatus = I2C_ADDR_NAK; // NAK on Addr\n            *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n            I2C_ERR_INC(I2C_ERRCNT_ADDR_NAK);\n            if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if NAK\n            return;\n        }\n        else\n        {\n            // Slave addr ACK, change to Rx mode\n            i2c->currentStatus = I2C_RECEIVING;\n            if(i2c->reqCount == 1)\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK; // no STOP, Rx, NAK on recv\n            else\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST; // no STOP, change to Rx\n            data = *(i2c->D); // dummy read\n\n            // Master receive loop\n            while(i2c->rxBufferLength < i2c->reqCount && i2c->currentStatus == I2C_RECEIVING)\n            {\n                while(!(*(i2c->S) & I2C_S_IICIF) && (timeout == 0 || deltaT < timeout));\n                *(i2c->S) = I2C_S_IICIF;\n                chkTimeout = (timeout != 0 && deltaT >= timeout);\n                // check if 2nd to last byte or timeout\n                if((i2c->rxBufferLength+2) == i2c->reqCount || (chkTimeout && !i2c->timeoutRxNAK))\n                {\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK; // no STOP, Rx, NAK on recv\n                }\n                // if last byte or timeout send STOP\n                if((i2c->rxBufferLength+1) >= i2c->reqCount || (chkTimeout && i2c->timeoutRxNAK))\n                {\n                    i2c->timeoutRxNAK = 0; // clear flag\n                    // change to Tx mode\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;\n                    // grab last data\n                    data = *(i2c->D);\n                    i2c->rxBuffer[i2c->rxBufferLength++] = data;\n                    if(i2c->currentStop == I2C_STOP) // NAK then STOP\n                    {\n                        delayMicroseconds(1); // empirical patch, lets things settle before issuing STOP\n                        *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n                    }\n                    // else NAK no STOP\n\n                    // Set final status\n                    if(chkTimeout)\n                    {\n                        i2c->currentStatus = I2C_TIMEOUT; // Rx incomplete, mark as timeout\n                        I2C_ERR_INC(I2C_ERRCNT_TIMEOUT);\n                        if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if timeout\n                    }\n                    else\n                    {\n                        i2c->currentStatus = I2C_WAITING; // Rx complete, change to waiting state\n                        if(i2c->user_onReqFromDone != nullptr) i2c->user_onReqFromDone(); // Call Master Rx complete callback\n                    }\n                }\n                else\n                {\n                    // grab next data, not last byte, will ACK\n                    i2c->rxBuffer[i2c->rxBufferLength++] = *(i2c->D);\n                }\n                if(chkTimeout) i2c->timeoutRxNAK = 1; // set flag to indicate NAK sent\n            }\n        }\n    }\n    //\n    // ISR/DMA mode - non-blocking\n    //\n    else if(i2c->opMode == I2C_OP_MODE_ISR || i2c->opMode == I2C_OP_MODE_DMA)\n    {\n        // send 1st data and enable interrupts\n        i2c->currentStatus = I2C_SEND_ADDR;\n        i2c->currentStop = sendStop;\n        if(i2c->opMode == I2C_OP_MODE_DMA && i2c->reqCount >= 5) // limit transfers less than 5 bytes to ISR method\n        {\n            // init DMA, let the hack begin\n            i2c->activeDMA = I2C_DMA_ADDR;\n            i2c->DMA->source(*(i2c->D));\n            i2c->DMA->destinationBuffer(&i2c->rxBuffer[0],i2c->reqCount-1); // DMA gets all except last byte\n        }\n        // start ISR\n        *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX; // enable intr\n        *(i2c->D) = (addr << 1) | 1; // address + READ\n    }\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Get Wire Error - returns \"Wire\" error code from a failed Tx/Rx command\n// return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error (timeout, arb lost)\n//\nuint8_t i2c_t3::getError(void)\n{\n    // convert status to Arduino return values (give these a higher priority than buf overflow error)\n    switch(i2c->currentStatus)\n    {\n    case I2C_BUF_OVF:  return 1;\n    case I2C_ADDR_NAK: return 2;\n    case I2C_DATA_NAK: return 3;\n    case I2C_ARB_LOST: return 4;\n    case I2C_TIMEOUT:  return 4;\n    case I2C_NOT_ACQ:  return 4;\n    default: break;\n    }\n    if(getWriteError()) return 1; // if write_error was set then flag as buffer overflow\n    return 0; // no errors\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Done Check - returns simple complete/not-complete value to indicate I2C status\n// return: 1=Tx/Rx complete (with or without errors), 0=still running\n//\nuint8_t i2c_t3::done_(struct i2cStruct* i2c)\n{\n    return (i2c->currentStatus < I2C_SENDING);\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Finish - blocking routine with timeout, loops until Tx/Rx is complete or timeout occurs\n// return: 1=success (Tx or Rx completed, no error), 0=fail (NAK, timeout or Arb Lost)\n// parameters:\n//      timeout = timeout in microseconds\n//\nuint8_t i2c_t3::finish_(struct i2cStruct* i2c, uint8_t bus, uint32_t timeout)\n{\n    elapsedMicros deltaT;\n\n    // update timeout\n    timeout = (timeout == 0) ? i2c->defTimeout : timeout;\n\n    // wait for completion or timeout\n    deltaT = 0;\n    while(!done_(i2c) && (timeout == 0 || deltaT < timeout));\n\n    // DMA mode and timeout\n    if(timeout != 0 && deltaT >= timeout && i2c->opMode == I2C_OP_MODE_DMA && i2c->activeDMA != I2C_DMA_OFF)\n    {\n        // If DMA mode times out, then wait for transfer to end then mark it as timeout.\n        // This is done this way because abruptly ending the DMA seems to cause\n        // the I2C_S_BUSY flag to get stuck, and I cannot find a reliable way to clear it.\n        while(!done_(i2c));\n        i2c->currentStatus = I2C_TIMEOUT;\n    }\n\n    // check exit status, if not done then timeout occurred\n    if(!done_(i2c)) i2c->currentStatus = I2C_TIMEOUT; // set to timeout state\n\n    // delay to allow bus to settle - allow Timeout or STOP to complete and be recognized.  Timeouts must\n    //                                propagate through ISR, and STOP must be recognized on both\n    //                                Master and Slave sides\n    delayMicroseconds(4);\n\n    // note that onTransmitDone, onReqFromDone, onError callbacks are handled in ISR, this is done\n    // because use of this function is optional on background transfers\n    if(i2c->currentStatus == I2C_WAITING) return 1;\n    return 0;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Write - write data to Tx buffer\n// return: #bytes written = success, 0=fail\n// parameters:\n//      data = data byte\n//\nsize_t i2c_t3::write(uint8_t data)\n{\n    if(i2c->txBufferLength < I2C_TX_BUFFER_LENGTH)\n    {\n        i2c->txBuffer[i2c->txBufferLength++] = data;\n        return 1;\n    }\n    setWriteError();\n    return 0;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Write Array - write count number of bytes from data array to Tx buffer\n// return: #bytes written = success, 0=fail\n// parameters:\n//      data = pointer to uint8_t array of data\n//      count = number of bytes to write\n//\nsize_t i2c_t3::write(const uint8_t* data, size_t count)\n{\n    if(i2c->txBufferLength < I2C_TX_BUFFER_LENGTH)\n    {\n        size_t avail = I2C_TX_BUFFER_LENGTH - i2c->txBufferLength;\n        uint8_t* dest = i2c->txBuffer + i2c->txBufferLength;\n\n        if(count > avail)\n        {\n            count = avail; // truncate to space avail if needed\n            setWriteError();\n        }\n        memcpy(dest, data, count);\n        i2c->txBufferLength += count;\n        return count;\n    }\n    setWriteError();\n    return 0;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Read - returns next data byte (signed int) from Rx buffer\n// return: data, -1 if buffer empty\n//\nint i2c_t3::read_(struct i2cStruct* i2c)\n{\n    if(i2c->rxBufferIndex >= i2c->rxBufferLength) return -1;\n    return i2c->rxBuffer[i2c->rxBufferIndex++];\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Read Array - read count number of bytes from Rx buffer to data array\n// return: #bytes read\n// parameters:\n//      data = pointer to uint8_t array of data\n//      count = number of bytes to write\n//\nsize_t i2c_t3::read_(struct i2cStruct* i2c, uint8_t* data, size_t count)\n{\n    if(i2c->rxBufferLength > i2c->rxBufferIndex)\n    {\n        size_t avail = i2c->rxBufferLength - i2c->rxBufferIndex;\n        uint8_t* src = i2c->rxBuffer + i2c->rxBufferIndex;\n\n        if(count > avail) count = avail; // truncate to data avail if needed\n        memcpy(data, src, count);\n        i2c->rxBufferIndex += count;\n        return count;\n    }\n    return 0;\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Peek - returns next data byte (signed int) from Rx buffer without removing it from Rx buffer\n// return: data, -1 if buffer empty\n//\nint i2c_t3::peek_(struct i2cStruct* i2c)\n{\n    if(i2c->rxBufferIndex >= i2c->rxBufferLength) return -1;\n    return i2c->rxBuffer[i2c->rxBufferIndex];\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Read Byte - returns next data byte (uint8_t) from Rx buffer\n// return: data, 0 if buffer empty\n//\nuint8_t i2c_t3::readByte_(struct i2cStruct* i2c)\n{\n    if(i2c->rxBufferIndex >= i2c->rxBufferLength) return 0;\n    return i2c->rxBuffer[i2c->rxBufferIndex++];\n}\n\n\n// ------------------------------------------------------------------------------------------------------\n// Peek Byte - returns next data byte (uint8_t) from Rx buffer without removing it from Rx buffer\n// return: data, 0 if buffer empty\n//\nuint8_t i2c_t3::peekByte_(struct i2cStruct* i2c)\n{\n    if(i2c->rxBufferIndex >= i2c->rxBufferLength) return 0;\n    return i2c->rxBuffer[i2c->rxBufferIndex];\n}\n\n\n// ======================================================================================================\n// ------------------------------------------------------------------------------------------------------\n// I2C Interrupt Service Routine\n// ------------------------------------------------------------------------------------------------------\n// ======================================================================================================\n\n\nvoid i2c0_isr(void) // I2C0 ISR\n{\n    I2C0_INTR_FLAG_ON;\n    i2c_isr_handler(&(i2c_t3::i2cData[0]),0);\n    I2C0_INTR_FLAG_OFF;\n}\n#if I2C_BUS_NUM >= 2\n    void i2c1_isr(void) // I2C1 ISR\n    {\n        I2C1_INTR_FLAG_ON;\n        i2c_isr_handler(&(i2c_t3::i2cData[1]),1);\n        I2C1_INTR_FLAG_OFF;\n    }\n#endif\n#if I2C_BUS_NUM >= 3\n    void i2c2_isr(void) // I2C2 ISR\n    {\n        I2C2_INTR_FLAG_ON;\n        i2c_isr_handler(&(i2c_t3::i2cData[2]),2);\n        I2C2_INTR_FLAG_OFF;\n    }\n#endif\n#if I2C_BUS_NUM >= 4\n    void i2c3_isr(void) // I2C3 ISR\n    {\n        I2C3_INTR_FLAG_ON;\n        i2c_isr_handler(&(i2c_t3::i2cData[3]),3);\n        I2C3_INTR_FLAG_OFF;\n    }\n#endif\n\n//\n// I2C ISR base handler\n//\nvoid i2c_isr_handler(struct i2cStruct* i2c, uint8_t bus)\n{\n    uint8_t status, c1, data;\n    i2c_t3::isrActive++;\n\n    status = *(i2c->S);\n    c1 = *(i2c->C1);\n    #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n        uint8_t flt = *(i2c->FLT);  // store flags\n    #endif\n\n    if(c1 & I2C_C1_MST)\n    {\n        //\n        // Master Mode\n        //\n        if(c1 & I2C_C1_TX)\n        {\n            if(i2c->activeDMA == I2C_DMA_BULK || i2c->activeDMA == I2C_DMA_LAST)\n            {\n                if(i2c->DMA->complete() && i2c->activeDMA == I2C_DMA_BULK)\n                {\n                    // clear DMA interrupt, final byte should trigger another ISR\n                    i2c->DMA->clearInterrupt();\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX; // intr en, Tx mode, DMA disabled\n                    // DMA says complete at the beginning of its last byte, need to\n                    // wait until end of its last byte to re-engage ISR\n                    i2c->activeDMA = I2C_DMA_LAST;\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                }\n                else if(i2c->activeDMA == I2C_DMA_LAST)\n                {\n                    // wait for TCF\n                    while(!(*(i2c->S) & I2C_S_TCF));\n                    // clear DMA, only do this after TCF\n                    i2c->DMA->clearComplete();\n                    // re-engage ISR for last byte\n                    i2c->activeDMA = I2C_DMA_OFF;\n                    i2c->txBufferIndex = i2c->txBufferLength-1;\n                    *(i2c->D) = i2c->txBuffer[i2c->txBufferIndex];\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                }\n                else if(i2c->DMA->error())\n                {\n                    i2c->DMA->clearError();\n                    i2c->DMA->clearInterrupt();\n                    i2c->activeDMA = I2C_DMA_OFF;\n                    i2c->currentStatus = I2C_DMA_ERR;\n                    I2C_ERR_INC(I2C_ERRCNT_DMA_ERR);\n                    // check arbitration\n                    if(status & I2C_S_ARBL)\n                    {\n                        // Arbitration Lost\n                        i2c->currentStatus = I2C_ARB_LOST;\n                        I2C_ERR_INC(I2C_ERRCNT_ARBL);\n                        *(i2c->S) = I2C_S_ARBL; // clear arbl flag\n                        i2c->txBufferIndex = 0; // reset Tx buffer index to prepare for resend\n                        // TODO does this need to check IAAS and drop to Slave Rx? if so set Rx + dummy read. not sure if this would work for DMA\n                    }\n                    *(i2c->C1) = I2C_C1_IICEN; // change to Rx mode, intr disabled, DMA disabled\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if DMA error or ARBL\n                }\n                i2c_t3::isrActive--;\n                return;\n            } // end DMA Tx\n            else\n            {\n                // Continue Master Transmit\n                // check if Master Tx or Rx\n                if(i2c->currentStatus == I2C_SENDING)\n                {\n                    // check arbitration\n                    if(status & I2C_S_ARBL)\n                    {\n                        // Arbitration Lost\n                        i2c->activeDMA = I2C_DMA_OFF; // clear pending DMA (if happens on address byte)\n                        i2c->currentStatus = I2C_ARB_LOST;\n                        *(i2c->S) = I2C_S_ARBL; // clear arbl flag\n                        *(i2c->C1) = I2C_C1_IICEN; // change to Rx mode, intr disabled (does this send STOP if ARBL flagged?)\n                        i2c->txBufferIndex = 0; // reset Tx buffer index to prepare for resend\n                        // TODO does this need to check IAAS and drop to Slave Rx? if so set Rx + dummy read.\n                        *(i2c->S) = I2C_S_IICIF; // clear intr\n                        I2C_ERR_INC(I2C_ERRCNT_ARBL);\n                        if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if ARBL\n                    }\n                    // check if slave ACK'd\n                    else if(status & I2C_S_RXAK)\n                    {\n                        i2c->activeDMA = I2C_DMA_OFF; // clear pending DMA (if happens on address byte)\n                        if(i2c->txBufferIndex == 0)\n                        {\n                            i2c->currentStatus = I2C_ADDR_NAK; // NAK on Addr\n                            I2C_ERR_INC(I2C_ERRCNT_ADDR_NAK);\n                        }\n                        else\n                        {\n                            i2c->currentStatus = I2C_DATA_NAK; // NAK on Data\n                            I2C_ERR_INC(I2C_ERRCNT_DATA_NAK);\n                        }\n                        // send STOP, change to Rx mode, intr disabled\n                        // note: Slave NAK is an error, so send STOP regardless of setting\n                        *(i2c->C1) = I2C_C1_IICEN;\n                        *(i2c->S) = I2C_S_IICIF; // clear intr\n                        if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if NAK\n                    }\n                    else\n                    {\n                        // check if last byte transmitted\n                        if(++i2c->txBufferIndex >= i2c->txBufferLength)\n                        {\n                            // Tx complete, change to waiting state\n                            i2c->currentStatus = I2C_WAITING;\n                            // send STOP if configured\n                            if(i2c->currentStop == I2C_STOP)\n                                *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n                            else\n                                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; // no STOP, stay in Tx mode, intr disabled\n                            // run TransmitDone callback when done\n                            *(i2c->S) = I2C_S_IICIF; // clear intr\n                            if(i2c->user_onTransmitDone != nullptr) i2c->user_onTransmitDone();\n                        }\n                        else if(i2c->activeDMA == I2C_DMA_ADDR)\n                        {\n                            // Start DMA\n                            i2c->activeDMA = I2C_DMA_BULK;\n                            *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX | I2C_C1_DMAEN; // intr en, Tx mode, DMA en\n                            i2c->DMA->enable();\n                            *(i2c->D) = i2c->txBuffer[1]; // DMA will start on next request\n                            *(i2c->S) = I2C_S_IICIF; // clear intr\n                        }\n                        else\n                        {\n                            // ISR transmit next byte\n                            *(i2c->D) = i2c->txBuffer[i2c->txBufferIndex];\n                            *(i2c->S) = I2C_S_IICIF; // clear intr\n                        }\n                    }\n                    i2c_t3::isrActive--;\n                    return;\n                }\n                else if(i2c->currentStatus == I2C_SEND_ADDR)\n                {\n                    // Master Receive, addr sent\n                    if(status & I2C_S_ARBL)\n                    {\n                        // Arbitration Lost\n                        i2c->currentStatus = I2C_ARB_LOST;\n                        *(i2c->S) = I2C_S_ARBL; // clear arbl flag\n                        *(i2c->C1) = I2C_C1_IICEN; // change to Rx mode, intr disabled (does this send STOP if ARBL flagged?)\n                        // TODO does this need to check IAAS and drop to Slave Rx? if so set Rx + dummy read. not sure if this would work for DMA\n                        *(i2c->S) = I2C_S_IICIF; // clear intr\n                        I2C_ERR_INC(I2C_ERRCNT_ARBL);\n                        if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if ARBL\n                    }\n                    else if(status & I2C_S_RXAK)\n                    {\n                        // Slave addr NAK\n                        i2c->currentStatus = I2C_ADDR_NAK; // NAK on Addr\n                        // send STOP, change to Rx mode, intr disabled\n                        // note: Slave NAK is an error, so send STOP regardless of setting\n                        *(i2c->C1) = I2C_C1_IICEN;\n                        *(i2c->S) = I2C_S_IICIF; // clear intr\n                        I2C_ERR_INC(I2C_ERRCNT_ADDR_NAK);\n                        if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if NAK\n                    }\n                    else if(i2c->activeDMA == I2C_DMA_ADDR)\n                    {\n                        // Start DMA\n                        i2c->activeDMA = I2C_DMA_BULK;\n                        *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_DMAEN; // intr en, no STOP, change to Rx, DMA en\n                        i2c->DMA->enable();\n                        data = *(i2c->D); // dummy read\n                        *(i2c->S) = I2C_S_IICIF; // clear intr\n                    }\n                    else\n                    {\n                        // Slave addr ACK, change to Rx mode\n                        i2c->currentStatus = I2C_RECEIVING;\n                        if(i2c->reqCount == 1)\n                            *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // no STOP, Rx, NAK on recv\n                        else\n                            *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // no STOP, change to Rx\n                        data = *(i2c->D); // dummy read\n                        *(i2c->S) = I2C_S_IICIF; // clear intr\n                    }\n                    i2c_t3::isrActive--;\n                    return;\n                }\n                else if(i2c->currentStatus == I2C_TIMEOUT)\n                {\n                    // send STOP if configured\n                    if(i2c->currentStop == I2C_STOP)\n                        *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n                    else\n                        *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; // no STOP, stay in Tx mode, intr disabled\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    I2C_ERR_INC(I2C_ERRCNT_TIMEOUT);\n                    if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if timeout\n                    i2c_t3::isrActive--;\n                    return;\n                }\n                else\n                {\n                    // Should not be in Tx mode if not sending\n                    // send STOP, change to Rx mode, intr disabled\n                    *(i2c->C1) = I2C_C1_IICEN;\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    i2c_t3::isrActive--;\n                    return;\n                }\n            } // end ISR Tx\n        }\n        else\n        {\n            // Continue Master Receive\n            //\n            if(i2c->activeDMA == I2C_DMA_BULK || i2c->activeDMA == I2C_DMA_LAST)\n            {\n                if(i2c->DMA->complete() && i2c->activeDMA == I2C_DMA_BULK) // 2nd to last byte\n                {\n                    // clear DMA interrupt, final byte should trigger another ISR\n                    i2c->DMA->clearInterrupt();\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // intr en, Rx mode, DMA disabled, NAK on recv\n                    i2c->activeDMA = I2C_DMA_LAST;\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                }\n                else if(i2c->activeDMA == I2C_DMA_LAST) // last byte\n                {\n                    // clear DMA\n                    i2c->DMA->clearComplete();\n                    i2c->activeDMA = I2C_DMA_OFF;\n                    // change to Tx mode\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;\n                    // grab last data\n                    i2c->rxBufferLength = i2c->reqCount-1;\n                    i2c->rxBuffer[i2c->rxBufferLength++] = *(i2c->D);\n                    if(i2c->currentStop == I2C_STOP) // NAK then STOP\n                    {\n                        delayMicroseconds(1); // empirical patch, lets things settle before issuing STOP\n                        *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n                    }\n                    // else NAK no STOP\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    i2c->currentStatus = I2C_WAITING; // Rx complete, change to waiting state\n                    if(i2c->user_onReqFromDone != nullptr) i2c->user_onReqFromDone(); // Call Master Rx complete callback\n                }\n                else if(i2c->DMA->error()) // not sure what would cause this...\n                {\n                    i2c->DMA->clearError();\n                    i2c->DMA->clearInterrupt();\n                    i2c->activeDMA = I2C_DMA_OFF;\n                    i2c->currentStatus = I2C_DMA_ERR;\n                    *(i2c->C1) = I2C_C1_IICEN; // change to Rx mode, intr disabled, DMA disabled\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    I2C_ERR_INC(I2C_ERRCNT_DMA_ERR);\n                    if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if DMA error\n                }\n                i2c_t3::isrActive--;\n                return;\n            }\n            else\n            {\n                // check if 2nd to last byte or timeout\n                if((i2c->rxBufferLength+2) == i2c->reqCount || (i2c->currentStatus == I2C_TIMEOUT && !i2c->timeoutRxNAK))\n                {\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // no STOP, Rx, NAK on recv\n                }\n                // if last byte or timeout send STOP\n                if((i2c->rxBufferLength+1) >= i2c->reqCount || (i2c->currentStatus == I2C_TIMEOUT && i2c->timeoutRxNAK))\n                {\n                    i2c->timeoutRxNAK = 0; // clear flag\n                    // change to Tx mode\n                    *(i2c->C1) = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;\n                    // grab last data\n                    i2c->rxBuffer[i2c->rxBufferLength++] = *(i2c->D);\n                    if(i2c->currentStop == I2C_STOP) // NAK then STOP\n                    {\n                        delayMicroseconds(1); // empirical patch, lets things settle before issuing STOP\n                        *(i2c->C1) = I2C_C1_IICEN; // send STOP, change to Rx mode, intr disabled\n                    }\n                    // else NAK no STOP\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    // Rx complete\n                    if(i2c->currentStatus == I2C_TIMEOUT)\n                    {\n                        I2C_ERR_INC(I2C_ERRCNT_TIMEOUT);\n                        if(i2c->user_onError != nullptr) i2c->user_onError(); // run Error callback if timeout\n                    }\n                    else\n                    {\n                        i2c->currentStatus = I2C_WAITING;\n                        if(i2c->user_onReqFromDone != nullptr) i2c->user_onReqFromDone(); // Call Master Rx complete callback\n                    }\n                }\n                else\n                {\n                    // grab next data, not last byte, will ACK\n                    i2c->rxBuffer[i2c->rxBufferLength++] = *(i2c->D);\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                }\n                if(i2c->currentStatus == I2C_TIMEOUT && !i2c->timeoutRxNAK)\n                    i2c->timeoutRxNAK = 1; // set flag to indicate NAK sent\n\n                i2c_t3::isrActive--;\n                return;\n            }\n        }\n    }\n    else\n    {\n        //\n        // Slave Mode\n        //\n\n        // ARBL makes no sense on Slave, but this might get set if there is a pullup problem and\n        // SCL/SDA get stuck.  This is primarily to guard against ARBL flag getting stuck.\n        if(status & I2C_S_ARBL)\n        {\n            // Arbitration Lost\n            *(i2c->S) = I2C_S_ARBL; // clear arbl flag\n            if(!(status & I2C_S_IAAS))\n            {\n                #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n                    *(i2c->FLT) |= I2C_FLT_STOPF | I2C_FLT_STARTF;  // clear STOP/START intr\n                #endif\n                *(i2c->S) = I2C_S_IICIF; // clear intr\n                i2c_t3::isrActive--;\n                return;\n            }\n        }\n        if(status & I2C_S_IAAS)\n        {\n            // If in Slave Rx already, then RepSTART occured, run callback\n            if(i2c->currentStatus == I2C_SLAVE_RX && i2c->user_onReceive != nullptr)\n            {\n                i2c->rxBufferIndex = 0;\n                i2c->user_onReceive(i2c->rxBufferLength);\n            }\n\n            // Is Addressed As Slave\n            if(status & I2C_S_SRW)\n            {\n                // Addressed Slave Transmit\n                //\n                i2c->currentStatus = I2C_SLAVE_TX;\n                i2c->txBufferLength = 0;\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;\n                i2c->rxAddr = (*(i2c->D) >> 1); // read to get target addr\n                if(i2c->user_onRequest != nullptr) i2c->user_onRequest(); // load Slave Tx buffer with data\n                if(i2c->txBufferLength == 0) i2c->txBuffer[0] = 0; // send 0's if buffer empty\n                *(i2c->D) = i2c->txBuffer[0]; // send first data\n                i2c->txBufferIndex = 1;\n            }\n            else\n            {\n                // Addressed Slave Receive\n                //\n                // setup SDA-rising ISR - required for STOP detection in Slave Rx mode for 3.0/3.1/3.2\n                #if defined(__MK20DX256__) && I2C_BUS_NUM == 2 // 3.1/3.2 (dual-bus)\n                    i2c->irqCount = 0;\n                    attachInterrupt(i2c->currentSDA, (bus == 0) ? i2c_t3::sda0_rising_isr : i2c_t3::sda1_rising_isr, RISING);\n                #elif defined(__MK20DX128__) || defined(__MK20DX256__) // 3.0/3.1/3.2 (single-bus)\n                    i2c->irqCount = 0;\n                    attachInterrupt(i2c->currentSDA, i2c_t3::sda0_rising_isr, RISING);\n                #elif defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)\n                    *(i2c->FLT) |= I2C_FLT_SSIE; // enable START/STOP intr for LC/3.5/3.6\n                #endif\n                i2c->currentStatus = I2C_SLAVE_RX;\n                i2c->rxBufferLength = 0;\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE;\n                i2c->rxAddr = (*(i2c->D) >> 1); // read to get target addr\n            }\n            #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n                *(i2c->FLT) |= I2C_FLT_STOPF | I2C_FLT_STARTF;  // clear STOP/START intr\n            #endif\n            *(i2c->S) = I2C_S_IICIF; // clear intr\n            i2c_t3::isrActive--;\n            return;\n        }\n        if(c1 & I2C_C1_TX)\n        {\n            // Continue Slave Transmit\n            if((status & I2C_S_RXAK) == 0)\n            {\n                // Master ACK'd previous byte\n                if(i2c->txBufferIndex < i2c->txBufferLength)\n                    data = i2c->txBuffer[i2c->txBufferIndex++];\n                else\n                    data = 0; // send 0's if buffer empty\n                *(i2c->D) = data;\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;\n            }\n            else\n            {\n                // Master did not ACK previous byte\n                *(i2c->C1) = I2C_C1_IICEN | I2C_C1_IICIE; // switch to Rx mode\n                data = *(i2c->D); // dummy read\n                i2c->currentStatus = I2C_WAITING;\n            }\n        }\n        else if(i2c->currentStatus == I2C_SLAVE_RX)\n        {\n            #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n                if(flt & (I2C_FLT_STOPF|I2C_FLT_STARTF)) // STOP/START detected, run callback\n                {\n                    // LC (MKL26) appears to have the same I2C_FLT reg definition as 3.6 (K66)\n                    // There is both STOPF and STARTF and they are both enabled via SSIE, and they must both\n                    // be cleared in order to work\n                    *(i2c->FLT) |= I2C_FLT_STOPF | I2C_FLT_STARTF;  // clear STOP/START intr\n                    *(i2c->FLT) &= ~I2C_FLT_SSIE;                   // disable STOP/START intr (will re-enable on next IAAS)\n                    *(i2c->S) = I2C_S_IICIF; // clear intr\n                    i2c->currentStatus = I2C_WAITING;\n                    // Slave Rx complete, run callback\n                    if(i2c->user_onReceive != nullptr)\n                    {\n                        i2c->rxBufferIndex = 0;\n                        i2c->user_onReceive(i2c->rxBufferLength);\n                    }\n                    i2c_t3::isrActive--;\n                    return;\n                }\n            #endif\n            // Continue Slave Receive\n            //\n            // setup SDA-rising ISR - required for STOP detection in Slave Rx mode for 3.0/3.1/3.2\n            #if defined(__MK20DX256__) && I2C_BUS_NUM == 2 // 3.1/3.2 (dual-bus)\n                i2c->irqCount = 0;\n                attachInterrupt(i2c->currentSDA, (bus == 0) ? i2c_t3::sda0_rising_isr : i2c_t3::sda1_rising_isr, RISING);\n            #elif defined(__MK20DX128__) || defined(__MK20DX256__) // 3.0/3.1/3.2 (single-bus)\n                i2c->irqCount = 0;\n                attachInterrupt(i2c->currentSDA, i2c_t3::sda0_rising_isr, RISING);\n            #endif\n            data = *(i2c->D);\n            if(i2c->rxBufferLength < I2C_RX_BUFFER_LENGTH)\n                i2c->rxBuffer[i2c->rxBufferLength++] = data;\n        }\n        #if defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // LC/3.5/3.6\n            *(i2c->FLT) |= I2C_FLT_STOPF | I2C_FLT_STARTF;  // clear STOP/START intr\n        #endif\n        *(i2c->S) = I2C_S_IICIF; // clear intr\n    }\n}\n\n#if defined(__MK20DX128__) || defined(__MK20DX256__) // 3.0/3.1/3.2\n// ------------------------------------------------------------------------------------------------------\n// SDA-Rising Interrupt Service Routine - 3.0/3.1/3.2 only\n//\n// Detects the stop condition that terminates a slave receive transfer.\n//\n\n// I2C0 SDA ISR\nvoid i2c_t3::sda0_rising_isr(void)\n{\n    i2c_t3::sda_rising_isr_handler(&(i2c_t3::i2cData[0]),0);\n}\n\n#if I2C_BUS_NUM >= 2\n    // I2C1 SDA ISR\n    void i2c_t3::sda1_rising_isr(void)\n    {\n        i2c_t3::sda_rising_isr_handler(&(i2c_t3::i2cData[1]),1);\n    }\n#endif\n\n//\n// SDA ISR base handler\n//\nvoid i2c_t3::sda_rising_isr_handler(struct i2cStruct* i2c, uint8_t bus)\n{\n    uint8_t status = *(i2c->S); // capture status first, can change if ISR is too slow\n    if(!(status & I2C_S_BUSY))\n    {\n        i2c->currentStatus = I2C_WAITING;\n        detachInterrupt(i2c->currentSDA);\n        if(i2c->user_onReceive != nullptr)\n        {\n            i2c->rxBufferIndex = 0;\n            i2c->user_onReceive(i2c->rxBufferLength);\n        }\n    }\n    else\n    {\n        if(++(i2c->irqCount) >= 2 || !(i2c->currentMode == I2C_SLAVE))\n            detachInterrupt(i2c->currentSDA);\n    }\n}\n#endif // sda_rising_isr\n\n// ------------------------------------------------------------------------------------------------------\n// Instantiate\n//\ni2c_t3 Wire  = i2c_t3(0);       // I2C0\n#if I2C_BUS_NUM >= 2\n    i2c_t3 Wire1 = i2c_t3(1);   // I2C1\n#endif\n#if I2C_BUS_NUM >= 3\n    i2c_t3 Wire2 = i2c_t3(2);   // I2C2\n#endif\n#if I2C_BUS_NUM >= 4\n    i2c_t3 Wire3 = i2c_t3(3);   // I2C3\n#endif\n\n#endif // i2c_t3\n\n/*\n   ------------------------------------------------------------------------------------------------------\n   Changelog\n   ------------------------------------------------------------------------------------------------------\n\n    - (v11.0) Modified 01Dec18 by Brian (nox771 at gmail.com)\n        - Added state variables and modified pinConfigure_() to recognize unconfigured SCL/SDA pins, \n          allowing for setSCL()/setSDA() prior to begin(), which was previously blocked by bus busy \n          check on unconfigured pins.\n        - Header change to MIT permissive license\n\n    - (v10.1) Modified 02Jan18 by Brian (nox771 at gmail.com)\n        - Added User #define to disable priority checks entirely\n        - Added i2c_t3::isrActive flag to dynamically disable priority checks during ISR & callbacks.\n          This is to prevent runaway priority escalation in cases of callbacks with nested Wire calls.\n\n    - (v10.0) Modified 21Oct17 by Brian (nox771 at gmail.com)\n        - Default assignments have been added to many functions for pins/pullup/rate/op_mode, so\n          all those parameters are now optional in many function calls (marked ^ below)\n        - Unbound SCL/SDA pin assignment.  Pins can be specified with either i2c_pins enum or by direct\n          SCL,SDA pin definition (using any valid SCL and SDA pin).  New function summary is:\n            - begin(mode, address1, ^i2c_pins, ^i2c_pullup, ^rate, ^i2c_op_mode)\n            - begin(mode, address1, ^pinSCL, ^pinSDA, ^i2c_pullup, ^rate, ^i2c_op_mode)\n            - pinConfigure(i2c_pins, ^pullup)\n            - pinConfigure(pinSCL, pinSDA, ^pullup)\n            - setSCL(pin)\n            - setSDA(pin)\n            - getSCL()\n            - getSDA()\n          Note: internal to i2c structure, currentPins has been replaced by currentSCL and currentSDA\n        - Added Master callback functions for completion of transfers.  Primarily for\n          sendTransmission/sendRequest, but these will also work on foreground commands\n          endTransmission/requestFrom.  Also added an Error callback for Master bus errors.\n            - onTransmitDone(function) - where function() is called when Master Transmit is complete\n            - onReqFromDone(function) - where function() is called when Master Receive is complete\n            - onError(function) - where function() is called upon any I2C error which terminates the\n                                  Master bus operation (eg. NAK, timeout, acquire fail, etc)\n        - Fixed blocking conditions that could occur in immediate mode\n        - Added error counters which may be optionally enabled via I2C_ERROR_COUNTERS define.  When\n          enabled it will track (Master mode only): Reset Bus (auto-retry only), Timeout, Addr NAK,\n          Data NAK, Arb Lost, Bus Not Acquired, DMA Errors.\n            - i2c_err_count enum, getErrorCount(), and zeroErrorCount() functions added\n\n    - (v9.4) Modified 01Oct17 by Brian (nox771 at gmail.com)\n        - Fixed Slave ISR for LC/3.5/3.6 not properly recognizing RepSTART\n        - Fixed nested Wire calls during Slave ISR receive (calling Wire inside Wire1 Slave ISR)\n        - Added uint8_t and char array read functions - Wire.read(databuf, count);\n\n    - (v9.3) Modified 20Sep17 by Brian (nox771 at gmail.com)\n        - Fixed Slave ISR for LC/3.5/3.6\n\n    - (v9.2) Modified 29Dec16 by Brian (nox771 at gmail.com)\n        - improved resetBus() function to reset C1 state (thanks hw999)\n\n    - (v9.1) Modified 16Oct16 by Brian (nox771 at gmail.com)\n        - applied two fixes due to bug reports:\n            - removed I2C_F_DIV120 setting (120 divide-ratio) for I2C clock\n            - disabled I2C_AUTO_RETRY by default (setting remains but must be manually enabled)\n\n    - (v9) Modified 01Jul16 by Brian (nox771 at gmail.com)\n        - Added support for Teensy 3.5/3.6:\n            - fully supported (Master/Slave modes, IMM/ISR/DMA operation)\n            - supports all available pin/bus options on Wire/Wire1/Wire2/Wire3\n        - Fixed LC slave bug, whereby it was incorrectly detecting STOPs directed to other slaves\n        - I2C rate is now set using a much more flexible method than previously used (this is partially\n          motivated by increasing device count and frequencies).  As a result, the fixed set of rate\n          enums are no longer needed (however they are currently still supported), and desired I2C\n          frequency can be directly specified, eg. for 400kHz, I2C_RATE_400 can be replaced by 400000.\n          Some setRate() functions are deprecated due to these changes.\n\n    - (v8) Modified 02Apr15 by Brian (nox771 at gmail.com)\n        - added support for Teensy LC:\n            - fully supported (Master/Slave modes, IMM/ISR/DMA operation)\n            - Wire: pins 16/17 or 18/19, rate limited to I2C_RATE_1200\n            - Wire1: pins 22/23, rate limited to I2C_RATE_2400\n        - added timeout on acquiring bus (prevents lockup when bus cannot be acquired)\n        - added setDefaultTimeout() function for setting the default timeout to apply to all commands\n        - added resetBus() function for toggling SCL to release stuck Slave devices\n        - added setRate(rate) function, similar to setClock(freq), but using rate specifiers (does not\n                require specifying busFreq)\n        - added I2C_AUTO_RETRY user define\n\n    - (v7) Modified 09Jan15 by Brian (nox771 at gmail.com)\n        - added support for F_BUS frequencies: 60MHz, 56MHz, 48MHz, 36MHz, 24MHz, 16MHz, 8MHz, 4MHz, 2MHz\n        - added new rates: I2C_RATE_1800, I2C_RATE_2800, I2C_RATE_3000\n        - added new priority escalation - in cases where I2C ISR is blocked by having a lower priority than\n                                          calling function, the I2C will either adjust I2C ISR to a higher\n                                          priority, or switch to Immediate mode as needed.\n        - added new operating mode control - I2C can be set to operate in ISR mode, DMA mode (Master only),\n                                             or Immediate Mode (Master only)\n        - added new begin() functions to allow setting the initial operating mode:\n            - begin(i2c_mode mode, uint8_t address, i2c_pins pins, i2c_pullup pullup, i2c_rate rate,\n                    i2c_op_mode opMode)\n            - begin(i2c_mode mode, uint8_t address1, uint8_t address2, i2c_pins pins, i2c_pullup pullup,\n                    i2c_rate rate, i2c_op_mode opMode)\n        - added new functions:\n            - uint8_t setOpMode(i2c_op_mode opMode) - used to change operating mode on the fly\n                                                      (only when bus is idle)\n            - void sendTransmission() - non-blocking Tx with implicit I2C_STOP, added for symmetry\n                                        with endTransmission()\n            - uint8_t setRate(uint32_t busFreq, i2c_rate rate) - used to set I2C clock dividers to get\n                                                                 desired rate, i2c_rate argument\n            - uint8_t setRate(uint32_t busFreq, uint32_t i2cFreq) - used to set I2C clock dividers to get\n                                                                    desired SCL freq, uint32_t argument\n                                                                    (quantized to nearest i2c_rate)\n        - added new Wire compatibility functions:\n            - void setClock(uint32_t i2cFreq) - (note: degenerate form of setRate() with busFreq == F_BUS)\n            - uint8_t endTransmission(uint8_t sendStop)\n            - uint8_t requestFrom(uint8_t addr, uint8_t len)\n            - uint8_t requestFrom(uint8_t addr, uint8_t len, uint8_t sendStop)\n        - fixed bug in Slave Range code whereby onRequest() callback occurred prior to updating rxAddr\n          instead of after\n        - fixed bug in arbitration, was missing from Master Tx mode\n        - removed I2C1 defines (now included in kinetis.h)\n        - removed all debug code (eliminates rbuf dependency)\n\n    - (v6) Modified 16Jan14 by Brian (nox771 at gmail.com)\n        - all new structure using dereferenced pointers instead of hardcoding. This allows functions\n          (including ISRs) to be reused across multiple I2C buses.  Most functions moved to static,\n          which in turn are called by inline user functions.  Added new struct (i2cData) for holding all\n          bus information.\n        - added support for Teensy 3.1 and I2C1 interface on pins 29/30 and 26/31.\n        - added header define (I2C_BUS_ENABLE n) to control number of enabled buses (eg. both I2C0 & I2C1\n          or just I2C0).  When using only I2C0 the code and ram usage will be lower.\n        - added interrupt flag (toggles pin high during ISR) with independent defines for I2C0 and\n          I2C1 (refer to header file), useful for logic analyzer trigger\n\n    - (v5) Modified 09Jun13 by Brian (nox771 at gmail.com)\n        - fixed bug in ISR timeout code in which timeout condition could fail to reset in certain cases\n        - fixed bug in Slave mode in sda_rising_isr attach, whereby it was not getting attached on the addr byte\n        - moved debug routines so they are entirely defined internal to the library (no end user code req'd)\n        - debug routines now use IntervalTimer library\n        - added support for range of Slave addresses\n        - added getRxAddr() for Slave using addr range to determine its called address\n        - removed virtual keyword from all functions (is not a base class)\n\n    - (v1-v4) Modified 26Feb13 by Brian (nox771 at gmail.com)\n        - Reworked begin function:\n            - added option for pins to use (SCL:SDA on 19:18 or 16:17 - note pin order difference)\n            - added option for internal pullup - as mentioned in previous code pullup is very strong,\n                                                 approx 190 ohms, but is possibly useful for high speed I2C\n            - added option for rates - 100kHz, 200kHz, 300kHz, 400kHz, 600kHz, 800kHz, 1MHz, 1.2MHz, <-- 24/48MHz bus\n                                       1.5MHz, 2.0MHz, 2.4MHz                                        <-- 48MHz bus only\n        - Removed string.h dependency (memcpy)\n        - Changed Master modes to interrupt driven\n        - Added non-blocking Tx/Rx routines, and status/done/finish routines:\n            - sendTransmission() - non-blocking transmit\n            - sendRequest() - non-blocking receive\n            - status() - reports current status\n            - done() - indicates Tx/Rx complete (for main loop polling if I2C is running in background)\n            - finish() - loops until Tx/Rx complete or bus error\n        - Added readByte()/peekByte() for uint8_t return values (note: returns 0 instead of -1 if buf empty)\n        - Added fixes for Slave Rx mode - in short Slave Rx on this part is fubar\n          (as proof, notice the difference in the I2Cx_FLT register in the KL25 Sub-Family parts)\n            - the SDA-rising ISR hack can work but only detects STOP conditons.\n              A slave Rx followed by RepSTART won't be detected since bus remains busy.\n              To fix this if IAAS occurs while already in Slave Rx mode then it will\n              assume RepSTART occurred and trigger onReceive callback.\n        - Separated Tx/Rx buffer sizes for asymmetric devices (adjustable in i2c_t3.h)\n        - Changed Tx/Rx buffer indicies to size_t to allow for large (>256 byte) buffers\n        - Left debug routines in place (controlled via header defines - default is OFF).  If debug is\n            enabled, note that it can easily overrun the Debug queue on large I2C transfers, yielding\n            garbage output.  Adjust ringbuf size (in rbuf.h) and possibly PIT interrupt rate to adjust\n            data flow to Serial (note also the buffer in Serial can overflow if written too quickly).\n        - Added getError() function to return Wire error code\n        - Added pinConfigure() function for changing pins on the fly (only when bus not busy)\n        - Added timeouts to endTransmission(), requestFrom(), and finish()\n\n    ------------------------------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "i2c_t3.h",
    "content": "/*\n    ------------------------------------------------------------------------------------------------------\n    i2c_t3 - I2C library for Teensy 3.x & LC\n\n    - (v11.0) Modified 01Dec18 by Brian (nox771 at gmail.com)\n\n    Full changelog at end of file\n    ------------------------------------------------------------------------------------------------------\n    Copyright (c) 2013-2018, Brian (nox771 at gmail.com)\n\n    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and \n    associated documentation files (the \"Software\"), to deal in the Software without restriction, \n    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, \n    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, \n    subject to the following conditions:\n\n    The above copyright notice and this permission notice shall be included in all copies or substantial \n    portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \n    LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION \n    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    ------------------------------------------------------------------------------------------------------\n*/\n\n#if defined(__AVR__)\n#error \"Sorry, i2c_t3 only works on Teensy LC and 3.x boards.  Use Wire for Teensy 2.0.\"\n#endif\n\n#if !defined(I2C_T3_H) && (defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || \\\n                           defined(__MK64FX512__) || defined(__MK66FX1M0__)) // 3.0/3.1-3.2/LC/3.5/3.6\n#define I2C_T3_H\n\n#include <inttypes.h>\n#include <stdio.h> // for size_t\n#include \"Arduino.h\"\n#include <DMAChannel.h>\n\n// TODO missing kinetis.h defs\n#ifndef I2C_F_DIV52\n    #define I2C_F_DIV52  ((uint8_t)0x43)\n    #define I2C_F_DIV60  ((uint8_t)0x45)\n    #define I2C_F_DIV136 ((uint8_t)0x4F)\n    #define I2C_F_DIV176 ((uint8_t)0x55)\n    #define I2C_F_DIV352 ((uint8_t)0x95)\n    #define I2C_FLT_SSIE    ((uint8_t)0x20)         // Start/Stop Interrupt Enable\n    #define I2C_FLT_STARTF  ((uint8_t)0x10)         // Start Detect Flag\n#endif\n\n\n// ======================================================================================================\n// == Start User Define Section =========================================================================\n// ======================================================================================================\n\n// ------------------------------------------------------------------------------------------------------\n// I2C Bus Enable control - change to enable buses as follows.  The number of buses will be limited to the\n//                          lower of this setting or what is available on the device.\n//\n// Teensy   Max #Buses\n// ------   ----------\n//   LC         2\n//  3.0         1\n//  3.1         2\n//  3.2         2\n//  3.5         3\n//  3.6         4\n//\n// I2C_BUS_ENABLE 1   (enable Wire only)\n// I2C_BUS_ENABLE 2   (enable Wire & Wire1)\n// I2C_BUS_ENABLE 3   (enable Wire & Wire1 & Wire2)\n// I2C_BUS_ENABLE 4   (enable Wire & Wire1 & Wire2 & Wire3)\n//\n#define I2C_BUS_ENABLE 4\n\n// ------------------------------------------------------------------------------------------------------\n// Tx/Rx buffer sizes - modify these as needed.  Buffers should be large enough to hold:\n//                      Target Addr + Data payload.  Default is: 1byte Addr + 258byte Data\n//                      (this can be substantially reduced if working with sensors or small data packets)\n//\n#define I2C_TX_BUFFER_LENGTH 259\n#define I2C_RX_BUFFER_LENGTH 259\n\n// ------------------------------------------------------------------------------------------------------\n// Interrupt flag - uncomment and set below to make the specified pin high whenever the\n//                  I2C interrupt occurs (modify pin number as needed).  This is useful as a\n//                  trigger signal when using a logic analyzer.\n//\n//#define I2C0_INTR_FLAG_PIN 5\n//#define I2C1_INTR_FLAG_PIN 6\n//#define I2C2_INTR_FLAG_PIN 9\n//#define I2C3_INTR_FLAG_PIN 10\n\n// ------------------------------------------------------------------------------------------------------\n// Auto retry - uncomment to make the library automatically call resetBus() if it has a timeout while\n//              trying to send a START (occurs at the beginning of any endTransmission() or requestFrom()\n//              call).  This will toggle SCL to try and get a hung Slave device to release the SDA line.\n//              If successful then it will try again to send a START, if not then it will return a timeout\n//              error (same as if auto retry was not defined).\n//\n// Note: this is incompatible with multi-master buses, only use in single-master configurations\n//\n//#define I2C_AUTO_RETRY\n\n// ------------------------------------------------------------------------------------------------------\n// Error counters - uncomment to make the library track error counts.  Error counts can be retrieved or\n//                  zeroed using the getErrorCount() and zeroErrorCount() functions respectively.\n//                  When included, errors will be tracked on the following (Master-mode only):\n//                  Reset Bus (auto-retry only), Timeout, Addr NAK, Data NAK, Arb Lost, Bus Not Acquired,\n//                  DMA Errors\n//\n#define I2C_ERROR_COUNTERS\n\n// ------------------------------------------------------------------------------------------------------\n// Disable priority check - uncomment this to entirely disable auto priority escalation.  Normally\n//                          priority escalation occurs to ensure I2C ISR operates at a higher priority\n//                          than the calling function (to prevent ISR stall if the calling function\n//                          blocks).  Uncommenting this will disable the check and cause I2C ISR to\n//                          remain at default priority.  It is recommended to disable this check and\n//                          manually set ISR priority levels when using complex configurations.\n//\n//#define I2C_DISABLE_PRIORITY_CHECK\n\n\n// ======================================================================================================\n// == End User Define Section ===========================================================================\n// ======================================================================================================\n\n\n// ------------------------------------------------------------------------------------------------------\n// Set number of enabled buses\n//\n#if defined(__MK20DX128__) // 3.0\n    #define I2C_BUS_NUM 1\n#elif (defined(__MK20DX256__) || defined(__MKL26Z64__)) && (I2C_BUS_ENABLE >= 2) // 3.1/3.2/LC\n    #define I2C_BUS_NUM 2\n#elif defined(__MK64FX512__) && (I2C_BUS_ENABLE >= 3) // 3.5\n    #define I2C_BUS_NUM 3\n#elif defined(__MK66FX1M0__) && (I2C_BUS_ENABLE >= 4) // 3.6\n    #define I2C_BUS_NUM 4\n#else\n    #define I2C_BUS_NUM I2C_BUS_ENABLE\n#endif\n\n\n// ------------------------------------------------------------------------------------------------------\n// Interrupt flag setup\n//\n#if defined(I2C0_INTR_FLAG_PIN)\n    #define I2C0_INTR_FLAG_INIT do             \\\n    {                                          \\\n        pinMode(I2C0_INTR_FLAG_PIN, OUTPUT);   \\\n        digitalWrite(I2C0_INTR_FLAG_PIN, LOW); \\\n    } while(0)\n\n    #define I2C0_INTR_FLAG_ON   do {digitalWrite(I2C0_INTR_FLAG_PIN, HIGH);} while(0)\n    #define I2C0_INTR_FLAG_OFF  do {digitalWrite(I2C0_INTR_FLAG_PIN, LOW);} while(0)\n#else\n    #define I2C0_INTR_FLAG_INIT do{}while(0)\n    #define I2C0_INTR_FLAG_ON   do{}while(0)\n    #define I2C0_INTR_FLAG_OFF  do{}while(0)\n#endif\n\n#if defined(I2C1_INTR_FLAG_PIN)\n    #define I2C1_INTR_FLAG_INIT do             \\\n    {                                          \\\n        pinMode(I2C1_INTR_FLAG_PIN, OUTPUT);   \\\n        digitalWrite(I2C1_INTR_FLAG_PIN, LOW); \\\n    } while(0)\n\n    #define I2C1_INTR_FLAG_ON   do {digitalWrite(I2C1_INTR_FLAG_PIN, HIGH);} while(0)\n    #define I2C1_INTR_FLAG_OFF  do {digitalWrite(I2C1_INTR_FLAG_PIN, LOW);} while(0)\n#else\n    #define I2C1_INTR_FLAG_INIT do{}while(0)\n    #define I2C1_INTR_FLAG_ON   do{}while(0)\n    #define I2C1_INTR_FLAG_OFF  do{}while(0)\n#endif\n\n#if defined(I2C2_INTR_FLAG_PIN)\n    #define I2C2_INTR_FLAG_INIT do             \\\n    {                                          \\\n        pinMode(I2C2_INTR_FLAG_PIN, OUTPUT);   \\\n        digitalWrite(I2C2_INTR_FLAG_PIN, LOW); \\\n    } while(0)\n\n    #define I2C2_INTR_FLAG_ON   do {digitalWrite(I2C2_INTR_FLAG_PIN, HIGH);} while(0)\n    #define I2C2_INTR_FLAG_OFF  do {digitalWrite(I2C2_INTR_FLAG_PIN, LOW);} while(0)\n#else\n    #define I2C2_INTR_FLAG_INIT do{}while(0)\n    #define I2C2_INTR_FLAG_ON   do{}while(0)\n    #define I2C2_INTR_FLAG_OFF  do{}while(0)\n#endif\n\n#if defined(I2C3_INTR_FLAG_PIN)\n    #define I2C3_INTR_FLAG_INIT do             \\\n    {                                          \\\n        pinMode(I2C3_INTR_FLAG_PIN, OUTPUT);   \\\n        digitalWrite(I2C3_INTR_FLAG_PIN, LOW); \\\n    } while(0)\n\n    #define I2C3_INTR_FLAG_ON   do {digitalWrite(I2C3_INTR_FLAG_PIN, HIGH);} while(0)\n    #define I2C3_INTR_FLAG_OFF  do {digitalWrite(I2C3_INTR_FLAG_PIN, LOW);} while(0)\n#else\n    #define I2C3_INTR_FLAG_INIT do{}while(0)\n    #define I2C3_INTR_FLAG_ON   do{}while(0)\n    #define I2C3_INTR_FLAG_OFF  do{}while(0)\n#endif\n\n\n// ------------------------------------------------------------------------------------------------------\n// Error counters setup\n//\n#if defined(I2C_ERROR_COUNTERS)\n    #define I2C_ERR_INC(i2c_err_count) do {if(i2c->errCounts[i2c_err_count] < UINT32_MAX) i2c->errCounts[i2c_err_count]++;} while(0)\n#else\n    #define I2C_ERR_INC(i2c_err_count) do{}while(0)\n#endif\n\n\n// ------------------------------------------------------------------------------------------------------\n// Function argument enums\n//\nenum i2c_op_mode  {I2C_OP_MODE_IMM, I2C_OP_MODE_ISR, I2C_OP_MODE_DMA};\nenum i2c_mode     {I2C_MASTER, I2C_SLAVE};\nenum i2c_pullup   {I2C_PULLUP_EXT, I2C_PULLUP_INT};\nenum i2c_rate     {I2C_RATE_100  = 100000,\n                   I2C_RATE_200  = 200000,\n                   I2C_RATE_300  = 300000,\n                   I2C_RATE_400  = 400000,\n                   I2C_RATE_600  = 600000,\n                   I2C_RATE_800  = 800000,\n                   I2C_RATE_1000 = 1000000,\n                   I2C_RATE_1200 = 1200000,\n                   I2C_RATE_1500 = 1500000,\n                   I2C_RATE_1800 = 1800000,\n                   I2C_RATE_2000 = 2000000,\n                   I2C_RATE_2400 = 2400000,\n                   I2C_RATE_2800 = 2800000,\n                   I2C_RATE_3000 = 3000000};\nenum i2c_stop     {I2C_NOSTOP, I2C_STOP};\nenum i2c_status   {I2C_WAITING,     // stopped states\n                   I2C_TIMEOUT,     //  |\n                   I2C_ADDR_NAK,    //  |\n                   I2C_DATA_NAK,    //  |\n                   I2C_ARB_LOST,    //  |\n                   I2C_BUF_OVF,     //  |\n                   I2C_NOT_ACQ,     //  |\n                   I2C_DMA_ERR,     //  V\n                   I2C_SENDING,     // active states\n                   I2C_SEND_ADDR,   //  |\n                   I2C_RECEIVING,   //  |\n                   I2C_SLAVE_TX,    //  |\n                   I2C_SLAVE_RX};   //  V\nenum i2c_dma_state {I2C_DMA_OFF,\n                    I2C_DMA_ADDR,\n                    I2C_DMA_BULK,\n                    I2C_DMA_LAST};\n#if defined(__MKL26Z64__) // LC\n    enum i2c_pins {I2C_PINS_16_17 = 0,      // 16 SCL0  17 SDA0\n                   I2C_PINS_18_19,          // 19 SCL0  18 SDA0\n                   I2C_PINS_22_23,          // 22 SCL1  23 SDA1\n                   I2C_PINS_DEFAULT,\n                   I2C_PINS_COUNT};\n    const uint8_t i2c_valid_pins[] = { 0, 16, 17, 2,  // bus, scl, sda, alt\n                                       0, 19, 18, 2,\n                                       1, 22, 23, 2,\n                                       0,  0,  0, 0 };\n#elif defined(__MK20DX128__) // 3.0\n    enum i2c_pins {I2C_PINS_16_17 = 0,      // 16 SCL0  17 SDA0\n                   I2C_PINS_18_19,          // 19 SCL0  18 SDA0\n                   I2C_PINS_DEFAULT,\n                   I2C_PINS_COUNT};\n    const uint8_t i2c_valid_pins[] = { 0, 16, 17, 2,  // bus, scl, sda, alt\n                                       0, 19, 18, 2,\n                                       0,  0,  0, 0 };\n#elif defined(__MK20DX256__) // 3.1/3.2\n    enum i2c_pins {I2C_PINS_16_17 = 0,      // 16 SCL0  17 SDA0\n                   I2C_PINS_18_19,          // 19 SCL0  18 SDA0\n                   I2C_PINS_29_30,          // 29 SCL1  30 SDA1\n                   I2C_PINS_26_31,          // 26 SCL1  31 SDA1\n                   I2C_PINS_DEFAULT,\n                   I2C_PINS_COUNT};\n    const uint8_t i2c_valid_pins[] = { 0, 16, 17, 2,  // bus, scl, sda, alt\n                                       0, 19, 18, 2,\n                                       1, 29, 30, 2,\n                                       1, 26, 31, 6,\n                                       0,  0,  0, 0 };\n#elif defined(__MK64FX512__) // 3.5\n    enum i2c_pins {I2C_PINS_3_4 = 0,        //  3 SCL2   4 SDA2\n                   I2C_PINS_7_8,            //  7 SCL0   8 SDA0\n                   I2C_PINS_16_17,          // 16 SCL0  17 SDA0\n                   I2C_PINS_18_19,          // 19 SCL0  18 SDA0\n                   I2C_PINS_33_34,          // 33 SCL0  34 SDA0\n                   I2C_PINS_37_38,          // 37 SCL1  38 SDA1\n                   I2C_PINS_47_48,          // 47 SCL0  48 SDA0\n                   I2C_PINS_DEFAULT,\n                   I2C_PINS_COUNT};\n    const uint8_t i2c_valid_pins[] = { 2,  3,  4, 5,  // bus, scl, sda, alt\n                                       0,  7,  8, 7,\n                                       0, 16, 17, 2,\n                                       0, 19, 18, 2,\n                                       0, 33, 34, 5,\n                                       1, 37, 38, 2,\n                                       0, 47, 48, 2,\n                                       0,  0,  0, 0 };\n#elif defined(__MK66FX1M0__) // 3.6\n    enum i2c_pins {I2C_PINS_3_4 = 0,        //  3 SCL2   4 SDA2\n                   I2C_PINS_7_8,            //  7 SCL0   8 SDA0\n                   I2C_PINS_16_17,          // 16 SCL0  17 SDA0\n                   I2C_PINS_18_19,          // 19 SCL0  18 SDA0\n                   I2C_PINS_33_34,          // 33 SCL0  34 SDA0\n                   I2C_PINS_37_38,          // 37 SCL1  38 SDA1\n                   I2C_PINS_47_48,          // 47 SCL0  48 SDA0\n                   I2C_PINS_56_57,          // 57 SCL3  56 SDA3\n                   I2C_PINS_DEFAULT,\n                   I2C_PINS_COUNT};\n    const uint8_t i2c_valid_pins[] = { 2,  3,  4, 5,  // bus, scl, sda, alt\n                                       0,  7,  8, 7,\n                                       0, 16, 17, 2,\n                                       0, 19, 18, 2,\n                                       0, 33, 34, 5,\n                                       1, 37, 38, 2,\n                                       0, 47, 48, 2,\n                                       3, 57, 56, 2,\n                                       0,  0,  0, 0 };\n#endif\nenum i2c_err_count {I2C_ERRCNT_RESET_BUS=0,\n                    I2C_ERRCNT_TIMEOUT,\n                    I2C_ERRCNT_ADDR_NAK,\n                    I2C_ERRCNT_DATA_NAK,\n                    I2C_ERRCNT_ARBL,\n                    I2C_ERRCNT_NOT_ACQ,\n                    I2C_ERRCNT_DMA_ERR};\n\n\n// ------------------------------------------------------------------------------------------------------\n// Divide ratio tables\n//\nconst int32_t i2c_div_num[] =\n    {20,22,24,26,28,30,32,34,36,40,44,48,52,56,60,64,68,72,\n     80,88,96,104,112,128,136,144,160,176,192,224,240,256,288,\n     320,352,384,448,480,512,576,640,768,896,960,1024,1152,\n     1280,1536,1920,1792,2048,2304,2560,3072,3840};\n\nconst uint8_t i2c_div_ratio[] =\n    {I2C_F_DIV20,I2C_F_DIV22,I2C_F_DIV24,I2C_F_DIV26,\n     I2C_F_DIV28,I2C_F_DIV30,I2C_F_DIV32,I2C_F_DIV34,\n     I2C_F_DIV36,I2C_F_DIV40,I2C_F_DIV44,I2C_F_DIV48,\n     I2C_F_DIV52,I2C_F_DIV56,I2C_F_DIV60,I2C_F_DIV64,\n     I2C_F_DIV68,I2C_F_DIV72,I2C_F_DIV80,I2C_F_DIV88,\n     I2C_F_DIV96,I2C_F_DIV104,I2C_F_DIV112,I2C_F_DIV128,\n     I2C_F_DIV136,I2C_F_DIV144,I2C_F_DIV160,I2C_F_DIV176,\n     I2C_F_DIV192,I2C_F_DIV224,I2C_F_DIV240,I2C_F_DIV256,\n     I2C_F_DIV288,I2C_F_DIV320,I2C_F_DIV352,I2C_F_DIV384,\n     I2C_F_DIV448,I2C_F_DIV480,I2C_F_DIV512,I2C_F_DIV576,\n     I2C_F_DIV640,I2C_F_DIV768,I2C_F_DIV896,I2C_F_DIV960,\n     I2C_F_DIV1024,I2C_F_DIV1152,I2C_F_DIV1280,I2C_F_DIV1536,\n     I2C_F_DIV1920,I2C_F_DIV1792,I2C_F_DIV2048,I2C_F_DIV2304,\n     I2C_F_DIV2560,I2C_F_DIV3072,I2C_F_DIV3840};\n\n\n// ------------------------------------------------------------------------------------------------------\n// Main I2C data structure\n//\nstruct i2cStruct\n{\n    volatile uint8_t* A1;                    // Address Register 1                (User&ISR)\n    volatile uint8_t* F;                     // Frequency Divider Register        (User&ISR)\n    volatile uint8_t* C1;                    // Control Register 1                (User&ISR)\n    volatile uint8_t* S;                     // Status Register                   (User&ISR)\n    volatile uint8_t* D;                     // Data I/O Register                 (User&ISR)\n    volatile uint8_t* C2;                    // Control Register 2                (User&ISR)\n    volatile uint8_t* FLT;                   // Programmable Input Glitch Filter  (User&ISR)\n    volatile uint8_t* RA;                    // Range Address Register            (User&ISR)\n    volatile uint8_t* SMB;                   // SMBus Control and Status Register (User&ISR)\n    volatile uint8_t* A2;                    // Address Register 2                (User&ISR)\n    volatile uint8_t* SLTH;                  // SCL Low Timeout Register High     (User&ISR)\n    volatile uint8_t* SLTL;                  // SCL Low Timeout Register Low      (User&ISR)\n    uint8_t  rxBuffer[I2C_RX_BUFFER_LENGTH]; // Rx Buffer                         (ISR)\n    volatile size_t   rxBufferIndex;         // Rx Index                          (User&ISR)\n    volatile size_t   rxBufferLength;        // Rx Length                         (ISR)\n    uint8_t  txBuffer[I2C_TX_BUFFER_LENGTH]; // Tx Buffer                         (User)\n    volatile size_t   txBufferIndex;         // Tx Index                          (User&ISR)\n    volatile size_t   txBufferLength;        // Tx Length                         (User&ISR)\n    i2c_op_mode opMode;                      // Operating Mode                    (User)\n    i2c_mode currentMode;                    // Current Mode                      (User)\n    volatile uint8_t  currentSCL;            // Current SCL pin                   (User&ISR)\n    volatile uint8_t  currentSDA;            // Current SDA pin                   (User&ISR)\n    i2c_pullup currentPullup;                // Current Pullup                    (User)\n    uint32_t currentRate;                    // Current Rate                      (User)\n    i2c_stop currentStop;                    // Current Stop                      (User)\n    volatile i2c_status currentStatus;       // Current Status                    (User&ISR)\n    uint8_t  rxAddr;                         // Rx Address                        (ISR)\n    size_t   reqCount;                       // Byte Request Count                (User)\n    uint8_t  irqCount;                       // IRQ Count, used by SDA-rising ISR (ISR)\n    uint8_t  timeoutRxNAK;                   // Rx Timeout NAK flag               (ISR)\n    volatile i2c_dma_state activeDMA;        // Active DMA flag                   (User&ISR)\n    void (*user_onTransmitDone)(void);       // Master Tx Callback Function       (User)\n    void (*user_onReqFromDone)(void);        // Master Rx Callback Function       (User)\n    void (*user_onReceive)(size_t len);      // Slave Rx Callback Function        (User)\n    void (*user_onRequest)(void);            // Slave Tx Callback Function        (User)\n    void (*user_onError)(void);              // Error Callback Function           (User)\n    DMAChannel* DMA;                         // DMA Channel object                (User&ISR)\n    uint32_t defTimeout;                     // Default Timeout                   (User)\n    volatile uint32_t errCounts[7];          // Error Counts Array                (User&ISR)\n    uint8_t  configuredSCL;                  // SCL configured flag               (User)\n    uint8_t  configuredSDA;                  // SDA configured flag               (User)\n};\n\n\n// ------------------------------------------------------------------------------------------------------\n// I2C Class\n//\nextern \"C\" void i2c0_isr(void);\n#if I2C_BUS_NUM >= 2\n    extern \"C\" void i2c1_isr(void);\n#endif\n#if I2C_BUS_NUM >= 3\n    extern \"C\" void i2c2_isr(void);\n#endif\n#if I2C_BUS_NUM >= 4\n    extern \"C\" void i2c3_isr(void);\n#endif\nextern \"C\" void i2c_isr_handler(struct i2cStruct* i2c, uint8_t bus);\n\nclass i2c_t3 : public Stream\n{\nprivate:\n    //\n    // I2C data structures - these need to be static so \"C\" ISRs can use them\n    //\n    static struct i2cStruct i2cData[I2C_BUS_NUM];\n    //\n    // Base handler - ISRs are non-class global functions, friend of class req'd for data access\n    //\n    friend void i2c_isr_handler(struct i2cStruct* i2c, uint8_t bus);\n    //\n    // Bus ISRs\n    //\n    friend void i2c0_isr(void);                 // I2C0 ISR\n    #if (defined(__MK20DX128__) || defined(__MK20DX256__))\n        static void sda_rising_isr_handler(struct i2cStruct* i2c, uint8_t bus); // Slave STOP base handler - 3.0/3.1/3.2 only\n        static void sda0_rising_isr(void);      // Slave STOP detection (I2C0) - 3.0/3.1/3.2 only\n    #endif\n    #if I2C_BUS_NUM >= 2\n        friend void i2c1_isr(void);             // I2C1 ISR\n        #if defined(__MK20DX256__)\n            static void sda1_rising_isr(void);  // Slave STOP detection (I2C1) - 3.1/3.2 only\n        #endif\n    #endif\n    #if I2C_BUS_NUM >= 3\n        friend void i2c2_isr(void);             // I2C2 ISR\n    #endif\n    #if I2C_BUS_NUM >= 4\n        friend void i2c3_isr(void);             // I2C3 ISR\n    #endif\n\npublic:\n    //\n    // I2C bus number - this is a local, passed as an argument to base functions\n    //                  since static functions cannot see it.\n    uint8_t bus;\n    //\n    // I2C structure pointer - this is a local, passed as an argument to base functions\n    //                         since static functions cannot see it.\n    struct i2cStruct* i2c;\n    //\n    // I2C ISR Active flag - this is used to disable priority escalation.  Increment to 1 to disable priority\n    //                       check.  This is a global flag to prevent complex cross-bus issues.  It is only\n    //                       incremented/decremented, not set.\n    //\n    static volatile uint8_t isrActive;\n\n    // ------------------------------------------------------------------------------------------------------\n    // Constructor\n    //\n    i2c_t3(uint8_t i2c_bus);\n    ~i2c_t3();\n\n    // ------------------------------------------------------------------------------------------------------\n    // Pin Mapping - convert i2c_pins enum into pin values, intended for internal use only\n    //\n    inline uint8_t mapSCL(i2c_pins pins) { return i2c_valid_pins[pins*4+1]; }\n    inline uint8_t mapSDA(i2c_pins pins) { return i2c_valid_pins[pins*4+2]; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Valid pin checks - verify if SCL or SDA pin is valid, intended for internal use only\n    // return: alt setting, 0=not valid\n    // parameters:\n    //      bus = bus number\n    //      pin = pin number to check\n    //      offset = array offset\n    //\n    static uint8_t validPin_(uint8_t bus, uint8_t pin, uint8_t offset);\n\n    // ------------------------------------------------------------------------------------------------------\n    // Initialize I2C (base routine)\n    //\n    static void begin_(struct i2cStruct* i2c, uint8_t bus, i2c_mode mode, uint8_t address1, uint8_t address2,\n                       uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup, uint32_t rate, i2c_op_mode opMode);\n    //\n    // Initialize I2C (Master) - initializes I2C as Master mode, external pullups, 100kHz rate,\n    //                           and default pin setting\n    // default pin setting SCL/SDA:\n    //      Wire:   19/18\n    //      Wire1:  29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)\n    //      Wire2:   3/4  (3.5/3.6)\n    //      Wire3:  57/56 (3.6)\n    // return: none\n    //\n    inline void begin(void)\n        { begin_(i2c, bus, I2C_MASTER, 0, 0, 0, 0, I2C_PULLUP_EXT, 100000, I2C_OP_MODE_ISR); }\n    //\n    // Initialize I2C (Slave) - initializes I2C as Slave mode using address, external pullups, 100kHz rate,\n    //                          and default pin setting\n    // default pin setting SCL/SDA:\n    //      Wire:   19/18\n    //      Wire1:  29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)\n    //      Wire2:   3/4  (3.5/3.6)\n    //      Wire3:  57/56 (3.6)\n    // return: none\n    // parameters:\n    //      address = 7bit slave address of device\n    //\n    inline void begin(int address)\n        { begin_(i2c, bus, I2C_SLAVE, (uint8_t)address, 0, 0, 0, I2C_PULLUP_EXT, 100000, I2C_OP_MODE_ISR); }\n    inline void begin(uint8_t address)\n        { begin_(i2c, bus, I2C_SLAVE, address, 0, 0, 0, I2C_PULLUP_EXT, 100000, I2C_OP_MODE_ISR); }\n    //\n    // Initialize I2C - initializes I2C as Master or single address Slave\n    // return: none\n    // parameters (optional parameters marked '^'):\n    //      mode = I2C_MASTER, I2C_SLAVE\n    //      address1 = 7bit slave address when configured as Slave (ignored for Master mode)\n    //     ^address2 = 2nd 7bit address for specifying Slave address range (ignored for Master mode)\n    //     ^pins = pins to use, can be specified as 'i2c_pins' enum,\n    //             or as 'SCL,SDA' pair (using any valid SCL or SDA), options are:\n    //                                 Pin Name\n    //          Interface  Devices   (deprecated)    SCL    SDA   Default\n    //          ---------  -------  --------------  -----  -----  -------\n    //             Wire      All    I2C_PINS_16_17    16     17\n    //             Wire      All    I2C_PINS_18_19    19*    18      +\n    //             Wire    3.5/3.6  I2C_PINS_7_8       7      8\n    //             Wire    3.5/3.6  I2C_PINS_33_34    33     34\n    //             Wire    3.5/3.6  I2C_PINS_47_48    47     48\n    //            Wire1       LC    I2C_PINS_22_23    22     23      +\n    //            Wire1    3.1/3.2  I2C_PINS_26_31    26     31\n    //            Wire1    3.1/3.2  I2C_PINS_29_30    29     30      +\n    //            Wire1    3.5/3.6  I2C_PINS_37_38    37     38      +\n    //            Wire2    3.5/3.6  I2C_PINS_3_4       3      4      +\n    //            Wire3      3.6    I2C_PINS_56_57    57*    56      +\n    //          (note: in almost all cases SCL is the lower pin #, except cases marked *)\n    //     ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)\n    //     ^rate = I2C frequency to use, can be specified directly in Hz, eg. 400000 for 400kHz, or using one of the\n    //             following enum values (deprecated):\n    //             I2C_RATE_100, I2C_RATE_200, I2C_RATE_300, I2C_RATE_400,\n    //             I2C_RATE_600, I2C_RATE_800, I2C_RATE_1000, I2C_RATE_1200,\n    //             I2C_RATE_1500, I2C_RATE_1800, I2C_RATE_2000, I2C_RATE_2400,\n    //             I2C_RATE_2800, I2C_RATE_3000\n    //     ^opMode = I2C_OP_MODE_IMM, I2C_OP_MODE_ISR, I2C_OP_MODE_DMA (ignored for Slave mode, defaults ISR mode)\n    //\n    inline void begin(i2c_mode mode, uint8_t address1, i2c_pins pins=I2C_PINS_DEFAULT,\n                      i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)\n        { begin_(i2c, bus, mode, address1, 0, mapSCL(pins), mapSDA(pins), pullup, rate, opMode); }\n\n    inline void begin(i2c_mode mode, uint8_t address1, uint8_t pinSCL, uint8_t pinSDA,\n                      i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)\n        { begin_(i2c, bus, mode, address1, 0, pinSCL, pinSDA, pullup, rate, opMode); }\n\n    inline void begin(i2c_mode mode, uint8_t address1, uint8_t address2, i2c_pins pins=I2C_PINS_DEFAULT,\n                      i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)\n        { begin_(i2c, bus, mode, address1, address2, mapSCL(pins), mapSDA(pins), pullup, rate, opMode); }\n\n    inline void begin(i2c_mode mode, uint8_t address1, uint8_t address2, uint8_t pinSCL, uint8_t pinSDA,\n                      i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)\n        { begin_(i2c, bus, mode, address1, address2, pinSCL, pinSDA, pullup, rate, opMode); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set Operating Mode (base routine)\n    //\n    static uint8_t setOpMode_(struct i2cStruct* i2c, uint8_t bus, i2c_op_mode opMode);\n    //\n    // Set Operating Mode - this configures operating mode of the I2C as either Immediate, ISR, or DMA.\n    //                      By default Arduino-style begin() calls will initialize to ISR mode.  This can\n    //                      only be called when the bus is idle (no changing mode in the middle of Tx/Rx).\n    //                      Note that Slave mode can only use ISR operation.\n    // return: 1=success, 0=fail (bus busy)\n    // parameters:\n    //      opMode = I2C_OP_MODE_ISR, I2C_OP_MODE_DMA, I2C_OP_MODE_IMM\n    //\n    inline uint8_t setOpMode(i2c_op_mode opMode) { return setOpMode_(i2c, bus, opMode); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set I2C rate (base routine)\n    //\n    static void setRate_(struct i2cStruct* i2c, uint32_t busFreq, uint32_t i2cFreq);\n    //\n    // Set I2C rate - reconfigures I2C frequency divider based on supplied bus freq and desired I2C freq.\n    //                This will be done assuming an idealized I2C rate, even though at high I2C rates\n    //                the actual throughput is much lower than theoretical value.\n    //\n    //                Since the division ratios are quantized with non-uniform spacing, the selected rate\n    //                will be the one using the nearest available divider.\n    // return: none\n    // parameters:\n    //      busFreq = bus frequency, typically F_BUS unless reconfigured\n    //      freq = desired I2C frequency (will be quantized to nearest rate), or can be I2C_RATE_XXX enum (deprecated),\n    //             such as I2C_RATE_100, I2C_RATE_400, etc...\n    //\n    // Max I2C rate is 1/20th F_BUS.  Some examples:\n    //\n    //     F_CPU      F_BUS     Max I2C\n    //     (MHz)      (MHz)       Rate\n    // -------------  -----    ----------\n    //    240/120      120        6.0M    bus overclock\n    //      216        108        5.4M    bus overclock\n    //     192/96       96        4.8M    bus overclock\n    //      180         90        4.5M    bus overclock\n    //      240         80        4.0M    bus overclock\n    //   216/144/72     72        3.6M    bus overclock\n    //      192         64        3.2M    bus overclock\n    //  240/180/120     60        3.0M\n    //      168         56        2.8M\n    //      216         54        2.7M\n    // 192/144/96/48    48        2.4M\n    //       72         36        1.8M\n    //       24         24        1.2M\n    //       16         16        800k\n    //        8          8        400k\n    //        4          4        200k\n    //        2          2        100k\n    //\n    inline void setRate(uint32_t busFreq, uint32_t i2cFreq) { setRate_(i2c, busFreq, i2cFreq); }\n    // return value and i2c_rate enum no longer needed (deprecated form, always returns 1)\n    inline uint8_t setRate(uint32_t busFreq, i2c_rate rate) { setRate_(i2c, busFreq, (uint32_t)rate); return 1; }\n    // Wire compatibility\n    inline void setClock(uint32_t i2cFreq)\n    {\n        #if defined(__MKL26Z64__) // LC\n            if(i2c->currentSCL == 22)\n                setRate_(i2c, (uint32_t)F_CPU, i2cFreq); // LC Wire1 bus uses system clock (F_CPU) instead of bus clock (F_BUS)\n            else\n                setRate_(i2c, (uint32_t)F_BUS, i2cFreq);\n        #else\n            setRate_(i2c, (uint32_t)F_BUS, i2cFreq);\n        #endif\n    }\n    // i2c_t3 version of setClock (deprecated)\n    inline uint8_t setRate(i2c_rate rate) { setClock((uint32_t)rate); return 1; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Get I2C clock - return current clock setting\n    // return: uint32_t = bus frequency (Hz)\n    // parameters: none\n    inline uint32_t getClock(void) { return i2c->currentRate; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Configure I2C pins (base routine)\n    //\n    static uint8_t pinConfigure_(struct i2cStruct* i2c, uint8_t bus, uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup, \n                                 uint8_t configuredSCL, uint8_t configuredSDA);\n    //\n    // ------------------------------------------------------------------------------------------------------\n    // Configure I2C pins - reconfigures active I2C pins on-the-fly (only works when bus is idle).  If reconfig\n    //                      set then inactive pins will switch to input mode using same pullup configuration.\n    // return: 1=success, 0=fail (bus busy or incompatible pins)\n    // parameters:\n    //      pins = pins to use, can be specified as 'i2c_pins' enum,\n    //             or as 'SCL,SDA' pair (using any valid SCL or SDA), options are:\n    //                                 Pin Name\n    //          Interface  Devices   (deprecated)    SCL    SDA   Default\n    //          ---------  -------  --------------  -----  -----  -------\n    //             Wire      All    I2C_PINS_16_17    16     17\n    //             Wire      All    I2C_PINS_18_19    19*    18      +\n    //             Wire    3.5/3.6  I2C_PINS_7_8       7      8\n    //             Wire    3.5/3.6  I2C_PINS_33_34    33     34\n    //             Wire    3.5/3.6  I2C_PINS_47_48    47     48\n    //            Wire1       LC    I2C_PINS_22_23    22     23      +\n    //            Wire1    3.1/3.2  I2C_PINS_26_31    26     31\n    //            Wire1    3.1/3.2  I2C_PINS_29_30    29     30      +\n    //            Wire1    3.5/3.6  I2C_PINS_37_38    37     38      +\n    //            Wire2    3.5/3.6  I2C_PINS_3_4       3      4      +\n    //            Wire3      3.6    I2C_PINS_56_57    57*    56      +\n    //          (note: in almost all cases SCL is the lower pin #, except cases marked *)\n    //      ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)\n    //\n    inline uint8_t pinConfigure(i2c_pins pins, i2c_pullup pullup=I2C_PULLUP_EXT)\n        { return pinConfigure_(i2c, bus, mapSCL(pins), mapSDA(pins), pullup, i2c->configuredSCL, i2c->configuredSDA); }\n    inline uint8_t pinConfigure(uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup=I2C_PULLUP_EXT)\n        { return pinConfigure_(i2c, bus, pinSCL, pinSDA, pullup, i2c->configuredSCL, i2c->configuredSDA); }\n    //\n    // ------------------------------------------------------------------------------------------------------\n    // Set SCL/SDA - change the SCL or SDA pin\n    // return: none\n    // parameters:\n    //      pin = pin to use, if invalid then no change will occur\n    inline void setSCL(uint8_t pin) \n        { pinConfigure_(i2c, bus, pin, i2c->currentSDA, i2c->currentPullup, i2c->configuredSCL, 1); }\n    inline void setSDA(uint8_t pin) \n        { pinConfigure_(i2c, bus, i2c->currentSCL, pin, i2c->currentPullup, 1, i2c->configuredSDA); }\n    //\n    // ------------------------------------------------------------------------------------------------------\n    // Get SCL/SDA - get the current SCL or SDA pin\n    // return: pin used\n    //\n    inline uint8_t getSCL(void) { return i2c->currentSCL; }\n    inline uint8_t getSDA(void) { return i2c->currentSDA; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set Default Timeout - sets the default timeout to be applied to all functions called with a timeout of\n    //                       zero (the default in cases where timeout is not specified).  The default is\n    //                       initially zero (infinite wait).\n    // return: none\n    // parameters:\n    //      timeout = timeout in microseconds\n    inline void setDefaultTimeout(uint32_t timeout) { i2c->defTimeout = timeout; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Acquire Bus - acquires bus in Master mode and escalates priority as needed, intended\n    //               for internal use only\n    // return: 1=success, 0=fail (cannot acquire bus)\n    // parameters:\n    //      timeout = timeout in microseconds\n    //      forceImm = flag to indicate if immediate mode is required\n    //\n    static uint8_t acquireBus_(struct i2cStruct* i2c, uint8_t bus, uint32_t timeout, uint8_t& forceImm);\n\n    // ------------------------------------------------------------------------------------------------------\n    // Reset Bus - toggles SCL until SDA line is released (9 clocks max).  This is used to correct\n    //             a hung bus in which a Slave device missed some clocks and remains stuck outputting\n    //             a low signal on SDA (thereby preventing START/STOP signaling).\n    // return: none\n    //\n    static void resetBus_(struct i2cStruct* i2c, uint8_t bus);\n    inline void resetBus(void) { resetBus_(i2c, bus); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Setup Master Transmit - initialize Tx buffer for transmit to slave at address\n    // return: none\n    // parameters:\n    //      address = target 7bit slave address\n    //\n    void beginTransmission(uint8_t address);\n    inline void beginTransmission(int address) { beginTransmission((uint8_t)address); } // Wire compatibility\n\n    // ------------------------------------------------------------------------------------------------------\n    // Master Transmit (base routine) - cannot be static due to call to getError() and in turn getWriteError()\n    //\n    uint8_t endTransmission(struct i2cStruct* i2c, uint8_t bus, i2c_stop sendStop, uint32_t timeout);\n    //\n    // Master Transmit - blocking routine, transmits Tx buffer to slave. i2c_stop parameter can be used\n    //                   to indicate if command should end with a STOP(I2C_STOP) or not (I2C_NOSTOP).\n    //                   Timeout parameter can be optionally specified.\n    // return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error\n    // parameters:\n    //      ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n    //      ^timeout = timeout in microseconds (default 0 = infinite wait)\n    //\n    inline uint8_t endTransmission(i2c_stop sendStop=I2C_STOP, uint32_t timeout=0) { return endTransmission(i2c, bus, sendStop, timeout); }\n    inline uint8_t endTransmission(uint8_t sendStop) { return endTransmission(i2c, bus, (i2c_stop)sendStop, 0); } // Wire compatibility\n\n    // ------------------------------------------------------------------------------------------------------\n    // Send Master Transmit (base routine)\n    //\n    static void sendTransmission_(struct i2cStruct* i2c, uint8_t bus, i2c_stop sendStop, uint32_t timeout);\n    //\n    // Send Master Transmit - non-blocking routine, starts transmit of Tx buffer to slave. i2c_stop parameter can be\n    //                        used to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use\n    //                        done(), finish(), or onTransmitDone() callback to determine completion and\n    //                        status() to determine success/fail.  Note that sendTransmission() does not currently\n    //                        support timeouts (aside from initial bus acquisition which does support it).\n    // return: none\n    // parameters:\n    //     ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n    //\n    inline void sendTransmission(i2c_stop sendStop=I2C_STOP) { sendTransmission_(i2c, bus, sendStop, 0); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Master Receive (base routine)\n    //\n    static size_t requestFrom_(struct i2cStruct* i2c, uint8_t bus, uint8_t addr, size_t len, i2c_stop sendStop, uint32_t timeout);\n    //\n    // Master Receive - Requests length bytes from slave at address. Receive data will be placed in the Rx buffer.\n    //                  i2c_stop parameter can be used to indicate if command should end with a STOP (I2C_STOP) or\n    //                  not (I2C_NOSTOP).  Timeout parameter can be optionally specified.\n    // return: #bytes received = success, 0=fail (0 length request, NAK, timeout, or bus error)\n    // parameters:\n    //      address = target 7bit slave address\n    //      length = number of bytes requested\n    //     ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n    //     ^timeout = timeout in microseconds (default 0 = infinite wait)\n    //\n    inline size_t requestFrom(uint8_t addr, size_t len, i2c_stop sendStop=I2C_STOP, uint32_t timeout=0)\n        { return requestFrom_(i2c, bus, addr, len, sendStop, timeout); }\n    inline size_t requestFrom(int addr, int len)\n        { return requestFrom_(i2c, bus, (uint8_t)addr, (size_t)len, I2C_STOP, 0); } // Wire compatibility\n    inline uint8_t requestFrom(uint8_t addr, uint8_t len, uint8_t sendStop=1)\n        { return (uint8_t)requestFrom_(i2c, bus, addr, (size_t)len, (i2c_stop)sendStop, 0); } // Wire compatibility\n\n    // ------------------------------------------------------------------------------------------------------\n    // Start Master Receive (base routine)\n    //\n    static void sendRequest_(struct i2cStruct* i2c, uint8_t bus, uint8_t addr, size_t len, i2c_stop sendStop, uint32_t timeout);\n    //\n    // Start Master Receive - non-blocking routine, starts request for length bytes from slave at address. Receive\n    //                        data will be placed in the Rx buffer. i2c_stop parameter can be used to indicate if\n    //                        command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use done(), finish()\n    //                        or onReqFromDone() callback to determine completion and status() to determine\n    //                        success/fail.\n    // return: none\n    // parameters:\n    //      address = target 7bit slave address\n    //      length = number of bytes requested\n    //     ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)\n    //\n    inline void sendRequest(uint8_t addr, size_t len, i2c_stop sendStop=I2C_STOP) { sendRequest_(i2c, bus, addr, len, sendStop, 0); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Get Wire Error - returns \"Wire\" error code from a failed Tx/Rx command\n    // return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error\n    //\n    uint8_t getError(void);\n\n    // ------------------------------------------------------------------------------------------------------\n    // Return Status - returns current status of I2C (enum return value)\n    // return: I2C_WAITING, I2C_TIMEOUT, I2C_ADDR_NAK, I2C_DATA_NAK, I2C_ARB_LOST, I2C_BUF_OVF,\n    //         I2C_NOT_ACQ, I2C_DMA_ERR, I2C_SENDING, I2C_SEND_ADDR, I2C_RECEIVING, I2C_SLAVE_TX, I2C_SLAVE_RX\n    //\n    inline i2c_status status(void) { return i2c->currentStatus; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Return Status (base routine)\n    //\n    static uint8_t done_(struct i2cStruct* i2c);\n    //\n    // Done Check - returns simple complete/not-complete value to indicate I2C status\n    // return: 1=Tx/Rx complete (with or without errors), 0=still running\n    //\n    inline uint8_t done(void) { return done_(i2c); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Return Status (base routine)\n    //\n    static uint8_t finish_(struct i2cStruct* i2c, uint8_t bus, uint32_t timeout);\n    //\n    // Finish - blocking routine, loops until Tx/Rx is complete.  Timeout parameter can be optionally specified.\n    // return: 1=success (Tx or Rx completed, no error), 0=fail (NAK, timeout or Arb Lost)\n    // parameters:\n    //      ^timeout = timeout in microseconds (default 0 = infinite wait)\n    //\n    inline uint8_t finish(uint32_t timeout=0) { return finish_(i2c, bus, timeout); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Write - write data byte to Tx buffer\n    // return: #bytes written = success, 0=fail\n    // parameters:\n    //      data = data byte\n    //\n    size_t write(uint8_t data);\n    inline size_t write(unsigned long n) { return write((uint8_t)n); }\n    inline size_t write(long n)          { return write((uint8_t)n); }\n    inline size_t write(unsigned int n)  { return write((uint8_t)n); }\n    inline size_t write(int n)           { return write((uint8_t)n); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Write Array - write count number of bytes from data array to Tx buffer\n    // return: #bytes written = success, 0=fail\n    // parameters:\n    //      data = pointer to uint8_t (or char) array of data\n    //      count = number of bytes to write\n    //\n    // As a special case C-strings (null terminated) can be written without a count byte\n    //\n    size_t write(const uint8_t* data, size_t count);\n    inline size_t write(const char* str, size_t count) { return write((const uint8_t*)str, count); }\n    inline size_t write(const char* str) { return write((const uint8_t*)str, strlen(str)+1); } // write C-string\n\n    // ------------------------------------------------------------------------------------------------------\n    // Available - returns number of remaining available bytes in Rx buffer\n    // return: #bytes available\n    //\n    inline int available(void) { return i2c->rxBufferLength - i2c->rxBufferIndex; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Read (base routine)\n    //\n    static int read_(struct i2cStruct* i2c);\n    //\n    // Read - returns next data byte (signed int) from Rx buffer\n    // return: data, -1 if buffer empty\n    //\n    inline int read(void) { return read_(i2c); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Read Array - read count number of bytes from Rx buffer to data array\n    // return: #bytes read\n    // parameters:\n    //      data = pointer to uint8_t (or char) array of data\n    //      count = number of bytes to read\n    //\n    static size_t read_(struct i2cStruct* i2c, uint8_t* data, size_t count);\n    inline size_t read(uint8_t* data, size_t count) { return read_(i2c, data, count); }\n    inline size_t read(char* str, size_t count) { return read_(i2c, (uint8_t*)str, count); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Peek (base routine)\n    //\n    static int peek_(struct i2cStruct* i2c);\n    //\n    // Peek - returns next data byte (signed int) from Rx buffer without removing it from Rx buffer\n    // return: data, -1 if buffer empty\n    //\n    inline int peek(void) { return peek_(i2c); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Read Byte (base routine)\n    //\n    static uint8_t readByte_(struct i2cStruct* i2c);\n    //\n    // Read Byte - returns next data byte (uint8_t) from Rx buffer\n    // return: data, 0 if buffer empty\n    //\n    inline uint8_t readByte(void) { return readByte_(i2c); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Peek Byte (base routine)\n    //\n    static uint8_t peekByte_(struct i2cStruct* i2c);\n    //\n    // Peek Byte - returns next data byte (uint8_t) from Rx buffer without removing it from Rx buffer\n    // return: data, 0 if buffer empty\n    //\n    inline uint8_t peekByte(void) { return peekByte_(i2c); }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Flush (not implemented)\n    //\n    inline void flush(void) {}\n\n    // ------------------------------------------------------------------------------------------------------\n    // Get Rx Address - returns target address of incoming I2C command. Used for Slaves operating over an address range.\n    // return: rxAddr of last received command\n    //\n    inline uint8_t getRxAddr(void) { return i2c->rxAddr; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set callback function for Master Tx\n    //\n    inline void onTransmitDone(void (*function)(void)) { i2c->user_onTransmitDone = function; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set callback function for Master Rx\n    //\n    inline void onReqFromDone(void (*function)(void)) { i2c->user_onReqFromDone = function; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set callback function for Slave Rx\n    //\n    inline void onReceive(void (*function)(size_t len)) { i2c->user_onReceive = function; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set callback function for Slave Tx\n    //\n    inline void onRequest(void (*function)(void)) { i2c->user_onRequest = function; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Set callback function for Errors\n    //\n    inline void onError(void (*function)(void)) { i2c->user_onError = function; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // Get error count from specified counter\n    // return: error count\n    // parameters:\n    //      counter = I2C_ERRCNT_RESET_BUS, I2C_ERRCNT_TIMEOUT, I2C_ERRCNT_ADDR_NAK, I2C_ERRCNT_DATA_NAK,\n    //                I2C_ERRCNT_ARBL, I2C_ERRCNT_NOT_ACQ, I2C_ERRCNT_DMA_ERR\n    //\n    inline uint32_t getErrorCount(i2c_err_count counter) { return i2c->errCounts[counter]; }\n    // ------------------------------------------------------------------------------------------------------\n    // Zero error count of specified counter\n    // return: none\n    // parameters:\n    //      counter = I2C_ERRCNT_RESET_BUS, I2C_ERRCNT_TIMEOUT, I2C_ERRCNT_ADDR_NAK, I2C_ERRCNT_DATA_NAK,\n    //                I2C_ERRCNT_ARBL, I2C_ERRCNT_NOT_ACQ, I2C_ERRCNT_DMA_ERR\n    //\n    inline void zeroErrorCount(i2c_err_count counter) { i2c->errCounts[counter] = 0; }\n\n    // ------------------------------------------------------------------------------------------------------\n    // For compatibility with pre-1.0 sketches and libraries\n    inline void send(uint8_t b)             { write(b); }\n    inline void send(uint8_t* s, uint8_t n) { write(s, n); }\n    inline void send(int n)                 { write((uint8_t)n); }\n    inline void send(char* s)               { write(s); }\n    inline uint8_t receive(void)            { int c = read(); return (c<0) ? 0 : c; }\n};\n\nextern i2c_t3 Wire;\n#if I2C_BUS_NUM >= 2\n    extern i2c_t3 Wire1;\n#endif\n#if I2C_BUS_NUM >= 3\n    extern i2c_t3 Wire2;\n#endif\n#if I2C_BUS_NUM >= 4\n    extern i2c_t3 Wire3;\n#endif\n\n#endif // I2C_T3_H\n\n/*\n   ------------------------------------------------------------------------------------------------------\n   Changelog\n   ------------------------------------------------------------------------------------------------------\n\n    - (v11.0) Modified 01Dec18 by Brian (nox771 at gmail.com)\n        - Added state variables and modified pinConfigure_() to recognize unconfigured SCL/SDA pins, \n          allowing for setSCL()/setSDA() prior to begin(), which was previously blocked by bus busy \n          check on unconfigured pins.\n        - Header change to MIT permissive license\n\n    - (v10.1) Modified 02Jan18 by Brian (nox771 at gmail.com)\n        - Added User #define to disable priority checks entirely\n        - Added i2c_t3::isrActive flag to dynamically disable priority checks during ISR & callbacks.\n          This is to prevent runaway priority escalation in cases of callbacks with nested Wire calls.\n\n    - (v10.0) Modified 21Oct17 by Brian (nox771 at gmail.com)\n        - Default assignments have been added to many functions for pins/pullup/rate/op_mode, so\n          all those parameters are now optional in many function calls (marked ^ below)\n        - Unbound SCL/SDA pin assignment.  Pins can be specified with either i2c_pins enum or by direct\n          SCL,SDA pin definition (using any valid SCL and SDA pin).  New function summary is:\n            - begin(mode, address1, ^i2c_pins, ^i2c_pullup, ^rate, ^i2c_op_mode)\n            - begin(mode, address1, ^pinSCL, ^pinSDA, ^i2c_pullup, ^rate, ^i2c_op_mode)\n            - pinConfigure(i2c_pins, ^pullup)\n            - pinConfigure(pinSCL, pinSDA, ^pullup)\n            - setSCL(pin)\n            - setSDA(pin)\n            - getSCL()\n            - getSDA()\n          Note: internal to i2c structure, currentPins has been replaced by currentSCL and currentSDA\n        - Added Master callback functions for completion of transfers.  Primarily for\n          sendTransmission/sendRequest, but these will also work on foreground commands\n          endTransmission/requestFrom.  Also added an Error callback for Master bus errors.\n            - onTransmitDone(function) - where function() is called when Master Transmit is complete\n            - onReqFromDone(function) - where function() is called when Master Receive is complete\n            - onError(function) - where function() is called upon any I2C error which terminates the\n                                  Master bus operation (eg. NAK, timeout, acquire fail, etc)\n        - Fixed blocking conditions that could occur in immediate mode\n        - Added error counters which may be optionally enabled via I2C_ERROR_COUNTERS define.  When\n          enabled it will track (Master mode only): Reset Bus (auto-retry only), Timeout, Addr NAK,\n          Data NAK, Arb Lost, Bus Not Acquired, DMA Errors.\n            - i2c_err_count enum, getErrorCount(), and zeroErrorCount() functions added\n\n    - (v9.4) Modified 01Oct17 by Brian (nox771 at gmail.com)\n        - Fixed Slave ISR for LC/3.5/3.6 not properly recognizing RepSTART\n        - Fixed nested Wire calls during Slave ISR receive (calling Wire inside Wire1 Slave ISR)\n        - Added uint8_t and char array read functions - Wire.read(databuf, count);\n\n    - (v9.3) Modified 20Sep17 by Brian (nox771 at gmail.com)\n        - Fixed Slave ISR for LC/3.5/3.6\n\n    - (v9.2) Modified 29Dec16 by Brian (nox771 at gmail.com)\n        - improved resetBus() function to reset C1 state (thanks hw999)\n\n    - (v9.1) Modified 16Oct16 by Brian (nox771 at gmail.com)\n        - applied two fixes due to bug reports:\n            - removed I2C_F_DIV120 setting (120 divide-ratio) for I2C clock\n            - disabled I2C_AUTO_RETRY by default (setting remains but must be manually enabled)\n\n    - (v9) Modified 01Jul16 by Brian (nox771 at gmail.com)\n        - Added support for Teensy 3.5/3.6:\n            - fully supported (Master/Slave modes, IMM/ISR/DMA operation)\n            - supports all available pin/bus options on Wire/Wire1/Wire2/Wire3\n        - Fixed LC slave bug, whereby it was incorrectly detecting STOPs directed to other slaves\n        - I2C rate is now set using a much more flexible method than previously used (this is partially\n          motivated by increasing device count and frequencies).  As a result, the fixed set of rate\n          enums are no longer needed (however they are currently still supported), and desired I2C\n          frequency can be directly specified, eg. for 400kHz, I2C_RATE_400 can be replaced by 400000.\n          Some setRate() functions are deprecated due to these changes.\n\n    - (v8) Modified 02Apr15 by Brian (nox771 at gmail.com)\n        - added support for Teensy LC:\n            - fully supported (Master/Slave modes, IMM/ISR/DMA operation)\n            - Wire: pins 16/17 or 18/19, rate limited to I2C_RATE_1200\n            - Wire1: pins 22/23, rate limited to I2C_RATE_2400\n        - added timeout on acquiring bus (prevents lockup when bus cannot be acquired)\n        - added setDefaultTimeout() function for setting the default timeout to apply to all commands\n        - added resetBus() function for toggling SCL to release stuck Slave devices\n        - added setRate(rate) function, similar to setClock(freq), but using rate specifiers (does not\n                require specifying busFreq)\n        - added I2C_AUTO_RETRY user define\n\n    - (v7) Modified 09Jan15 by Brian (nox771 at gmail.com)\n        - added support for F_BUS frequencies: 60MHz, 56MHz, 48MHz, 36MHz, 24MHz, 16MHz, 8MHz, 4MHz, 2MHz\n        - added new rates: I2C_RATE_1800, I2C_RATE_2800, I2C_RATE_3000\n        - added new priority escalation - in cases where I2C ISR is blocked by having a lower priority than\n                                          calling function, the I2C will either adjust I2C ISR to a higher priority,\n                                          or switch to Immediate mode as needed.\n        - added new operating mode control - I2C can be set to operate in ISR mode, DMA mode (Master only),\n                                             or Immediate Mode (Master only)\n        - added new begin() functions to allow setting the initial operating mode:\n            - begin(i2c_mode mode, uint8_t address, i2c_pins pins, i2c_pullup pullup, i2c_rate rate, i2c_op_mode opMode)\n            - begin(i2c_mode mode, uint8_t address1, uint8_t address2, i2c_pins pins, i2c_pullup pullup, i2c_rate rate, i2c_op_mode opMode)\n        - added new functions:\n            - uint8_t setOpMode(i2c_op_mode opMode) - used to change operating mode on the fly (only when bus is idle)\n            - void sendTransmission() - non-blocking Tx with implicit I2C_STOP, added for symmetry with endTransmission()\n            - uint8_t setRate(uint32_t busFreq, i2c_rate rate) - used to set I2C clock dividers to get desired rate, i2c_rate argument\n            - uint8_t setRate(uint32_t busFreq, uint32_t i2cFreq) - used to set I2C clock dividers to get desired SCL freq, uint32_t argument\n                                                                    (quantized to nearest i2c_rate)\n        - added new Wire compatibility functions:\n            - void setClock(uint32_t i2cFreq) - (note: degenerate form of setRate() with busFreq == F_BUS)\n            - uint8_t endTransmission(uint8_t sendStop)\n            - uint8_t requestFrom(uint8_t addr, uint8_t len)\n            - uint8_t requestFrom(uint8_t addr, uint8_t len, uint8_t sendStop)\n        - fixed bug in Slave Range code whereby onRequest() callback occurred prior to updating rxAddr instead of after\n        - fixed bug in arbitration, was missing from Master Tx mode\n        - removed I2C1 defines (now included in kinetis.h)\n        - removed all debug code (eliminates rbuf dependency)\n\n    - (v6) Modified 16Jan14 by Brian (nox771 at gmail.com)\n        - all new structure using dereferenced pointers instead of hardcoding. This allows functions\n          (including ISRs) to be reused across multiple I2C buses.  Most functions moved to static,\n          which in turn are called by inline user functions.  Added new struct (i2cData) for holding all\n          bus information.\n        - added support for Teensy 3.1 and I2C1 interface on pins 29/30 and 26/31.\n        - added header define (I2C_BUS_ENABLE n) to control number of enabled buses (eg. both I2C0 & I2C1\n          or just I2C0).  When using only I2C0 the code and ram usage will be lower.\n        - added interrupt flag (toggles pin high during ISR) with independent defines for I2C0 and\n          I2C1 (refer to header file), useful for logic analyzer trigger\n\n    - (v5) Modified 09Jun13 by Brian (nox771 at gmail.com)\n        - fixed bug in ISR timeout code in which timeout condition could fail to reset in certain cases\n        - fixed bug in Slave mode in sda_rising_isr attach, whereby it was not getting attached on the addr byte\n        - moved debug routines so they are entirely defined internal to the library (no end user code req'd)\n        - debug routines now use IntervalTimer library\n        - added support for range of Slave addresses\n        - added getRxAddr() for Slave using addr range to determine its called address\n        - removed virtual keyword from all functions (is not a base class)\n\n    - (v1-v4) Modified 26Feb13 by Brian (nox771 at gmail.com)\n        - Reworked begin function:\n            - added option for pins to use (SCL:SDA on 19:18 or 16:17 - note pin order difference)\n            - added option for internal pullup - as mentioned in previous code pullup is very strong,\n                                                 approx 190 ohms, but is possibly useful for high speed I2C\n            - added option for rates - 100kHz, 200kHz, 300kHz, 400kHz, 600kHz, 800kHz, 1MHz, 1.2MHz, <-- 24/48MHz bus\n                                       1.5MHz, 2.0MHz, 2.4MHz                                        <-- 48MHz bus only\n        - Removed string.h dependency (memcpy)\n        - Changed Master modes to interrupt driven\n        - Added non-blocking Tx/Rx routines, and status/done/finish routines:\n            - sendTransmission() - non-blocking transmit\n            - sendRequest() - non-blocking receive\n            - status() - reports current status\n            - done() - indicates Tx/Rx complete (for main loop polling if I2C is running in background)\n            - finish() - loops until Tx/Rx complete or bus error\n        - Added readByte()/peekByte() for uint8_t return values (note: returns 0 instead of -1 if buf empty)\n        - Added fixes for Slave Rx mode - in short Slave Rx on this part is fubar\n          (as proof, notice the difference in the I2Cx_FLT register in the KL25 Sub-Family parts)\n            - the SDA-rising ISR hack can work but only detects STOP conditons.\n              A slave Rx followed by RepSTART won't be detected since bus remains busy.\n              To fix this if IAAS occurs while already in Slave Rx mode then it will\n              assume RepSTART occurred and trigger onReceive callback.\n        - Separated Tx/Rx buffer sizes for asymmetric devices (adjustable in i2c_t3.h)\n        - Changed Tx/Rx buffer indicies to size_t to allow for large (>256 byte) buffers\n        - Left debug routines in place (controlled via header defines - default is OFF).  If debug is\n            enabled, note that it can easily overrun the Debug queue on large I2C transfers, yielding\n            garbage output.  Adjust ringbuf size (in rbuf.h) and possibly PIT interrupt rate to adjust\n            data flow to Serial (note also the buffer in Serial can overflow if written too quickly).\n        - Added getError() function to return Wire error code\n        - Added pinConfigure() function for changing pins on the fly (only when bus not busy)\n        - Added timeouts to endTransmission(), requestFrom(), and finish()\n\n    ------------------------------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "keywords.txt",
    "content": "I2C_BUS_NUM LITERAL1\nI2C_TX_BUFFER_LENGTH    LITERAL1\nI2C_RX_BUFFER_LENGTH    LITERAL1\nI2C_OP_MODE_IMM\tLITERAL1\nI2C_OP_MODE_ISR\tLITERAL1\nI2C_OP_MODE_DMA\tLITERAL1\nI2C_MASTER\tLITERAL1\nI2C_SLAVE\tLITERAL1\nI2C_PINS_3_4\tLITERAL1\nI2C_PINS_7_8\tLITERAL1\nI2C_PINS_16_17\tLITERAL1\nI2C_PINS_18_19\tLITERAL1\nI2C_PINS_22_23\tLITERAL1\nI2C_PINS_26_31\tLITERAL1\nI2C_PINS_29_30\tLITERAL1\nI2C_PINS_33_34\tLITERAL1\nI2C_PINS_37_38\tLITERAL1\nI2C_PINS_47_48\tLITERAL1\nI2C_PINS_56_57\tLITERAL1\nI2C_PULLUP_EXT\tLITERAL1\nI2C_PULLUP_INT\tLITERAL1\nI2C_RATE_100\tLITERAL1\nI2C_RATE_200\tLITERAL1\nI2C_RATE_300\tLITERAL1\nI2C_RATE_400\tLITERAL1\nI2C_RATE_600\tLITERAL1\nI2C_RATE_800\tLITERAL1\nI2C_RATE_1000\tLITERAL1\nI2C_RATE_1200\tLITERAL1\nI2C_RATE_1500\tLITERAL1\nI2C_RATE_1800\tLITERAL1\nI2C_RATE_2000\tLITERAL1\nI2C_RATE_2400\tLITERAL1\nI2C_RATE_2800\tLITERAL1\nI2C_RATE_3000\tLITERAL1\nI2C_NOSTOP\tLITERAL1\nI2C_STOP\tLITERAL1\nI2C_WAITING\tLITERAL1\nI2C_TIMEOUT\tLITERAL1\nI2C_ADDR_NAK\tLITERAL1\nI2C_DATA_NAK\tLITERAL1\nI2C_ARB_LOST\tLITERAL1\nI2C_BUF_OVF\tLITERAL1\nI2C_NOT_ACQ\tLITERAL1\nI2C_DMA_ERR\tLITERAL1\nI2C_SENDING\tLITERAL1\nI2C_SEND_ADDR\tLITERAL1\nI2C_RECEIVING\tLITERAL1\nI2C_SLAVE_TX\tLITERAL1\nI2C_SLAVE_RX\tLITERAL1\nI2C_DMA_OFF\tLITERAL1\nI2C_DMA_ADDR\tLITERAL1\nI2C_DMA_BULK\tLITERAL1\nI2C_DMA_LAST\tLITERAL1\nI2C_ERRCNT_RESET_BUS\tLITERAL1\nI2C_ERRCNT_TIMEOUT\tLITERAL1\nI2C_ERRCNT_ADDR_NAK\tLITERAL1\nI2C_ERRCNT_DATA_NAK\tLITERAL1\nI2C_ERRCNT_ARBL\tLITERAL1\nI2C_ERRCNT_NOT_ACQ\tLITERAL1\nI2C_ERRCNT_DMA_ERR\tLITERAL1\n\nWire\tKEYWORD2\nWire1\tKEYWORD2\nWire2\tKEYWORD2\nWire3\tKEYWORD2\ni2c_t3\tKEYWORD2\nbegin\tKEYWORD2\nsetOpMode\tKEYWORD2\nsetRate\tKEYWORD2\nsetClock\tKEYWORD2\ngetClock\tKEYWORD2\npinConfigure\tKEYWORD2\nsetSCL\tKEYWORD2\nsetSDA\tKEYWORD2\ngetSCL\tKEYWORD2\ngetSDA\tKEYWORD2\nsetDefaultTimeout\tKEYWORD2\nresetBus\tKEYWORD2\nbeginTransmission\tKEYWORD2\nendTransmission\tKEYWORD2\nsendTransmission\tKEYWORD2\nrequestFrom\tKEYWORD2\nsendRequest\tKEYWORD2\ngetError\tKEYWORD2\nstatus\tKEYWORD2\ndone\tKEYWORD2\nfinish\tKEYWORD2\nwrite\tKEYWORD2\navailable\tKEYWORD2\nread\tKEYWORD2\npeek\tKEYWORD2\nreadByte\tKEYWORD2\npeekByte\tKEYWORD2\ngetRxAddr\tKEYWORD2\nonTransmitDone\tKEYWORD2\nonReqFromDone\tKEYWORD2\nonReceive\tKEYWORD2\nonRequest\tKEYWORD2\nonError\tKEYWORD2\ngetErrorCount\tKEYWORD2\nzeroErrorCount\tKEYWORD2\nsend\tKEYWORD2\nreceive\tKEYWORD2\n"
  }
]