mirror of https://github.com/noisymime/Arduino.git
Adding ability to send repeated starts in Wire library.
This adds an additional (boolean) parameter to both endTransmission() and requestFrom(), which specifies whether or not to send a stop condition after the corresponding transmission. This defaults to true, as in the previous behavior of the library. http://code.google.com/p/arduino/issues/detail?id=663
This commit is contained in:
parent
561cd7054d
commit
2f29f898de
|
@ -15,6 +15,8 @@
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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" {
|
extern "C" {
|
||||||
|
@ -73,14 +75,14 @@ void TwoWire::begin(int address)
|
||||||
begin((uint8_t)address);
|
begin((uint8_t)address);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
|
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
|
||||||
{
|
{
|
||||||
// clamp to buffer length
|
// clamp to buffer length
|
||||||
if(quantity > BUFFER_LENGTH){
|
if(quantity > BUFFER_LENGTH){
|
||||||
quantity = BUFFER_LENGTH;
|
quantity = BUFFER_LENGTH;
|
||||||
}
|
}
|
||||||
// perform blocking read into buffer
|
// perform blocking read into buffer
|
||||||
uint8_t read = twi_readFrom(address, rxBuffer, quantity);
|
uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
|
||||||
// set rx buffer iterator vars
|
// set rx buffer iterator vars
|
||||||
rxBufferIndex = 0;
|
rxBufferIndex = 0;
|
||||||
rxBufferLength = read;
|
rxBufferLength = read;
|
||||||
|
@ -88,9 +90,19 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
|
||||||
return 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)
|
uint8_t TwoWire::requestFrom(int address, int quantity)
|
||||||
{
|
{
|
||||||
return 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, int sendStop)
|
||||||
|
{
|
||||||
|
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwoWire::beginTransmission(uint8_t address)
|
void TwoWire::beginTransmission(uint8_t address)
|
||||||
|
@ -109,10 +121,23 @@ void TwoWire::beginTransmission(int address)
|
||||||
beginTransmission((uint8_t)address);
|
beginTransmission((uint8_t)address);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t TwoWire::endTransmission(void)
|
//
|
||||||
|
// 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)
|
// transmit buffer (blocking)
|
||||||
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
|
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
|
||||||
// reset tx buffer iterator vars
|
// reset tx buffer iterator vars
|
||||||
txBufferIndex = 0;
|
txBufferIndex = 0;
|
||||||
txBufferLength = 0;
|
txBufferLength = 0;
|
||||||
|
@ -121,6 +146,14 @@ uint8_t TwoWire::endTransmission(void)
|
||||||
return ret;
|
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:
|
// must be called in:
|
||||||
// slave tx event callback
|
// slave tx event callback
|
||||||
// or after beginTransmission(address)
|
// or after beginTransmission(address)
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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
|
#ifndef TwoWire_h
|
||||||
|
@ -50,8 +52,11 @@ class TwoWire : public Stream
|
||||||
void beginTransmission(uint8_t);
|
void beginTransmission(uint8_t);
|
||||||
void beginTransmission(int);
|
void beginTransmission(int);
|
||||||
uint8_t endTransmission(void);
|
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 requestFrom(uint8_t, uint8_t, uint8_t);
|
||||||
uint8_t requestFrom(int, int);
|
uint8_t requestFrom(int, int);
|
||||||
|
uint8_t requestFrom(int, int, int);
|
||||||
virtual size_t write(uint8_t);
|
virtual size_t write(uint8_t);
|
||||||
virtual size_t write(const uint8_t *, size_t);
|
virtual size_t write(const uint8_t *, size_t);
|
||||||
virtual int available(void);
|
virtual int available(void);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 <math.h>
|
||||||
|
@ -37,14 +39,16 @@
|
||||||
#include "twi.h"
|
#include "twi.h"
|
||||||
|
|
||||||
static volatile uint8_t twi_state;
|
static volatile uint8_t twi_state;
|
||||||
static uint8_t twi_slarw;
|
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_onSlaveTransmit)(void);
|
||||||
static void (*twi_onSlaveReceive)(uint8_t*, int);
|
static void (*twi_onSlaveReceive)(uint8_t*, int);
|
||||||
|
|
||||||
static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
|
static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
|
||||||
static volatile uint8_t twi_masterBufferIndex;
|
static volatile uint8_t twi_masterBufferIndex;
|
||||||
static uint8_t twi_masterBufferLength;
|
static volatile uint8_t twi_masterBufferLength;
|
||||||
|
|
||||||
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
|
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
|
||||||
static volatile uint8_t twi_txBufferIndex;
|
static volatile uint8_t twi_txBufferIndex;
|
||||||
|
@ -65,6 +69,8 @@ void twi_init(void)
|
||||||
{
|
{
|
||||||
// initialize state
|
// initialize state
|
||||||
twi_state = TWI_READY;
|
twi_state = TWI_READY;
|
||||||
|
twi_sendStop = true; // default value
|
||||||
|
twi_inRepStart = false;
|
||||||
|
|
||||||
// activate internal pullups for twi.
|
// activate internal pullups for twi.
|
||||||
digitalWrite(SDA, 1);
|
digitalWrite(SDA, 1);
|
||||||
|
@ -103,9 +109,10 @@ void twi_setAddress(uint8_t address)
|
||||||
* Input address: 7bit i2c device address
|
* Input address: 7bit i2c device address
|
||||||
* data: pointer to byte array
|
* data: pointer to byte array
|
||||||
* length: number of bytes to read into 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
|
* Output number of bytes read
|
||||||
*/
|
*/
|
||||||
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
|
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
|
@ -119,6 +126,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
twi_state = TWI_MRX;
|
twi_state = TWI_MRX;
|
||||||
|
twi_sendStop = sendStop;
|
||||||
// reset error state (0xFF.. no error occured)
|
// reset error state (0xFF.. no error occured)
|
||||||
twi_error = 0xFF;
|
twi_error = 0xFF;
|
||||||
|
|
||||||
|
@ -135,6 +143,18 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
|
||||||
twi_slarw = TW_READ;
|
twi_slarw = TW_READ;
|
||||||
twi_slarw |= address << 1;
|
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
|
// send start condition
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
|
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
|
||||||
|
|
||||||
|
@ -162,13 +182,14 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
|
||||||
* data: pointer to byte array
|
* data: pointer to byte array
|
||||||
* length: number of bytes in array
|
* length: number of bytes in array
|
||||||
* wait: boolean indicating to wait for write or not
|
* 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
|
* Output 0 .. success
|
||||||
* 1 .. length to long for buffer
|
* 1 .. length to long for buffer
|
||||||
* 2 .. address send, NACK received
|
* 2 .. address send, NACK received
|
||||||
* 3 .. data send, NACK received
|
* 3 .. data send, NACK received
|
||||||
* 4 .. other twi error (lost bus arbitration, bus error, ..)
|
* 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 twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
|
@ -182,6 +203,7 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
twi_state = TWI_MTX;
|
twi_state = TWI_MTX;
|
||||||
|
twi_sendStop = sendStop;
|
||||||
// reset error state (0xFF.. no error occured)
|
// reset error state (0xFF.. no error occured)
|
||||||
twi_error = 0xFF;
|
twi_error = 0xFF;
|
||||||
|
|
||||||
|
@ -198,8 +220,23 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
|
||||||
twi_slarw = TW_WRITE;
|
twi_slarw = TW_WRITE;
|
||||||
twi_slarw |= address << 1;
|
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
|
// send start condition
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
|
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs
|
||||||
|
|
||||||
// wait for write operation to complete
|
// wait for write operation to complete
|
||||||
while(wait && (TWI_MTX == twi_state)){
|
while(wait && (TWI_MTX == twi_state)){
|
||||||
|
@ -343,7 +380,16 @@ SIGNAL(TWI_vect)
|
||||||
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
|
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
|
||||||
twi_reply(1);
|
twi_reply(1);
|
||||||
}else{
|
}else{
|
||||||
|
if (twi_sendStop)
|
||||||
twi_stop();
|
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;
|
break;
|
||||||
case TW_MT_SLA_NACK: // address sent, nack received
|
case TW_MT_SLA_NACK: // address sent, nack received
|
||||||
|
@ -374,6 +420,17 @@ SIGNAL(TWI_vect)
|
||||||
case TW_MR_DATA_NACK: // data received, nack sent
|
case TW_MR_DATA_NACK: // data received, nack sent
|
||||||
// put final byte into buffer
|
// put final byte into buffer
|
||||||
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
|
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
|
case TW_MR_SLA_NACK: // address sent, nack received
|
||||||
twi_stop();
|
twi_stop();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
|
|
||||||
void twi_init(void);
|
void twi_init(void);
|
||||||
void twi_setAddress(uint8_t);
|
void twi_setAddress(uint8_t);
|
||||||
uint8_t twi_readFrom(uint8_t, uint8_t*, 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 twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
|
||||||
uint8_t twi_transmit(const uint8_t*, uint8_t);
|
uint8_t twi_transmit(const uint8_t*, uint8_t);
|
||||||
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
|
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
|
||||||
void twi_attachSlaveTxEvent( void (*)(void) );
|
void twi_attachSlaveTxEvent( void (*)(void) );
|
||||||
|
|
Loading…
Reference in New Issue