| @@ -0,0 +1,298 @@ | |||
| /* | |||
| 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(); | |||
| @@ -0,0 +1,79 @@ | |||
| /* | |||
| 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 | |||
| @@ -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(); | |||
| } | |||
| */ | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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 | |||
| } | |||
| @@ -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 | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| ####################################### | |||
| # 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) | |||
| ####################################### | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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 | |||