Skip to content

Commit bc723e1

Browse files
committed
More rubost error handling for I2C
Signed-off-by: Daniel Egger <daniel@eggers-club.de>
1 parent e3c8e6f commit bc723e1

File tree

2 files changed

+58
-52
lines changed

2 files changed

+58
-52
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- More robust error handling for I2C
13+
1014
## [v0.11.0] - 2019-01-04
1115

1216
### Added

src/i2c.rs

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ macro_rules! i2c {
122122
// NOTE(unsafe) This executes only during initialisation
123123
let rcc = unsafe { &(*crate::stm32::RCC::ptr()) };
124124

125-
/* Enable clock for I2C */
125+
// Enable clock for I2C
126126
rcc.$apbenr.modify(|_, w| w.$i2cXen().set_bit());
127127

128-
/* Reset I2C */
128+
// Reset I2C
129129
rcc.$apbrstr.modify(|_, w| w.$i2cXrst().set_bit());
130130
rcc.$apbrstr.modify(|_, w| w.$i2cXrst().clear_bit());
131131
I2c { i2c, pins }.i2c_init(speed)
@@ -163,7 +163,7 @@ where
163163
fn i2c_init(self: Self, speed: KiloHertz) -> Self {
164164
use core::cmp;
165165

166-
/* Make sure the I2C unit is disabled so we can configure it */
166+
// Make sure the I2C unit is disabled so we can configure it
167167
self.i2c.cr1.modify(|_, w| w.pe().clear_bit());
168168

169169
// Calculate settings for I2C speed modes
@@ -191,7 +191,7 @@ where
191191
scldel = 3;
192192
}
193193

194-
/* Enable I2C signal generator, and configure I2C for 400KHz full speed */
194+
// Enable I2C signal generator, and configure I2C for 400KHz full speed
195195
self.i2c.timingr.write(|w| {
196196
w.presc()
197197
.bits(presc)
@@ -205,7 +205,7 @@ where
205205
.bits(scll)
206206
});
207207

208-
/* Enable the I2C processing */
208+
// Enable the I2C processing
209209
self.i2c.cr1.modify(|_, w| w.pe().set_bit());
210210

211211
self
@@ -215,15 +215,9 @@ where
215215
(self.i2c, self.pins)
216216
}
217217

218-
fn send_byte(&self, byte: u8) -> Result<(), Error> {
219-
/* Wait until we're ready for sending */
220-
while self.i2c.isr.read().txis().bit_is_clear() {}
221-
222-
/* Push out a byte of data */
223-
self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });
224-
225-
/* If we received a NACK, then this is an error */
226-
if self.i2c.isr.read().nackf().bit_is_set() {
218+
fn check_and_clear_error_flags(&self, isr: &crate::stm32::i2c1::isr::R) -> Result<(), Error> {
219+
// If we received a NACK, then this is an error
220+
if isr.nackf().bit_is_set() {
227221
self.i2c
228222
.icr
229223
.write(|w| w.stopcf().set_bit().nackcf().set_bit());
@@ -233,8 +227,28 @@ where
233227
Ok(())
234228
}
235229

230+
fn send_byte(&self, byte: u8) -> Result<(), Error> {
231+
// Wait until we're ready for sending
232+
while {
233+
let isr = self.i2c.isr.read();
234+
self.check_and_clear_error_flags(&isr)?;
235+
isr.txis().bit_is_clear()
236+
} {}
237+
238+
// Push out a byte of data
239+
self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });
240+
241+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
242+
Ok(())
243+
}
244+
236245
fn recv_byte(&self) -> Result<u8, Error> {
237-
while self.i2c.isr.read().rxne().bit_is_clear() {}
246+
while {
247+
let isr = self.i2c.isr.read();
248+
self.check_and_clear_error_flags(&isr)?;
249+
isr.rxne().bit_is_clear()
250+
} {}
251+
238252
let value = self.i2c.rxdr.read().bits() as u8;
239253
Ok(value)
240254
}
@@ -248,8 +262,7 @@ where
248262
type Error = Error;
249263

250264
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
251-
/* Set up current address, we're trying a "read" command and not going to set anything
252-
* and make sure we end a non-NACKed read (i.e. if we found a device) properly */
265+
// Set up current slave address for writing and disable autoending
253266
self.i2c.cr2.modify(|_, w| {
254267
w.sadd()
255268
.bits(u16::from(addr) << 1)
@@ -261,37 +274,29 @@ where
261274
.clear_bit()
262275
});
263276

264-
/* Send a START condition */
277+
// Send a START condition
265278
self.i2c.cr2.modify(|_, w| w.start().set_bit());
266279

267-
/* Wait until the transmit buffer is empty and there hasn't been either a NACK or STOP
268-
* being received */
269-
let mut isr;
280+
// Wait until the transmit buffer is empty and there hasn't been any error condition
270281
while {
271-
isr = self.i2c.isr.read();
272-
isr.txis().bit_is_clear()
273-
&& isr.nackf().bit_is_clear()
274-
&& isr.stopf().bit_is_clear()
275-
&& isr.tc().bit_is_clear()
282+
let isr = self.i2c.isr.read();
283+
self.check_and_clear_error_flags(&isr)?;
284+
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
276285
} {}
277286

278-
/* If we received a NACK, then this is an error */
279-
if isr.nackf().bit_is_set() {
280-
self.i2c
281-
.icr
282-
.write(|w| w.stopcf().set_bit().nackcf().set_bit());
283-
return Err(Error::NACK);
284-
}
285-
287+
// Send out all individual bytes
286288
for c in bytes {
287289
self.send_byte(*c)?;
288290
}
289291

290-
/* Wait until data was sent */
291-
while self.i2c.isr.read().tc().bit_is_clear() {}
292+
// Wait until data was sent
293+
while {
294+
let isr = self.i2c.isr.read();
295+
self.check_and_clear_error_flags(&isr)?;
296+
isr.tc().bit_is_clear()
297+
} {}
292298

293-
/* Set up current address, we're trying a "read" command and not going to set anything
294-
* and make sure we end a non-NACKed read (i.e. if we found a device) properly */
299+
// Set up current address for reading
295300
self.i2c.cr2.modify(|_, w| {
296301
w.sadd()
297302
.bits(u16::from(addr) << 1)
@@ -301,21 +306,19 @@ where
301306
.set_bit()
302307
});
303308

304-
/* Send a START condition */
309+
// Send another START condition
305310
self.i2c.cr2.modify(|_, w| w.start().set_bit());
306311

307-
/* Send the autoend after setting the start to get a restart */
312+
// Send the autoend after setting the start to get a restart
308313
self.i2c.cr2.modify(|_, w| w.autoend().set_bit());
309314

310-
/* Read in all bytes */
315+
// Now read in all bytes
311316
for c in buffer.iter_mut() {
312317
*c = self.recv_byte()?;
313318
}
314319

315-
/* Clear flags if they somehow ended up set */
316-
self.i2c
317-
.icr
318-
.write(|w| w.stopcf().set_bit().nackcf().set_bit());
320+
// Check and clear flags if they somehow ended up set
321+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
319322

320323
Ok(())
321324
}
@@ -329,8 +332,7 @@ where
329332
type Error = Error;
330333

331334
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
332-
/* Set up current address, we're trying a "read" command and not going to set anything
333-
* and make sure we end a non-NACKed read (i.e. if we found a device) properly */
335+
// Set up current slave address for writing and enable autoending
334336
self.i2c.cr2.modify(|_, w| {
335337
w.sadd()
336338
.bits(u16::from(addr) << 1)
@@ -342,17 +344,17 @@ where
342344
.set_bit()
343345
});
344346

345-
/* Send a START condition */
347+
// Send a START condition
346348
self.i2c.cr2.modify(|_, w| w.start().set_bit());
347349

350+
// Send out all individual bytes
348351
for c in bytes {
349352
self.send_byte(*c)?;
350353
}
351354

352-
/* Fallthrough is success */
353-
self.i2c
354-
.icr
355-
.write(|w| w.stopcf().set_bit().nackcf().set_bit());
355+
// Check and clear flags if they somehow ended up set
356+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
357+
356358
Ok(())
357359
}
358360
}

0 commit comments

Comments
 (0)