15
15
You should have received a copy of the GNU Lesser General Public
16
16
License along with this library; if not, write to the Free Software
17
17
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
18
20
*/
19
21
20
22
#include <math.h>
37
39
#include "twi.h"
38
40
39
41
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
41
45
42
46
static void (* twi_onSlaveTransmit )(void );
43
47
static void (* twi_onSlaveReceive )(uint8_t * , int );
44
48
45
49
static uint8_t twi_masterBuffer [TWI_BUFFER_LENGTH ];
46
50
static volatile uint8_t twi_masterBufferIndex ;
47
- static uint8_t twi_masterBufferLength ;
51
+ static volatile uint8_t twi_masterBufferLength ;
48
52
49
53
static uint8_t twi_txBuffer [TWI_BUFFER_LENGTH ];
50
54
static volatile uint8_t twi_txBufferIndex ;
@@ -65,6 +69,8 @@ void twi_init(void)
65
69
{
66
70
// initialize state
67
71
twi_state = TWI_READY ;
72
+ twi_sendStop = true; // default value
73
+ twi_inRepStart = false;
68
74
69
75
// activate internal pullups for twi.
70
76
digitalWrite (SDA , 1 );
@@ -103,9 +109,10 @@ void twi_setAddress(uint8_t address)
103
109
* Input address: 7bit i2c device address
104
110
* data: pointer to byte array
105
111
* length: number of bytes to read into array
112
+ * sendStop: Boolean indicating whether to send a stop at the end
106
113
* Output number of bytes read
107
114
*/
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 )
109
116
{
110
117
uint8_t i ;
111
118
@@ -119,6 +126,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
119
126
continue ;
120
127
}
121
128
twi_state = TWI_MRX ;
129
+ twi_sendStop = sendStop ;
122
130
// reset error state (0xFF.. no error occured)
123
131
twi_error = 0xFF ;
124
132
@@ -135,8 +143,20 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
135
143
twi_slarw = TW_READ ;
136
144
twi_slarw |= address << 1 ;
137
145
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 );
140
160
141
161
// wait for read operation to complete
142
162
while (TWI_MRX == twi_state ){
@@ -162,13 +182,14 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
162
182
* data: pointer to byte array
163
183
* length: number of bytes in array
164
184
* wait: boolean indicating to wait for write or not
185
+ * sendStop: boolean indicating whether or not to send a stop at the end
165
186
* Output 0 .. success
166
187
* 1 .. length to long for buffer
167
188
* 2 .. address send, NACK received
168
189
* 3 .. data send, NACK received
169
190
* 4 .. other twi error (lost bus arbitration, bus error, ..)
170
191
*/
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 )
172
193
{
173
194
uint8_t i ;
174
195
@@ -182,6 +203,7 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
182
203
continue ;
183
204
}
184
205
twi_state = TWI_MTX ;
206
+ twi_sendStop = sendStop ;
185
207
// reset error state (0xFF.. no error occured)
186
208
twi_error = 0xFF ;
187
209
@@ -198,8 +220,23 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
198
220
twi_slarw = TW_WRITE ;
199
221
twi_slarw |= address << 1 ;
200
222
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
203
240
204
241
// wait for write operation to complete
205
242
while (wait && (TWI_MTX == twi_state )){
@@ -343,7 +380,16 @@ SIGNAL(TWI_vect)
343
380
TWDR = twi_masterBuffer [twi_masterBufferIndex ++ ];
344
381
twi_reply (1 );
345
382
}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
+ }
347
393
}
348
394
break ;
349
395
case TW_MT_SLA_NACK : // address sent, nack received
@@ -374,6 +420,17 @@ SIGNAL(TWI_vect)
374
420
case TW_MR_DATA_NACK : // data received, nack sent
375
421
// put final byte into buffer
376
422
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 ;
377
434
case TW_MR_SLA_NACK : // address sent, nack received
378
435
twi_stop ();
379
436
break ;
0 commit comments