|
- /*
- TwoWire.cpp - TWI/I2C library for Wiring & Arduino
- Copyright (c) 2006 Nicholas Zambetti. All right reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
- Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
- */
-
- #include "Wire.h"
-
- #if defined(__arm__) && defined(CORE_TEENSY)
-
- #include "kinetis.h"
- #include <string.h> // for memcpy
- #include "core_pins.h"
- //#include "HardwareSerial.h"
- #include "Wire.h"
-
- uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
- uint8_t TwoWire::rxBufferIndex = 0;
- uint8_t TwoWire::rxBufferLength = 0;
- uint8_t TwoWire::txBuffer[BUFFER_LENGTH+1];
- uint8_t TwoWire::txBufferIndex = 0;
- uint8_t TwoWire::txBufferLength = 0;
- uint8_t TwoWire::transmitting = 0;
- uint8_t TwoWire::sda_pin_num = 18;
- uint8_t TwoWire::scl_pin_num = 19;
- void (*TwoWire::user_onRequest)(void) = NULL;
- void (*TwoWire::user_onReceive)(int) = NULL;
-
-
- TwoWire::TwoWire()
- {
- }
-
- static uint8_t slave_mode = 0;
- static uint8_t irqcount=0;
-
-
- void TwoWire::begin(void)
- {
- //serial_begin(BAUD2DIV(115200));
- //serial_print("\nWire Begin\n");
-
- slave_mode = 0;
- SIM_SCGC4 |= SIM_SCGC4_I2C0; // TODO: use bitband
- I2C0_C1 = 0;
- // On Teensy 3.0 external pullup resistors *MUST* be used
- // the PORT_PCR_PE bit is ignored when in I2C mode
- // I2C will not work at all without pullup resistors
- // It might seem like setting PORT_PCR_PE & PORT_PCR_PS
- // would enable pullup resistors. However, there seems
- // to be a bug in chip while I2C is enabled, where setting
- // those causes the port to be driven strongly high.
- if (sda_pin_num == 18) {
- CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- } else if (sda_pin_num == 17) {
- CORE_PIN17_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- }
- if (scl_pin_num == 19) {
- CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- } else if (scl_pin_num == 16) {
- CORE_PIN16_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- }
- setClock(100000);
- I2C0_C2 = I2C_C2_HDRS;
- I2C0_C1 = I2C_C1_IICEN;
- //pinMode(3, OUTPUT);
- //pinMode(4, OUTPUT);
- }
-
- void TwoWire::setClock(uint32_t frequency)
- {
- #if F_BUS == 60000000
- if (frequency < 400000) {
- I2C0_F = 0x2C; // 104 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x1C; // 416 kHz
- } else {
- I2C0_F = 0x12; // 938 kHz
- }
- I2C0_FLT = 4;
- #elif F_BUS == 56000000
- if (frequency < 400000) {
- I2C0_F = 0x2B; // 109 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x1C; // 389 kHz
- } else {
- I2C0_F = 0x0E; // 1 MHz
- }
- I2C0_FLT = 4;
- #elif F_BUS == 48000000
- if (frequency < 400000) {
- I2C0_F = 0x27; // 100 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x1A; // 400 kHz
- } else {
- I2C0_F = 0x0D; // 1 MHz
- }
- I2C0_FLT = 4;
- #elif F_BUS == 40000000
- if (frequency < 400000) {
- I2C0_F = 0x29; // 104 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x19; // 416 kHz
- } else {
- I2C0_F = 0x0B; // 1 MHz
- }
- I2C0_FLT = 3;
- #elif F_BUS == 36000000
- if (frequency < 400000) {
- I2C0_F = 0x28; // 113 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x19; // 375 kHz
- } else {
- I2C0_F = 0x0A; // 1 MHz
- }
- I2C0_FLT = 3;
- #elif F_BUS == 24000000
- if (frequency < 400000) {
- I2C0_F = 0x1F; // 100 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x12; // 375 kHz
- } else {
- I2C0_F = 0x02; // 1 MHz
- }
- I2C0_FLT = 2;
- #elif F_BUS == 16000000
- if (frequency < 400000) {
- I2C0_F = 0x20; // 100 kHz
- } else if (frequency < 1000000) {
- I2C0_F = 0x07; // 400 kHz
- } else {
- I2C0_F = 0x00; // 800 MHz
- }
- I2C0_FLT = 1;
- #elif F_BUS == 8000000
- if (frequency < 400000) {
- I2C0_F = 0x14; // 100 kHz
- } else {
- I2C0_F = 0x00; // 400 kHz
- }
- I2C0_FLT = 1;
- #elif F_BUS == 4000000
- if (frequency < 400000) {
- I2C0_F = 0x07; // 100 kHz
- } else {
- I2C0_F = 0x00; // 200 kHz
- }
- I2C0_FLT = 1;
- #elif F_BUS == 2000000
- I2C0_F = 0x00; // 100 kHz
- I2C0_FLT = 1;
- #else
- #error "F_BUS must be 60, 56, 48, 40, 36, 24, 16, 8, 4 or 2 MHz"
- #endif
- }
-
- void TwoWire::setSDA(uint8_t pin)
- {
- if (pin == sda_pin_num) return;
- if ((SIM_SCGC4 & SIM_SCGC4_I2C0)) {
- if (sda_pin_num == 18) {
- CORE_PIN18_CONFIG = 0;
- } else if (sda_pin_num == 17) {
- CORE_PIN17_CONFIG = 0;
- }
- if (pin == 18) {
- CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- } else if (pin == 17) {
- CORE_PIN17_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- }
- }
- sda_pin_num = pin;
- }
-
- void TwoWire::setSCL(uint8_t pin)
- {
- if (pin == scl_pin_num) return;
- if ((SIM_SCGC4 & SIM_SCGC4_I2C0)) {
- if (scl_pin_num == 19) {
- CORE_PIN19_CONFIG = 0;
- } else if (scl_pin_num == 16) {
- CORE_PIN16_CONFIG = 0;
- }
- if (pin == 19) {
- CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- } else if (pin == 16) {
- CORE_PIN16_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE;
- }
- }
- scl_pin_num = pin;
- }
-
- void TwoWire::begin(uint8_t address)
- {
- begin();
- I2C0_A1 = address << 1;
- slave_mode = 1;
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE;
- NVIC_ENABLE_IRQ(IRQ_I2C0);
- }
-
- void TwoWire::end()
- {
- NVIC_DISABLE_IRQ(IRQ_I2C0);
- I2C0_C1 = 0;
- CORE_PIN18_CONFIG = 0;
- CORE_PIN19_CONFIG = 0;
- SIM_SCGC4 &= ~SIM_SCGC4_I2C0; // TODO: use bitband
- }
-
- void i2c0_isr(void)
- {
- uint8_t status, c1, data;
- static uint8_t receiving=0;
-
- status = I2C0_S;
- //serial_print(".");
- if (status & I2C_S_ARBL) {
- // Arbitration Lost
- I2C0_S = I2C_S_ARBL;
- //serial_print("a");
- if (receiving && TwoWire::rxBufferLength > 0) {
- // TODO: does this detect the STOP condition in slave receive mode?
-
-
- }
- if (!(status & I2C_S_IAAS)) return;
- }
- if (status & I2C_S_IAAS) {
- //serial_print("\n");
- // Addressed As A Slave
- if (status & I2C_S_SRW) {
- //serial_print("T");
- // Begin Slave Transmit
- receiving = 0;
- TwoWire::txBufferLength = 0;
- if (TwoWire::user_onRequest != NULL) {
- TwoWire::user_onRequest();
- }
- if (TwoWire::txBufferLength == 0) {
- // is this correct, transmitting a single zero
- // when we should send nothing? Arduino's AVR
- // implementation does this, but is it ok?
- TwoWire::txBufferLength = 1;
- TwoWire::txBuffer[0] = 0;
- }
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;
- I2C0_D = TwoWire::txBuffer[0];
- TwoWire::txBufferIndex = 1;
- } else {
- // Begin Slave Receive
- //serial_print("R");
- receiving = 1;
- TwoWire::rxBufferLength = 0;
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE;
- data = I2C0_D;
- }
- I2C0_S = I2C_S_IICIF;
- return;
- }
- #if defined(KINETISL)
- c1 = I2C0_FLT;
- if ((c1 & I2C_FLT_STOPF) && (c1 & I2C_FLT_STOPIE)) {
- I2C0_FLT = c1 & ~I2C_FLT_STOPIE;
- if (TwoWire::user_onReceive != NULL) {
- TwoWire::rxBufferIndex = 0;
- TwoWire::user_onReceive(TwoWire::rxBufferLength);
- }
- }
- #endif
- c1 = I2C0_C1;
- if (c1 & I2C_C1_TX) {
- // Continue Slave Transmit
- //serial_print("t");
- if ((status & I2C_S_RXAK) == 0) {
- //serial_print(".");
- // Master ACK'd previous byte
- if (TwoWire::txBufferIndex < TwoWire::txBufferLength) {
- I2C0_D = TwoWire::txBuffer[TwoWire::txBufferIndex++];
- } else {
- I2C0_D = 0;
- }
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;
- } else {
- //serial_print("*");
- // Master did not ACK previous byte
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE;
- data = I2C0_D;
- }
- } else {
- // Continue Slave Receive
- irqcount = 0;
- #if defined(KINETISK)
- attachInterrupt(18, TwoWire::sda_rising_isr, RISING);
- #elif defined(KINETISL)
- I2C0_FLT |= I2C_FLT_STOPIE;
- #endif
- //digitalWriteFast(4, HIGH);
- data = I2C0_D;
- //serial_phex(data);
- if (TwoWire::rxBufferLength < BUFFER_LENGTH && receiving) {
- TwoWire::rxBuffer[TwoWire::rxBufferLength++] = data;
- }
- //digitalWriteFast(4, LOW);
- }
- I2C0_S = I2C_S_IICIF;
- }
-
- // Detects the stop condition that terminates a slave receive transfer.
- // Sadly, the I2C in Kinetis K series lacks the stop detect interrupt
- // This pin change interrupt hack is needed to detect the stop condition
- void TwoWire::sda_rising_isr(void)
- {
- //digitalWrite(3, HIGH);
- if (!(I2C0_S & I2C_S_BUSY)) {
- detachInterrupt(18);
- if (user_onReceive != NULL) {
- rxBufferIndex = 0;
- user_onReceive(rxBufferLength);
- }
- //delayMicroseconds(100);
- } else {
- if (++irqcount >= 2 || !slave_mode) {
- detachInterrupt(18);
- }
- }
- //digitalWrite(3, LOW);
- }
-
-
- // Chapter 44: Inter-Integrated Circuit (I2C) - Page 1012
- // I2C0_A1 // I2C Address Register 1
- // I2C0_F // I2C Frequency Divider register
- // I2C0_C1 // I2C Control Register 1
- // I2C0_S // I2C Status register
- // I2C0_D // I2C Data I/O register
- // I2C0_C2 // I2C Control Register 2
- // I2C0_FLT // I2C Programmable Input Glitch Filter register
-
- static uint8_t i2c_status(void)
- {
- static uint32_t p=0xFFFF;
- uint32_t s = I2C0_S;
- if (s != p) {
- //Serial.printf("(%02X)", s);
- p = s;
- }
- return s;
- }
-
- static void i2c_wait(void)
- {
- #if 0
- while (!(I2C0_S & I2C_S_IICIF)) ; // wait
- I2C0_S = I2C_S_IICIF;
- #endif
- //Serial.write('^');
- while (1) {
- if ((i2c_status() & I2C_S_IICIF)) break;
- }
- I2C0_S = I2C_S_IICIF;
- }
-
- void TwoWire::beginTransmission(uint8_t address)
- {
- txBuffer[0] = (address << 1);
- transmitting = 1;
- txBufferLength = 1;
- }
-
- size_t TwoWire::write(uint8_t data)
- {
- if (transmitting || slave_mode) {
- if (txBufferLength >= BUFFER_LENGTH+1) {
- setWriteError();
- return 0;
- }
- txBuffer[txBufferLength++] = data;
- return 1;
- }
- return 0;
- }
-
- size_t TwoWire::write(const uint8_t *data, size_t quantity)
- {
- if (transmitting || slave_mode) {
- size_t avail = BUFFER_LENGTH+1 - txBufferLength;
- if (quantity > avail) {
- quantity = avail;
- setWriteError();
- }
- memcpy(txBuffer + txBufferLength, data, quantity);
- txBufferLength += quantity;
- return quantity;
- }
- return 0;
- }
-
- void TwoWire::flush(void)
- {
- }
-
-
- uint8_t TwoWire::endTransmission(uint8_t sendStop)
- {
- uint8_t i, status, ret=0;
-
- // clear the status flags
- I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
- // now take control of the bus...
- if (I2C0_C1 & I2C_C1_MST) {
- // we are already the bus master, so send a repeated start
- //Serial.print("rstart:");
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX;
- } else {
- // we are not currently the bus master, so wait for bus ready
- //Serial.print("busy:");
- uint32_t wait_begin = millis();
- while (i2c_status() & I2C_S_BUSY) {
- //Serial.write('.') ;
- if (millis() - wait_begin > 15) {
- // bus stuck busy too long
- I2C0_C1 = 0;
- I2C0_C1 = I2C_C1_IICEN;
- //Serial.println("abort");
- return 4;
- }
- }
- // become the bus master in transmit mode (send start)
- slave_mode = 0;
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
- }
- // wait until start condition establishes control of the bus
- while (1) {
- status = i2c_status();
- if ((status & I2C_S_BUSY)) break;
- }
- // transmit the address and data
- for (i=0; i < txBufferLength; i++) {
- I2C0_D = txBuffer[i];
- //Serial.write('^');
- while (1) {
- status = i2c_status();
- if ((status & I2C_S_IICIF)) break;
- if (!(status & I2C_S_BUSY)) break;
- }
- I2C0_S = I2C_S_IICIF;
- //Serial.write('$');
- status = i2c_status();
- if ((status & I2C_S_ARBL)) {
- // we lost bus arbitration to another master
- // TODO: what is the proper thing to do here??
- //Serial.printf(" c1=%02X ", I2C0_C1);
- I2C0_C1 = I2C_C1_IICEN;
- ret = 4; // 4:other error
- break;
- }
- if (!(status & I2C_S_BUSY)) {
- // suddenly lost control of the bus!
- I2C0_C1 = I2C_C1_IICEN;
- ret = 4; // 4:other error
- break;
- }
- if (status & I2C_S_RXAK) {
- // the slave device did not acknowledge
- if (i == 0) {
- ret = 2; // 2:received NACK on transmit of address
- } else {
- ret = 3; // 3:received NACK on transmit of data
- }
- sendStop = 1;
- break;
- }
- }
- if (sendStop) {
- // send the stop condition
- I2C0_C1 = I2C_C1_IICEN;
- // TODO: do we wait for this somehow?
- }
- transmitting = 0;
- //Serial.print(" ret=");
- //Serial.println(ret);
- return ret;
- }
-
-
- uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
- {
- uint8_t tmp __attribute__((unused));
- uint8_t status, count=0;
-
- rxBufferIndex = 0;
- rxBufferLength = 0;
- //serial_print("requestFrom\n");
- // clear the status flags
- I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
- // now take control of the bus...
- if (I2C0_C1 & I2C_C1_MST) {
- // we are already the bus master, so send a repeated start
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX;
- } else {
- // we are not currently the bus master, so wait for bus ready
- while (i2c_status() & I2C_S_BUSY) ;
- // become the bus master in transmit mode (send start)
- slave_mode = 0;
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
- }
- // send the address
- I2C0_D = (address << 1) | 1;
- i2c_wait();
- status = i2c_status();
- if ((status & I2C_S_RXAK) || (status & I2C_S_ARBL)) {
- // the slave device did not acknowledge
- // or we lost bus arbitration to another master
- I2C0_C1 = I2C_C1_IICEN;
- return 0;
- }
- if (length == 0) {
- // TODO: does anybody really do zero length reads?
- // if so, does this code really work?
- I2C0_C1 = I2C_C1_IICEN | (sendStop ? 0 : I2C_C1_MST);
- return 0;
- } else if (length == 1) {
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK;
- } else {
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST;
- }
- tmp = I2C0_D; // initiate the first receive
- while (length > 1) {
- i2c_wait();
- length--;
- if (length == 1) I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK;
- rxBuffer[count++] = I2C0_D;
- }
- i2c_wait();
- I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
- rxBuffer[count++] = I2C0_D;
- if (sendStop) I2C0_C1 = I2C_C1_IICEN;
- rxBufferLength = count;
- return count;
- }
-
- int TwoWire::available(void)
- {
- return rxBufferLength - rxBufferIndex;
- }
-
- int TwoWire::read(void)
- {
- if (rxBufferIndex >= rxBufferLength) return -1;
- return rxBuffer[rxBufferIndex++];
- }
-
- int TwoWire::peek(void)
- {
- if (rxBufferIndex >= rxBufferLength) return -1;
- return rxBuffer[rxBufferIndex];
- }
-
-
-
-
-
- // alternate function prototypes
-
- uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
- {
- return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
- }
-
- uint8_t TwoWire::requestFrom(int address, int quantity)
- {
- return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
- }
-
- uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
- {
- return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
- }
-
- void TwoWire::beginTransmission(int address)
- {
- beginTransmission((uint8_t)address);
- }
-
- uint8_t TwoWire::endTransmission(void)
- {
- return endTransmission(true);
- }
-
- void TwoWire::begin(int address)
- {
- begin((uint8_t)address);
- }
-
- void TwoWire::onReceive( void (*function)(int) )
- {
- user_onReceive = function;
- }
-
- void TwoWire::onRequest( void (*function)(void) )
- {
- user_onRequest = function;
- }
-
- //TwoWire Wire = TwoWire();
- TwoWire Wire;
-
-
- #endif // __MK20DX128__ || __MK20DX256__
-
-
-
- #if defined(__AVR__)
-
- extern "C" {
- #include <stdlib.h>
- #include <string.h>
- #include <inttypes.h>
- #include "twi.h"
- }
-
-
- // Initialize Class Variables //////////////////////////////////////////////////
-
- uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
- uint8_t TwoWire::rxBufferIndex = 0;
- uint8_t TwoWire::rxBufferLength = 0;
-
- uint8_t TwoWire::txAddress = 0;
- uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
- uint8_t TwoWire::txBufferIndex = 0;
- uint8_t TwoWire::txBufferLength = 0;
-
- uint8_t TwoWire::transmitting = 0;
- void (*TwoWire::user_onRequest)(void);
- void (*TwoWire::user_onReceive)(int);
-
- // Constructors ////////////////////////////////////////////////////////////////
-
- TwoWire::TwoWire()
- {
- }
-
- // Public Methods //////////////////////////////////////////////////////////////
-
- void TwoWire::begin(void)
- {
- rxBufferIndex = 0;
- rxBufferLength = 0;
-
- txBufferIndex = 0;
- txBufferLength = 0;
-
- twi_init();
- }
-
- void TwoWire::begin(uint8_t address)
- {
- twi_setAddress(address);
- twi_attachSlaveTxEvent(onRequestService);
- twi_attachSlaveRxEvent(onReceiveService);
- begin();
- }
-
- void TwoWire::begin(int address)
- {
- begin((uint8_t)address);
- }
-
- void TwoWire::end()
- {
- TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));
- digitalWrite(SDA, 0);
- digitalWrite(SCL, 0);
- }
-
- void TwoWire::setClock(uint32_t frequency)
- {
- TWBR = ((F_CPU / frequency) - 16) / 2;
- }
-
- void TwoWire::setSDA(uint8_t pin)
- {
- }
-
- void TwoWire::setSCL(uint8_t pin)
- {
- }
-
- uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
- {
- // clamp to buffer length
- if(quantity > BUFFER_LENGTH){
- quantity = BUFFER_LENGTH;
- }
- // perform blocking read into buffer
- uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
- // set rx buffer iterator vars
- rxBufferIndex = 0;
- rxBufferLength = read;
-
- return read;
- }
-
- uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
- {
- return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
- }
-
- uint8_t TwoWire::requestFrom(int address, int quantity)
- {
- return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
- }
-
- uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
- {
- return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
- }
-
- void TwoWire::beginTransmission(uint8_t address)
- {
- // indicate that we are transmitting
- transmitting = 1;
- // set address of targeted slave
- txAddress = address;
- // reset tx buffer iterator vars
- txBufferIndex = 0;
- txBufferLength = 0;
- }
-
- void TwoWire::beginTransmission(int address)
- {
- beginTransmission((uint8_t)address);
- }
-
- //
- // Originally, 'endTransmission' was an f(void) function.
- // It has been modified to take one parameter indicating
- // whether or not a STOP should be performed on the bus.
- // Calling endTransmission(false) allows a sketch to
- // perform a repeated start.
- //
- // WARNING: Nothing in the library keeps track of whether
- // the bus tenure has been properly ended with a STOP. It
- // is very possible to leave the bus in a hung state if
- // no call to endTransmission(true) is made. Some I2C
- // devices will behave oddly if they do not see a STOP.
- //
- uint8_t TwoWire::endTransmission(uint8_t sendStop)
- {
- // transmit buffer (blocking)
- int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
- // reset tx buffer iterator vars
- txBufferIndex = 0;
- txBufferLength = 0;
- // indicate that we are done transmitting
- transmitting = 0;
- return ret;
- }
-
- // This provides backwards compatibility with the original
- // definition, and expected behaviour, of endTransmission
- //
- uint8_t TwoWire::endTransmission(void)
- {
- return endTransmission(true);
- }
-
- // must be called in:
- // slave tx event callback
- // or after beginTransmission(address)
- size_t TwoWire::write(uint8_t data)
- {
- if(transmitting){
- // in master transmitter mode
- // don't bother if buffer is full
- if(txBufferLength >= BUFFER_LENGTH){
- setWriteError();
- return 0;
- }
- // put byte in tx buffer
- txBuffer[txBufferIndex] = data;
- ++txBufferIndex;
- // update amount in buffer
- txBufferLength = txBufferIndex;
- }else{
- // in slave send mode
- // reply to master
- twi_transmit(&data, 1);
- }
- return 1;
- }
-
- // must be called in:
- // slave tx event callback
- // or after beginTransmission(address)
- size_t TwoWire::write(const uint8_t *data, size_t quantity)
- {
- if(transmitting){
- // in master transmitter mode
- for(size_t i = 0; i < quantity; ++i){
- write(data[i]);
- }
- }else{
- // in slave send mode
- // reply to master
- twi_transmit(data, quantity);
- }
- return quantity;
- }
-
- // must be called in:
- // slave rx event callback
- // or after requestFrom(address, numBytes)
- int TwoWire::available(void)
- {
- return rxBufferLength - rxBufferIndex;
- }
-
- // must be called in:
- // slave rx event callback
- // or after requestFrom(address, numBytes)
- int TwoWire::read(void)
- {
- int value = -1;
-
- // get each successive byte on each call
- if(rxBufferIndex < rxBufferLength){
- value = rxBuffer[rxBufferIndex];
- ++rxBufferIndex;
- }
-
- return value;
- }
-
- // must be called in:
- // slave rx event callback
- // or after requestFrom(address, numBytes)
- int TwoWire::peek(void)
- {
- int value = -1;
-
- if(rxBufferIndex < rxBufferLength){
- value = rxBuffer[rxBufferIndex];
- }
-
- return value;
- }
-
- void TwoWire::flush(void)
- {
- // XXX: to be implemented.
- }
-
- // behind the scenes function that is called when data is received
- void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
- {
- // don't bother if user hasn't registered a callback
- if(!user_onReceive){
- return;
- }
- // don't bother if rx buffer is in use by a master requestFrom() op
- // i know this drops data, but it allows for slight stupidity
- // meaning, they may not have read all the master requestFrom() data yet
- if(rxBufferIndex < rxBufferLength){
- return;
- }
- // copy twi rx buffer into local read buffer
- // this enables new reads to happen in parallel
- for(uint8_t i = 0; i < numBytes; ++i){
- rxBuffer[i] = inBytes[i];
- }
- // set rx iterator vars
- rxBufferIndex = 0;
- rxBufferLength = numBytes;
- // alert user program
- user_onReceive(numBytes);
- }
-
- // behind the scenes function that is called when data is requested
- void TwoWire::onRequestService(void)
- {
- // don't bother if user hasn't registered a callback
- if(!user_onRequest){
- return;
- }
- // reset tx buffer iterator vars
- // !!! this will kill any pending pre-master sendTo() activity
- txBufferIndex = 0;
- txBufferLength = 0;
- // alert user program
- user_onRequest();
- }
-
- // sets function called on slave write
- void TwoWire::onReceive( void (*function)(int) )
- {
- user_onReceive = function;
- }
-
- // sets function called on slave read
- void TwoWire::onRequest( void (*function)(void) )
- {
- user_onRequest = function;
- }
-
- // Preinstantiate Objects //////////////////////////////////////////////////////
-
- TwoWire Wire = TwoWire();
-
- #endif // __AVR__
|