Skip to content

Commit 2f29f89

Browse files
committed
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
1 parent 561cd70 commit 2f29f89

File tree

4 files changed

+111
-16
lines changed

4 files changed

+111
-16
lines changed

libraries/Wire/Wire.cpp

+38-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
You should have received a copy of the GNU Lesser General Public
1616
License along with this library; if not, write to the Free Software
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
Modified 2012 by Todd Krein ([email protected]) to implement repeated starts
1820
*/
1921

2022
extern "C" {
@@ -73,24 +75,34 @@ void TwoWire::begin(int address)
7375
begin((uint8_t)address);
7476
}
7577

76-
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
78+
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
7779
{
7880
// clamp to buffer length
7981
if(quantity > BUFFER_LENGTH){
8082
quantity = BUFFER_LENGTH;
8183
}
8284
// perform blocking read into buffer
83-
uint8_t read = twi_readFrom(address, rxBuffer, quantity);
85+
uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
8486
// set rx buffer iterator vars
8587
rxBufferIndex = 0;
8688
rxBufferLength = read;
8789

8890
return read;
8991
}
9092

93+
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
94+
{
95+
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
96+
}
97+
9198
uint8_t TwoWire::requestFrom(int address, int quantity)
9299
{
93-
return requestFrom((uint8_t)address, (uint8_t)quantity);
100+
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
101+
}
102+
103+
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
104+
{
105+
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
94106
}
95107

96108
void TwoWire::beginTransmission(uint8_t address)
@@ -109,10 +121,23 @@ void TwoWire::beginTransmission(int address)
109121
beginTransmission((uint8_t)address);
110122
}
111123

112-
uint8_t TwoWire::endTransmission(void)
124+
//
125+
// Originally, 'endTransmission' was an f(void) function.
126+
// It has been modified to take one parameter indicating
127+
// whether or not a STOP should be performed on the bus.
128+
// Calling endTransmission(false) allows a sketch to
129+
// perform a repeated start.
130+
//
131+
// WARNING: Nothing in the library keeps track of whether
132+
// the bus tenure has been properly ended with a STOP. It
133+
// is very possible to leave the bus in a hung state if
134+
// no call to endTransmission(true) is made. Some I2C
135+
// devices will behave oddly if they do not see a STOP.
136+
//
137+
uint8_t TwoWire::endTransmission(uint8_t sendStop)
113138
{
114139
// transmit buffer (blocking)
115-
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
140+
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
116141
// reset tx buffer iterator vars
117142
txBufferIndex = 0;
118143
txBufferLength = 0;
@@ -121,6 +146,14 @@ uint8_t TwoWire::endTransmission(void)
121146
return ret;
122147
}
123148

149+
// This provides backwards compatibility with the original
150+
// definition, and expected behaviour, of endTransmission
151+
//
152+
uint8_t TwoWire::endTransmission(void)
153+
{
154+
return endTransmission(true);
155+
}
156+
124157
// must be called in:
125158
// slave tx event callback
126159
// or after beginTransmission(address)

libraries/Wire/Wire.h

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
You should have received a copy of the GNU Lesser General Public
1616
License along with this library; if not, write to the Free Software
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
Modified 2012 by Todd Krein ([email protected]) to implement repeated starts
1820
*/
1921

2022
#ifndef TwoWire_h
@@ -50,8 +52,11 @@ class TwoWire : public Stream
5052
void beginTransmission(uint8_t);
5153
void beginTransmission(int);
5254
uint8_t endTransmission(void);
55+
uint8_t endTransmission(uint8_t);
5356
uint8_t requestFrom(uint8_t, uint8_t);
57+
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
5458
uint8_t requestFrom(int, int);
59+
uint8_t requestFrom(int, int, int);
5560
virtual size_t write(uint8_t);
5661
virtual size_t write(const uint8_t *, size_t);
5762
virtual int available(void);

libraries/Wire/utility/twi.c

+66-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
You should have received a copy of the GNU Lesser General Public
1616
License along with this library; if not, write to the Free Software
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
Modified 2012 by Todd Krein ([email protected]) to implement repeated starts
1820
*/
1921

2022
#include <math.h>
@@ -37,14 +39,16 @@
3739
#include "twi.h"
3840

3941
static volatile uint8_t twi_state;
40-
static uint8_t twi_slarw;
42+
static volatile uint8_t twi_slarw;
43+
static volatile uint8_t twi_sendStop; // should the transaction end with a stop
44+
static volatile uint8_t twi_inRepStart; // in the middle of a repeated start
4145

4246
static void (*twi_onSlaveTransmit)(void);
4347
static void (*twi_onSlaveReceive)(uint8_t*, int);
4448

4549
static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
4650
static volatile uint8_t twi_masterBufferIndex;
47-
static uint8_t twi_masterBufferLength;
51+
static volatile uint8_t twi_masterBufferLength;
4852

4953
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
5054
static volatile uint8_t twi_txBufferIndex;
@@ -65,6 +69,8 @@ void twi_init(void)
6569
{
6670
// initialize state
6771
twi_state = TWI_READY;
72+
twi_sendStop = true; // default value
73+
twi_inRepStart = false;
6874

6975
// activate internal pullups for twi.
7076
digitalWrite(SDA, 1);
@@ -103,9 +109,10 @@ void twi_setAddress(uint8_t address)
103109
* Input address: 7bit i2c device address
104110
* data: pointer to byte array
105111
* length: number of bytes to read into array
112+
* sendStop: Boolean indicating whether to send a stop at the end
106113
* Output number of bytes read
107114
*/
108-
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
115+
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
109116
{
110117
uint8_t i;
111118

@@ -119,6 +126,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
119126
continue;
120127
}
121128
twi_state = TWI_MRX;
129+
twi_sendStop = sendStop;
122130
// reset error state (0xFF.. no error occured)
123131
twi_error = 0xFF;
124132

@@ -135,8 +143,20 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
135143
twi_slarw = TW_READ;
136144
twi_slarw |= address << 1;
137145

138-
// send start condition
139-
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
146+
if (true == twi_inRepStart) {
147+
// if we're in the repeated start state, then we've already sent the start,
148+
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
149+
// We need to remove ourselves from the repeated start state before we enable interrupts,
150+
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
151+
// up. Also, don't enable the START interrupt. There may be one pending from the
152+
// repeated start that we sent outselves, and that would really confuse things.
153+
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
154+
TWDR = twi_slarw;
155+
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
156+
}
157+
else
158+
// send start condition
159+
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
140160

141161
// wait for read operation to complete
142162
while(TWI_MRX == twi_state){
@@ -162,13 +182,14 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
162182
* data: pointer to byte array
163183
* length: number of bytes in array
164184
* wait: boolean indicating to wait for write or not
185+
* sendStop: boolean indicating whether or not to send a stop at the end
165186
* Output 0 .. success
166187
* 1 .. length to long for buffer
167188
* 2 .. address send, NACK received
168189
* 3 .. data send, NACK received
169190
* 4 .. other twi error (lost bus arbitration, bus error, ..)
170191
*/
171-
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait)
192+
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
172193
{
173194
uint8_t i;
174195

@@ -182,6 +203,7 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
182203
continue;
183204
}
184205
twi_state = TWI_MTX;
206+
twi_sendStop = sendStop;
185207
// reset error state (0xFF.. no error occured)
186208
twi_error = 0xFF;
187209

@@ -198,8 +220,23 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
198220
twi_slarw = TW_WRITE;
199221
twi_slarw |= address << 1;
200222

201-
// send start condition
202-
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
223+
// if we're in a repeated start, then we've already sent the START
224+
// in the ISR. Don't do it again.
225+
//
226+
if (true == twi_inRepStart) {
227+
// if we're in the repeated start state, then we've already sent the start,
228+
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
229+
// We need to remove ourselves from the repeated start state before we enable interrupts,
230+
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
231+
// up. Also, don't enable the START interrupt. There may be one pending from the
232+
// repeated start that we sent outselves, and that would really confuse things.
233+
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
234+
TWDR = twi_slarw;
235+
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
236+
}
237+
else
238+
// send start condition
239+
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs
203240

204241
// wait for write operation to complete
205242
while(wait && (TWI_MTX == twi_state)){
@@ -343,7 +380,16 @@ SIGNAL(TWI_vect)
343380
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
344381
twi_reply(1);
345382
}else{
346-
twi_stop();
383+
if (twi_sendStop)
384+
twi_stop();
385+
else {
386+
twi_inRepStart = true; // we're gonna send the START
387+
// don't enable the interrupt. We'll generate the start, but we
388+
// avoid handling the interrupt until we're in the next transaction,
389+
// at the point where we would normally issue the start.
390+
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
391+
twi_state = TWI_READY;
392+
}
347393
}
348394
break;
349395
case TW_MT_SLA_NACK: // address sent, nack received
@@ -374,6 +420,17 @@ SIGNAL(TWI_vect)
374420
case TW_MR_DATA_NACK: // data received, nack sent
375421
// put final byte into buffer
376422
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
423+
if (twi_sendStop)
424+
twi_stop();
425+
else {
426+
twi_inRepStart = true; // we're gonna send the START
427+
// don't enable the interrupt. We'll generate the start, but we
428+
// avoid handling the interrupt until we're in the next transaction,
429+
// at the point where we would normally issue the start.
430+
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
431+
twi_state = TWI_READY;
432+
}
433+
break;
377434
case TW_MR_SLA_NACK: // address sent, nack received
378435
twi_stop();
379436
break;

libraries/Wire/utility/twi.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040

4141
void twi_init(void);
4242
void twi_setAddress(uint8_t);
43-
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t);
44-
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t);
43+
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
44+
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
4545
uint8_t twi_transmit(const uint8_t*, uint8_t);
4646
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
4747
void twi_attachSlaveTxEvent( void (*)(void) );

0 commit comments

Comments
 (0)