diff options
Diffstat (limited to 'libraries/Wire')
| -rw-r--r-- | libraries/Wire/Wire.cpp | 303 | ||||
| -rw-r--r-- | libraries/Wire/Wire.h | 80 | ||||
| -rw-r--r-- | libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino | 87 | ||||
| -rw-r--r-- | libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino | 39 | ||||
| -rw-r--r-- | libraries/Wire/examples/master_reader/master_reader.ino | 32 | ||||
| -rw-r--r-- | libraries/Wire/examples/master_writer/master_writer.ino | 31 | ||||
| -rw-r--r-- | libraries/Wire/examples/slave_receiver/slave_receiver.ino | 38 | ||||
| -rw-r--r-- | libraries/Wire/examples/slave_sender/slave_sender.ino | 32 | ||||
| -rw-r--r-- | libraries/Wire/keywords.txt | 32 | ||||
| -rw-r--r-- | libraries/Wire/library.properties | 8 | ||||
| -rw-r--r-- | libraries/Wire/utility/twi.c | 527 | ||||
| -rw-r--r-- | libraries/Wire/utility/twi.h | 53 | 
12 files changed, 1262 insertions, 0 deletions
| diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp new file mode 100644 index 0000000..553add7 --- /dev/null +++ b/libraries/Wire/Wire.cpp @@ -0,0 +1,303 @@ +/* +  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 +*/ + +extern "C" { +  #include <stdlib.h> +  #include <string.h> +  #include <inttypes.h> +  #include "twi.h" +} + +#include "Wire.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::setClock(uint32_t frequency) +{ +  TWBR = ((F_CPU / frequency) - 16) / 2; +} + +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(); + diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h new file mode 100644 index 0000000..732bdc3 --- /dev/null +++ b/libraries/Wire/Wire.h @@ -0,0 +1,80 @@ +/* +  TwoWire.h - TWI/I2C library for Arduino & Wiring +  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 +*/ + +#ifndef TwoWire_h +#define TwoWire_h + +#include <inttypes.h> +#include "Stream.h" + +#define BUFFER_LENGTH 32 + +class TwoWire : public Stream +{ +  private: +    static uint8_t rxBuffer[]; +    static uint8_t rxBufferIndex; +    static uint8_t rxBufferLength; + +    static uint8_t txAddress; +    static uint8_t txBuffer[]; +    static uint8_t txBufferIndex; +    static uint8_t txBufferLength; + +    static uint8_t transmitting; +    static void (*user_onRequest)(void); +    static void (*user_onReceive)(int); +    static void onRequestService(void); +    static void onReceiveService(uint8_t*, int); +  public: +    TwoWire(); +    void begin(); +    void begin(uint8_t); +    void begin(int); +    void setClock(uint32_t); +    void beginTransmission(uint8_t); +    void beginTransmission(int); +    uint8_t endTransmission(void); +    uint8_t endTransmission(uint8_t); +    uint8_t requestFrom(uint8_t, uint8_t); +    uint8_t requestFrom(uint8_t, uint8_t, uint8_t); +    uint8_t requestFrom(int, int); +    uint8_t requestFrom(int, int, int); +    virtual size_t write(uint8_t); +    virtual size_t write(const uint8_t *, size_t); +    virtual int available(void); +    virtual int read(void); +    virtual int peek(void); +    virtual void flush(void); +    void onReceive( void (*)(int) ); +    void onRequest( void (*)(void) ); + +    inline size_t write(unsigned long n) { return write((uint8_t)n); } +    inline size_t write(long n) { return write((uint8_t)n); } +    inline size_t write(unsigned int n) { return write((uint8_t)n); } +    inline size_t write(int n) { return write((uint8_t)n); } +    using Print::write; +}; + +extern TwoWire Wire; + +#endif + diff --git a/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino b/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino new file mode 100644 index 0000000..d97a9e3 --- /dev/null +++ b/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino @@ -0,0 +1,87 @@ +// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder +// by Nicholas Zambetti <http://www.zambetti.com> +// and James Tichenor <http://www.jamestichenor.net> + +// Demonstrates use of the Wire library reading data from the +// Devantech Utrasonic Rangers SFR08 and SFR10 + +// Created 29 April 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin();                // join i2c bus (address optional for master) +  Serial.begin(9600);          // start serial communication at 9600bps +} + +int reading = 0; + +void loop() +{ +  // step 1: instruct sensor to read echoes +  Wire.beginTransmission(112); // transmit to device #112 (0x70) +  // the address specified in the datasheet is 224 (0xE0) +  // but i2c adressing uses the high 7 bits so it's 112 +  Wire.write(byte(0x00));      // sets register pointer to the command register (0x00) +  Wire.write(byte(0x50));      // command sensor to measure in "inches" (0x50) +  // use 0x51 for centimeters +  // use 0x52 for ping microseconds +  Wire.endTransmission();      // stop transmitting + +  // step 2: wait for readings to happen +  delay(70);                   // datasheet suggests at least 65 milliseconds + +  // step 3: instruct sensor to return a particular echo reading +  Wire.beginTransmission(112); // transmit to device #112 +  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02) +  Wire.endTransmission();      // stop transmitting + +  // step 4: request reading from sensor +  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112 + +  // step 5: receive reading from sensor +  if (2 <= Wire.available())   // if two bytes were received +  { +    reading = Wire.read();  // receive high byte (overwrites previous reading) +    reading = reading << 8;    // shift high byte to be high 8 bits +    reading |= Wire.read(); // receive low byte as lower 8 bits +    Serial.println(reading);   // print the reading +  } + +  delay(250);                  // wait a bit since people have to read the output :) +} + + +/* + +// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) +// usage: changeAddress(0x70, 0xE6); + +void changeAddress(byte oldAddress, byte newAddress) +{ +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(byte(0xA0)); +  Wire.endTransmission(); + +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(byte(0xAA)); +  Wire.endTransmission(); + +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(byte(0xA5)); +  Wire.endTransmission(); + +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(newAddress); +  Wire.endTransmission(); +} + +*/ diff --git a/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino b/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino new file mode 100644 index 0000000..4d1580a --- /dev/null +++ b/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino @@ -0,0 +1,39 @@ +// I2C Digital Potentiometer +// by Nicholas Zambetti <http://www.zambetti.com> +// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/> + +// Demonstrates use of the Wire library +// Controls AD5171 digital potentiometer via I2C/TWI + +// Created 31 March 2006 + +// This example code is in the public domain. + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(); // join i2c bus (address optional for master) +} + +byte val = 0; + +void loop() +{ +  Wire.beginTransmission(44); // transmit to device #44 (0x2c) +  // device address is specified in datasheet +  Wire.write(byte(0x00));            // sends instruction byte +  Wire.write(val);             // sends potentiometer value byte +  Wire.endTransmission();     // stop transmitting + +  val++;        // increment value +  if (val == 64) // if reached 64th position (max) +  { +    val = 0;    // start over from lowest value +  } +  delay(500); +} + diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino new file mode 100644 index 0000000..74f0155 --- /dev/null +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -0,0 +1,32 @@ +// Wire Master Reader +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin();        // join i2c bus (address optional for master) +  Serial.begin(9600);  // start serial for output +} + +void loop() +{ +  Wire.requestFrom(2, 6);    // request 6 bytes from slave device #2 + +  while (Wire.available())   // slave may send less than requested +  { +    char c = Wire.read(); // receive a byte as character +    Serial.print(c);         // print the character +  } + +  delay(500); +} diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino new file mode 100644 index 0000000..482e922 --- /dev/null +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -0,0 +1,31 @@ +// Wire Master Writer +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(); // join i2c bus (address optional for master) +} + +byte x = 0; + +void loop() +{ +  Wire.beginTransmission(4); // transmit to device #4 +  Wire.write("x is ");        // sends five bytes +  Wire.write(x);              // sends one byte +  Wire.endTransmission();    // stop transmitting + +  x++; +  delay(500); +} diff --git a/libraries/Wire/examples/slave_receiver/slave_receiver.ino b/libraries/Wire/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 0000000..15eff9a --- /dev/null +++ b/libraries/Wire/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,38 @@ +// Wire Slave Receiver +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(4);                // join i2c bus with address #4 +  Wire.onReceive(receiveEvent); // register event +  Serial.begin(9600);           // start serial for output +} + +void loop() +{ +  delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) +{ +  while (1 < Wire.available()) // loop through all but the last +  { +    char c = Wire.read(); // receive byte as a character +    Serial.print(c);         // print the character +  } +  int x = Wire.read();    // receive byte as an integer +  Serial.println(x);         // print the integer +} diff --git a/libraries/Wire/examples/slave_sender/slave_sender.ino b/libraries/Wire/examples/slave_sender/slave_sender.ino new file mode 100644 index 0000000..4437ab1 --- /dev/null +++ b/libraries/Wire/examples/slave_sender/slave_sender.ino @@ -0,0 +1,32 @@ +// Wire Slave Sender +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(2);                // join i2c bus with address #2 +  Wire.onRequest(requestEvent); // register event +} + +void loop() +{ +  delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() +{ +  Wire.write("hello "); // respond with message of 6 bytes +  // as expected by master +} diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt new file mode 100644 index 0000000..ff31475 --- /dev/null +++ b/libraries/Wire/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin	KEYWORD2 +setClock	KEYWORD2 +beginTransmission	KEYWORD2 +endTransmission	KEYWORD2 +requestFrom	KEYWORD2 +send	KEYWORD2 +receive	KEYWORD2 +onReceive	KEYWORD2 +onRequest	KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire	KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties new file mode 100644 index 0000000..3246a75 --- /dev/null +++ b/libraries/Wire/library.properties @@ -0,0 +1,8 @@ +name=Wire +version=1.0 +author=Arduino +maintainer=Arduino <info@arduino.cc> +sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For all Arduino boards, BUT Arduino DUE.  +paragraph= +url=http://arduino.cc/en/Reference/Wire +architectures=avr diff --git a/libraries/Wire/utility/twi.c b/libraries/Wire/utility/twi.c new file mode 100644 index 0000000..201d7d1 --- /dev/null +++ b/libraries/Wire/utility/twi.c @@ -0,0 +1,527 @@ +/* +  twi.c - 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 <math.h> +#include <stdlib.h> +#include <inttypes.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <compat/twi.h> +#include "Arduino.h" // for digitalWrite + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif + +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#include "pins_arduino.h" +#include "twi.h" + +static volatile uint8_t twi_state; +static volatile uint8_t twi_slarw; +static volatile uint8_t twi_sendStop;			// should the transaction end with a stop +static volatile uint8_t twi_inRepStart;			// in the middle of a repeated start + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + +static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_masterBufferIndex; +static volatile uint8_t twi_masterBufferLength; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + +static volatile uint8_t twi_error; + +/*  + * Function twi_init + * Desc     readys twi pins and sets twi bitrate + * Input    none + * Output   none + */ +void twi_init(void) +{ +  // initialize state +  twi_state = TWI_READY; +  twi_sendStop = true;		// default value +  twi_inRepStart = false; +   +  // activate internal pullups for twi. +  digitalWrite(SDA, 1); +  digitalWrite(SCL, 1); + +  // initialize twi prescaler and bit rate +  cbi(TWSR, TWPS0); +  cbi(TWSR, TWPS1); +  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; + +  /* twi bit rate formula from atmega128 manual pg 204 +  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) +  note: TWBR should be 10 or higher for master mode +  It is 72 for a 16mhz Wiring board with 100kHz TWI */ + +  // enable twi module, acks, and twi interrupt +  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); +} + +/*  + * Function twi_slaveInit + * Desc     sets slave address and enables interrupt + * Input    none + * Output   none + */ +void twi_setAddress(uint8_t address) +{ +  // set twi slave address (skip over TWGCE bit) +  TWAR = address << 1; +} + +/*  + * Function twi_readFrom + * Desc     attempts to become twi bus master and read a + *          series of bytes from a device on the bus + * Input    address: 7bit i2c device address + *          data: pointer to byte array + *          length: number of bytes to read into array + *          sendStop: Boolean indicating whether to send a stop at the end + * Output   number of bytes read + */ +uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) +{ +  uint8_t i; + +  // ensure data will fit into buffer +  if(TWI_BUFFER_LENGTH < length){ +    return 0; +  } + +  // wait until twi is ready, become master receiver +  while(TWI_READY != twi_state){ +    continue; +  } +  twi_state = TWI_MRX; +  twi_sendStop = sendStop; +  // reset error state (0xFF.. no error occured) +  twi_error = 0xFF; + +  // initialize buffer iteration vars +  twi_masterBufferIndex = 0; +  twi_masterBufferLength = length-1;  // This is not intuitive, read on... +  // On receive, the previously configured ACK/NACK setting is transmitted in +  // response to the received byte before the interrupt is signalled.  +  // Therefor we must actually set NACK when the _next_ to last byte is +  // received, causing that NACK to be sent in response to receiving the last +  // expected byte of data. + +  // build sla+w, slave device address + w bit +  twi_slarw = TW_READ; +  twi_slarw |= address << 1; + +  if (true == twi_inRepStart) { +    // if we're in the repeated start state, then we've already sent the start, +    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. +    // We need to remove ourselves from the repeated start state before we enable interrupts, +    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning +    // up. Also, don't enable the START interrupt. There may be one pending from the  +    // repeated start that we sent outselves, and that would really confuse things. +    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR +    TWDR = twi_slarw; +    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START +  } +  else +    // send start condition +    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); + +  // wait for read operation to complete +  while(TWI_MRX == twi_state){ +    continue; +  } + +  if (twi_masterBufferIndex < length) +    length = twi_masterBufferIndex; + +  // copy twi buffer to data +  for(i = 0; i < length; ++i){ +    data[i] = twi_masterBuffer[i]; +  } +	 +  return length; +} + +/*  + * Function twi_writeTo + * Desc     attempts to become twi bus master and write a + *          series of bytes to a device on the bus + * Input    address: 7bit i2c device address + *          data: pointer to byte array + *          length: number of bytes in array + *          wait: boolean indicating to wait for write or not + *          sendStop: boolean indicating whether or not to send a stop at the end + * Output   0 .. success + *          1 .. length to long for buffer + *          2 .. address send, NACK received + *          3 .. data send, NACK received + *          4 .. other twi error (lost bus arbitration, bus error, ..) + */ +uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) +{ +  uint8_t i; + +  // ensure data will fit into buffer +  if(TWI_BUFFER_LENGTH < length){ +    return 1; +  } + +  // wait until twi is ready, become master transmitter +  while(TWI_READY != twi_state){ +    continue; +  } +  twi_state = TWI_MTX; +  twi_sendStop = sendStop; +  // reset error state (0xFF.. no error occured) +  twi_error = 0xFF; + +  // initialize buffer iteration vars +  twi_masterBufferIndex = 0; +  twi_masterBufferLength = length; +   +  // copy data to twi buffer +  for(i = 0; i < length; ++i){ +    twi_masterBuffer[i] = data[i]; +  } +   +  // build sla+w, slave device address + w bit +  twi_slarw = TW_WRITE; +  twi_slarw |= address << 1; +   +  // if we're in a repeated start, then we've already sent the START +  // in the ISR. Don't do it again. +  // +  if (true == twi_inRepStart) { +    // if we're in the repeated start state, then we've already sent the start, +    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. +    // We need to remove ourselves from the repeated start state before we enable interrupts, +    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning +    // up. Also, don't enable the START interrupt. There may be one pending from the  +    // repeated start that we sent outselves, and that would really confuse things. +    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR +    TWDR = twi_slarw;				 +    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START +  } +  else +    // send start condition +    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);	// enable INTs + +  // wait for write operation to complete +  while(wait && (TWI_MTX == twi_state)){ +    continue; +  } +   +  if (twi_error == 0xFF) +    return 0;	// success +  else if (twi_error == TW_MT_SLA_NACK) +    return 2;	// error: address send, nack received +  else if (twi_error == TW_MT_DATA_NACK) +    return 3;	// error: data send, nack received +  else +    return 4;	// other twi error +} + +/*  + * Function twi_transmit + * Desc     fills slave tx buffer with data + *          must be called in slave tx event callback + * Input    data: pointer to byte array + *          length: number of bytes in array + * Output   1 length too long for buffer + *          2 not slave transmitter + *          0 ok + */ +uint8_t twi_transmit(const uint8_t* data, uint8_t length) +{ +  uint8_t i; + +  // ensure data will fit into buffer +  if(TWI_BUFFER_LENGTH < length){ +    return 1; +  } +   +  // ensure we are currently a slave transmitter +  if(TWI_STX != twi_state){ +    return 2; +  } +   +  // set length and copy data into tx buffer +  twi_txBufferLength = length; +  for(i = 0; i < length; ++i){ +    twi_txBuffer[i] = data[i]; +  } +   +  return 0; +} + +/*  + * Function twi_attachSlaveRxEvent + * Desc     sets function called before a slave read operation + * Input    function: callback function to use + * Output   none + */ +void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) +{ +  twi_onSlaveReceive = function; +} + +/*  + * Function twi_attachSlaveTxEvent + * Desc     sets function called before a slave write operation + * Input    function: callback function to use + * Output   none + */ +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ +  twi_onSlaveTransmit = function; +} + +/*  + * Function twi_reply + * Desc     sends byte or readys receive line + * Input    ack: byte indicating to ack or to nack + * Output   none + */ +void twi_reply(uint8_t ack) +{ +  // transmit master read ready signal, with or without ack +  if(ack){ +    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); +  }else{ +	  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); +  } +} + +/*  + * Function twi_stop + * Desc     relinquishes bus master status + * Input    none + * Output   none + */ +void twi_stop(void) +{ +  // send stop condition +  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + +  // wait for stop condition to be exectued on bus +  // TWINT is not set after a stop condition! +  while(TWCR & _BV(TWSTO)){ +    continue; +  } + +  // update twi state +  twi_state = TWI_READY; +} + +/*  + * Function twi_releaseBus + * Desc     releases bus control + * Input    none + * Output   none + */ +void twi_releaseBus(void) +{ +  // release bus +  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + +  // update twi state +  twi_state = TWI_READY; +} + +ISR(TWI_vect) +{ +  switch(TW_STATUS){ +    // All Master +    case TW_START:     // sent start condition +    case TW_REP_START: // sent repeated start condition +      // copy device address and r/w bit to output register and ack +      TWDR = twi_slarw; +      twi_reply(1); +      break; + +    // Master Transmitter +    case TW_MT_SLA_ACK:  // slave receiver acked address +    case TW_MT_DATA_ACK: // slave receiver acked data +      // if there is data to send, send it, otherwise stop  +      if(twi_masterBufferIndex < twi_masterBufferLength){ +        // copy data to output register and ack +        TWDR = twi_masterBuffer[twi_masterBufferIndex++]; +        twi_reply(1); +      }else{ +	if (twi_sendStop) +          twi_stop(); +	else { +	  twi_inRepStart = true;	// we're gonna send the START +	  // don't enable the interrupt. We'll generate the start, but we  +	  // avoid handling the interrupt until we're in the next transaction, +	  // at the point where we would normally issue the start. +	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; +	  twi_state = TWI_READY; +	} +      } +      break; +    case TW_MT_SLA_NACK:  // address sent, nack received +      twi_error = TW_MT_SLA_NACK; +      twi_stop(); +      break; +    case TW_MT_DATA_NACK: // data sent, nack received +      twi_error = TW_MT_DATA_NACK; +      twi_stop(); +      break; +    case TW_MT_ARB_LOST: // lost bus arbitration +      twi_error = TW_MT_ARB_LOST; +      twi_releaseBus(); +      break; + +    // Master Receiver +    case TW_MR_DATA_ACK: // data received, ack sent +      // put byte into buffer +      twi_masterBuffer[twi_masterBufferIndex++] = TWDR; +    case TW_MR_SLA_ACK:  // address sent, ack received +      // ack if more bytes are expected, otherwise nack +      if(twi_masterBufferIndex < twi_masterBufferLength){ +        twi_reply(1); +      }else{ +        twi_reply(0); +      } +      break; +    case TW_MR_DATA_NACK: // data received, nack sent +      // put final byte into buffer +      twi_masterBuffer[twi_masterBufferIndex++] = TWDR; +	if (twi_sendStop) +          twi_stop(); +	else { +	  twi_inRepStart = true;	// we're gonna send the START +	  // don't enable the interrupt. We'll generate the start, but we  +	  // avoid handling the interrupt until we're in the next transaction, +	  // at the point where we would normally issue the start. +	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; +	  twi_state = TWI_READY; +	}     +	break; +    case TW_MR_SLA_NACK: // address sent, nack received +      twi_stop(); +      break; +    // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case + +    // Slave Receiver +    case TW_SR_SLA_ACK:   // addressed, returned ack +    case TW_SR_GCALL_ACK: // addressed generally, returned ack +    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack +    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack +      // enter slave receiver mode +      twi_state = TWI_SRX; +      // indicate that rx buffer can be overwritten and ack +      twi_rxBufferIndex = 0; +      twi_reply(1); +      break; +    case TW_SR_DATA_ACK:       // data received, returned ack +    case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack +      // if there is still room in the rx buffer +      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ +        // put byte in buffer and ack +        twi_rxBuffer[twi_rxBufferIndex++] = TWDR; +        twi_reply(1); +      }else{ +        // otherwise nack +        twi_reply(0); +      } +      break; +    case TW_SR_STOP: // stop or repeated start condition received +      // put a null char after data if there's room +      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ +        twi_rxBuffer[twi_rxBufferIndex] = '\0'; +      } +      // sends ack and stops interface for clock stretching +      twi_stop(); +      // callback to user defined callback +      twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); +      // since we submit rx buffer to "wire" library, we can reset it +      twi_rxBufferIndex = 0; +      // ack future responses and leave slave receiver state +      twi_releaseBus(); +      break; +    case TW_SR_DATA_NACK:       // data received, returned nack +    case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack +      // nack back at master +      twi_reply(0); +      break; +     +    // Slave Transmitter +    case TW_ST_SLA_ACK:          // addressed, returned ack +    case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack +      // enter slave transmitter mode +      twi_state = TWI_STX; +      // ready the tx buffer index for iteration +      twi_txBufferIndex = 0; +      // set tx buffer length to be zero, to verify if user changes it +      twi_txBufferLength = 0; +      // request for txBuffer to be filled and length to be set +      // note: user must call twi_transmit(bytes, length) to do this +      twi_onSlaveTransmit(); +      // if they didn't change buffer & length, initialize it +      if(0 == twi_txBufferLength){ +        twi_txBufferLength = 1; +        twi_txBuffer[0] = 0x00; +      } +      // transmit first byte from buffer, fall +    case TW_ST_DATA_ACK: // byte sent, ack returned +      // copy data to output register +      TWDR = twi_txBuffer[twi_txBufferIndex++]; +      // if there is more to send, ack, otherwise nack +      if(twi_txBufferIndex < twi_txBufferLength){ +        twi_reply(1); +      }else{ +        twi_reply(0); +      } +      break; +    case TW_ST_DATA_NACK: // received nack, we are done  +    case TW_ST_LAST_DATA: // received ack, but we are done already! +      // ack future responses +      twi_reply(1); +      // leave slave receiver state +      twi_state = TWI_READY; +      break; + +    // All +    case TW_NO_INFO:   // no state information +      break; +    case TW_BUS_ERROR: // bus error, illegal stop/start +      twi_error = TW_BUS_ERROR; +      twi_stop(); +      break; +  } +} + diff --git a/libraries/Wire/utility/twi.h b/libraries/Wire/utility/twi.h new file mode 100644 index 0000000..6526593 --- /dev/null +++ b/libraries/Wire/utility/twi.h @@ -0,0 +1,53 @@ +/* +  twi.h - 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 +*/ + +#ifndef twi_h +#define twi_h + +  #include <inttypes.h> + +  //#define ATMEGA8 + +  #ifndef TWI_FREQ +  #define TWI_FREQ 100000L +  #endif + +  #ifndef TWI_BUFFER_LENGTH +  #define TWI_BUFFER_LENGTH 32 +  #endif + +  #define TWI_READY 0 +  #define TWI_MRX   1 +  #define TWI_MTX   2 +  #define TWI_SRX   3 +  #define TWI_STX   4 +   +  void twi_init(void); +  void twi_setAddress(uint8_t); +  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t); +  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t); +  uint8_t twi_transmit(const uint8_t*, uint8_t); +  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); +  void twi_attachSlaveTxEvent( void (*)(void) ); +  void twi_reply(uint8_t); +  void twi_stop(void); +  void twi_releaseBus(void); + +#endif + | 
