| /* | |||||
| 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); | |||||
| } | |||||
| 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(); | |||||
| /* | |||||
| 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 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 | |||||
| // 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(); | |||||
| } | |||||
| */ | 
| // 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); | |||||
| } | |||||
| // 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); | |||||
| } | 
| // 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); | |||||
| } | 
| // 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 | |||||
| } | 
| // 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 | |||||
| } | 
| ####################################### | |||||
| # Syntax Coloring Map For Wire | |||||
| ####################################### | |||||
| ####################################### | |||||
| # Datatypes (KEYWORD1) | |||||
| ####################################### | |||||
| ####################################### | |||||
| # Methods and Functions (KEYWORD2) | |||||
| ####################################### | |||||
| begin KEYWORD2 | |||||
| beginTransmission KEYWORD2 | |||||
| endTransmission KEYWORD2 | |||||
| requestFrom KEYWORD2 | |||||
| send KEYWORD2 | |||||
| receive KEYWORD2 | |||||
| onReceive KEYWORD2 | |||||
| onRequest KEYWORD2 | |||||
| ####################################### | |||||
| # Instances (KEYWORD2) | |||||
| ####################################### | |||||
| Wire KEYWORD2 | |||||
| ####################################### | |||||
| # Constants (LITERAL1) | |||||
| ####################################### | |||||
| /* | |||||
| 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; | |||||
| } | |||||
| } | |||||
| /* | |||||
| 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 | |||||