Skip to content

Commit ee6d674

Browse files
committed
twim: handle all errors
Previously only AddressNack was handled, and the transfer would hang if another error ocurred.
1 parent cd7796c commit ee6d674

File tree

1 file changed

+68
-78
lines changed

1 file changed

+68
-78
lines changed

nrf-hal-common/src/twim.rs

Lines changed: 68 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,41 @@ where
160160
Ok(())
161161
}
162162

163+
fn clear_errorsrc(&mut self) {
164+
self.0
165+
.errorsrc
166+
.write(|w| w.anack().bit(true).dnack().bit(true).overrun().bit(true));
167+
}
168+
169+
/// Get Error instance, if any occurred.
170+
fn read_errorsrc(&self) -> Result<(), Error> {
171+
let err = self.0.errorsrc.read();
172+
if err.anack().is_received() {
173+
return Err(Error::AddressNack);
174+
}
175+
if err.dnack().is_received() {
176+
return Err(Error::DataNack);
177+
}
178+
if err.overrun().is_received() {
179+
return Err(Error::DataNack);
180+
}
181+
Ok(())
182+
}
183+
184+
/// Wait for stop or error
185+
fn wait(&mut self) {
186+
loop {
187+
if self.0.events_stopped.read().bits() != 0 {
188+
self.0.events_stopped.reset();
189+
break;
190+
}
191+
if self.0.events_error.read().bits() != 0 {
192+
self.0.events_error.reset();
193+
self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
194+
}
195+
}
196+
}
197+
163198
/// Write to an I2C slave.
164199
///
165200
/// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -177,37 +212,26 @@ where
177212
// Set up the DMA write.
178213
unsafe { self.set_tx_buffer(buffer)? };
179214

180-
// Clear address NACK.
181-
self.0.errorsrc.write(|w| w.anack().bit(true));
215+
// Clear events
216+
self.0.events_stopped.reset();
217+
self.0.events_error.reset();
218+
self.0.events_lasttx.reset();
219+
self.clear_errorsrc();
182220

183221
// Start write operation.
222+
self.0.shorts.write(|w| w.lasttx_stop().enabled());
184223
self.0.tasks_starttx.write(|w|
185224
// `1` is a valid value to write to task registers.
186225
unsafe { w.bits(1) });
187226

188-
// Wait until write operation is about to end.
189-
while self.0.events_lasttx.read().bits() == 0
190-
&& self.0.errorsrc.read().anack().is_not_received()
191-
{}
192-
self.0.events_lasttx.write(|w| w); // reset event
193-
194-
// Stop write operation.
195-
self.0.tasks_stop.write(|w|
196-
// `1` is a valid value to write to task registers.
197-
unsafe { w.bits(1) });
198-
199-
// Wait until write operation has ended.
200-
while self.0.events_stopped.read().bits() == 0 {}
201-
self.0.events_stopped.write(|w| w); // reset event
227+
self.wait();
202228

203229
// Conservative compiler fence to prevent optimizations that do not
204230
// take in to account actions by DMA. The fence has been placed here,
205231
// after all possible DMA actions have completed.
206232
compiler_fence(SeqCst);
207233

208-
if self.0.errorsrc.read().anack().is_received() {
209-
return Err(Error::AddressNack);
210-
}
234+
self.read_errorsrc()?;
211235

212236
if self.0.txd.amount.read().bits() != buffer.len() as u32 {
213237
return Err(Error::Transmit);
@@ -233,37 +257,25 @@ where
233257
// Set up the DMA read.
234258
unsafe { self.set_rx_buffer(buffer)? };
235259

236-
// Clear address NACK.
237-
self.0.errorsrc.write(|w| w.anack().bit(true));
260+
// Clear events
261+
self.0.events_stopped.reset();
262+
self.0.events_error.reset();
263+
self.clear_errorsrc();
238264

239265
// Start read operation.
266+
self.0.shorts.write(|w| w.lastrx_stop().enabled());
240267
self.0.tasks_startrx.write(|w|
241268
// `1` is a valid value to write to task registers.
242269
unsafe { w.bits(1) });
243270

244-
// Wait until read operation is about to end.
245-
while self.0.events_lastrx.read().bits() == 0
246-
&& self.0.errorsrc.read().anack().is_not_received()
247-
{}
248-
self.0.events_lastrx.write(|w| w); // reset event
249-
250-
// Stop read operation.
251-
self.0.tasks_stop.write(|w|
252-
// `1` is a valid value to write to task registers.
253-
unsafe { w.bits(1) });
254-
255-
// Wait until read operation has ended.
256-
while self.0.events_stopped.read().bits() == 0 {}
257-
self.0.events_stopped.write(|w| w); // reset event
271+
self.wait();
258272

259273
// Conservative compiler fence to prevent optimizations that do not
260274
// take in to account actions by DMA. The fence has been placed here,
261275
// after all possible DMA actions have completed.
262276
compiler_fence(SeqCst);
263277

264-
if self.0.errorsrc.read().anack().is_received() {
265-
return Err(Error::AddressNack);
266-
}
278+
self.read_errorsrc()?;
267279

268280
if self.0.rxd.amount.read().bits() != buffer.len() as u32 {
269281
return Err(Error::Receive);
@@ -298,53 +310,29 @@ where
298310
self.set_rx_buffer(rd_buffer)?;
299311
}
300312

301-
// Clear address NACK.
302-
self.0.errorsrc.write(|w| w.anack().bit(true));
313+
// Clear events
314+
self.0.events_stopped.reset();
315+
self.0.events_error.reset();
316+
self.clear_errorsrc();
303317

304-
// Start write operation.
318+
// Start write+read operation.
319+
self.0.shorts.write(|w| {
320+
w.lasttx_startrx().enabled();
321+
w.lastrx_stop().enabled();
322+
w
323+
});
305324
// `1` is a valid value to write to task registers.
306325
self.0.tasks_starttx.write(|w| unsafe { w.bits(1) });
307326

308-
// Wait until write operation is about to end.
309-
while self.0.events_lasttx.read().bits() == 0
310-
&& self.0.errorsrc.read().anack().is_not_received()
311-
{}
312-
self.0.events_lasttx.write(|w| w); // reset event
313-
314-
// Stop operation if address is NACK.
315-
if self.0.errorsrc.read().anack().is_received() {
316-
// `1` is a valid value to write to task registers.
317-
self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
318-
// Wait until operation is stopped
319-
while self.0.events_stopped.read().bits() == 0 {}
320-
self.0.events_stopped.write(|w| w); // reset event
321-
return Err(Error::AddressNack);
322-
}
323-
324-
// Start read operation.
325-
// `1` is a valid value to write to task registers.
326-
self.0.tasks_startrx.write(|w| unsafe { w.bits(1) });
327-
328-
// Wait until read operation is about to end.
329-
while self.0.events_lastrx.read().bits() == 0 {}
330-
self.0.events_lastrx.write(|w| w); // reset event
331-
332-
// Stop read operation.
333-
// `1` is a valid value to write to task registers.
334-
self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
335-
336-
// Wait until total operation has ended.
337-
while self.0.events_stopped.read().bits() == 0 {}
338-
339-
self.0.events_lasttx.write(|w| w); // reset event
340-
self.0.events_lastrx.write(|w| w); // reset event
341-
self.0.events_stopped.write(|w| w); // reset event
327+
self.wait();
342328

343329
// Conservative compiler fence to prevent optimizations that do not
344330
// take in to account actions by DMA. The fence has been placed here,
345331
// after all possible DMA actions have completed.
346332
compiler_fence(SeqCst);
347333

334+
self.read_errorsrc()?;
335+
348336
let bad_write = self.0.txd.amount.read().bits() != wr_buffer.len() as u32;
349337
let bad_read = self.0.rxd.amount.read().bits() != rd_buffer.len() as u32;
350338

@@ -398,7 +386,7 @@ where
398386

399387
// Wait until write operation is about to end.
400388
while self.0.events_lasttx.read().bits() == 0 {}
401-
self.0.events_lasttx.write(|w| w); // reset event
389+
self.0.events_lasttx.reset();
402390

403391
// Check for bad writes.
404392
if self.0.txd.amount.read().bits() != wr_buffer.len() as u32 {
@@ -413,7 +401,7 @@ where
413401

414402
// Wait until read operation is about to end.
415403
while self.0.events_lastrx.read().bits() == 0 {}
416-
self.0.events_lastrx.write(|w| w); // reset event
404+
self.0.events_lastrx.reset();
417405

418406
// Stop read operation.
419407
self.0.tasks_stop.write(|w|
@@ -422,7 +410,7 @@ where
422410

423411
// Wait until total operation has ended.
424412
while self.0.events_stopped.read().bits() == 0 {}
425-
self.0.events_stopped.write(|w| w); // reset event
413+
self.0.events_stopped.reset();
426414

427415
// Conservative compiler fence to prevent optimizations that do not
428416
// take in to account actions by DMA. The fence has been placed here,
@@ -515,6 +503,8 @@ pub enum Error {
515503
Receive,
516504
DMABufferNotInDataMemory,
517505
AddressNack,
506+
DataNack,
507+
Overrun,
518508
}
519509

520510
/// Implemented by all TWIM instances

0 commit comments

Comments
 (0)