@@ -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 | |||