Skip to content

Commit 1d4f773

Browse files
committed
FMPI2c embedded-hal implementations
1 parent eca5943 commit 1d4f773

File tree

6 files changed

+247
-167
lines changed

6 files changed

+247
-167
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2323
- Use `stm32f4-staging` until `stm32f4` is released [#706]
2424
- use GPIO pac fields instead of raw write
2525
- RTIC2 monotonics fix: CC1 instead of CC3
26+
- Fefactor FMPI2c `embedded-hal` implementations
2627
- Allow different lengths of buffers in hal_1 SpiBus impl [#566]
2728
- Clean SPI write impls
2829
- move `ptr()` to `Ptr` trait [#773]

src/fmpi2c.rs

Lines changed: 218 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
use core::ops::Deref;
22

33
use crate::gpio;
4-
use crate::i2c::{Error, NoAcknowledgeSource};
4+
55
use crate::pac::fmpi2c1 as i2c1;
66
use crate::pac::{self, RCC};
77
use crate::rcc::{BusClock, Enable, Reset};
88
use fugit::{HertzU32 as Hertz, RateExtU32};
99

10+
#[path = "i2c/common.rs"]
11+
mod common;
12+
pub use common::{Address, Error, NoAcknowledgeSource};
13+
use common::{Hal02Operation, Hal1Operation};
14+
1015
// Old names
1116
pub use I2c as FmpI2c;
1217
pub use Mode as FmpMode;
1318

19+
#[path = "i2c/hal_02.rs"]
1420
mod hal_02;
21+
#[path = "i2c/hal_1.rs"]
1522
mod hal_1;
1623

1724
pub trait Instance:
@@ -222,6 +229,83 @@ impl<I2C: Instance> I2c<I2C> {
222229
Ok(())
223230
}
224231

232+
/// Sends START and Address for writing
233+
#[inline(always)]
234+
fn prepare_write(&self, addr: Address, datalen: usize) -> Result<(), Error> {
235+
// Set up current slave address for writing and disable autoending
236+
self.i2c.cr2().modify(|_, w| {
237+
match addr {
238+
Address::Seven(addr) => {
239+
w.add10().clear_bit();
240+
w.sadd().set(u16::from(addr) << 1);
241+
}
242+
Address::Ten(addr) => {
243+
w.add10().set_bit();
244+
w.sadd().set(addr);
245+
}
246+
}
247+
w.nbytes().set(datalen as u8);
248+
w.rd_wrn().clear_bit();
249+
w.autoend().clear_bit()
250+
});
251+
252+
// Send a START condition
253+
self.i2c.cr2().modify(|_, w| w.start().set_bit());
254+
255+
// Wait until address was sent
256+
while {
257+
let isr = self.i2c.isr().read();
258+
self.check_and_clear_error_flags(&isr)
259+
.map_err(Error::nack_addr)?;
260+
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
261+
} {}
262+
263+
Ok(())
264+
}
265+
266+
/// Sends START and Address for reading
267+
fn prepare_read(
268+
&self,
269+
addr: Address,
270+
buflen: usize,
271+
first_transaction: bool,
272+
) -> Result<(), Error> {
273+
// Set up current address for reading
274+
self.i2c.cr2().modify(|_, w| {
275+
match addr {
276+
Address::Seven(addr) => {
277+
w.add10().clear_bit();
278+
w.sadd().set(u16::from(addr) << 1);
279+
}
280+
Address::Ten(addr) => {
281+
w.add10().set_bit();
282+
w.head10r().bit(!first_transaction);
283+
w.sadd().set(addr);
284+
}
285+
}
286+
w.nbytes().set(buflen as u8);
287+
w.rd_wrn().set_bit()
288+
});
289+
290+
// Send a START condition
291+
self.i2c.cr2().modify(|_, w| w.start().set_bit());
292+
293+
// Send the autoend after setting the start to get a restart
294+
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
295+
296+
Ok(())
297+
}
298+
299+
fn write_bytes(&mut self, bytes: impl Iterator<Item = u8>) -> Result<(), Error> {
300+
// Send bytes
301+
for c in bytes {
302+
self.send_byte(c)?;
303+
}
304+
305+
// Fallthrough is success
306+
Ok(())
307+
}
308+
225309
fn send_byte(&self, byte: u8) -> Result<(), Error> {
226310
// Wait until we're ready for sending
227311
while {
@@ -251,72 +335,38 @@ impl<I2C: Instance> I2c<I2C> {
251335
Ok(value)
252336
}
253337

254-
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
255-
// Set up current address for reading
256-
self.i2c.cr2().modify(|_, w| {
257-
w.sadd().set(u16::from(addr) << 1);
258-
w.nbytes().set(buffer.len() as u8);
259-
w.rd_wrn().set_bit()
260-
});
261-
262-
// Send a START condition
263-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
264-
265-
// Send the autoend after setting the start to get a restart
266-
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
267-
268-
// Now read in all bytes
269-
for c in buffer.iter_mut() {
338+
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
339+
// Receive bytes into buffer
340+
for c in buffer {
270341
*c = self.recv_byte()?;
271342
}
272343

273-
self.end_transaction()
344+
Ok(())
274345
}
275346

276-
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
277-
// Set up current slave address for writing and enable autoending
278-
self.i2c.cr2().modify(|_, w| {
279-
w.sadd().set(u16::from(addr) << 1);
280-
w.nbytes().set(bytes.len() as u8);
281-
w.rd_wrn().clear_bit();
282-
w.autoend().set_bit()
283-
});
284-
285-
// Send a START condition
286-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
287-
288-
// Send out all individual bytes
289-
for c in bytes {
290-
self.send_byte(*c)?;
291-
}
347+
pub fn read(&mut self, addr: impl Into<Address>, buffer: &mut [u8]) -> Result<(), Error> {
348+
self.prepare_read(addr.into(), buffer.len(), true)?;
349+
self.read_bytes(buffer)?;
292350

293351
self.end_transaction()
294352
}
295353

296-
pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
297-
// Set up current slave address for writing and disable autoending
298-
self.i2c.cr2().modify(|_, w| {
299-
w.sadd().set(u16::from(addr) << 1);
300-
w.nbytes().set(bytes.len() as u8);
301-
w.rd_wrn().clear_bit();
302-
w.autoend().clear_bit()
303-
});
354+
pub fn write(&mut self, addr: impl Into<Address>, bytes: &[u8]) -> Result<(), Error> {
355+
self.prepare_write(addr.into(), bytes.len())?;
356+
self.write_bytes(bytes.iter().cloned())?;
304357

305-
// Send a START condition
306-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
358+
self.end_transaction()
359+
}
307360

308-
// Wait until the transmit buffer is empty and there hasn't been any error condition
309-
while {
310-
let isr = self.i2c.isr().read();
311-
self.check_and_clear_error_flags(&isr)
312-
.map_err(Error::nack_addr)?;
313-
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
314-
} {}
315-
316-
// Send out all individual bytes
317-
for c in bytes {
318-
self.send_byte(*c)?;
319-
}
361+
pub fn write_read(
362+
&mut self,
363+
addr: impl Into<Address>,
364+
bytes: &[u8],
365+
buffer: &mut [u8],
366+
) -> Result<(), Error> {
367+
let addr = addr.into();
368+
self.prepare_write(addr, bytes.len())?;
369+
self.write_bytes(bytes.iter().cloned())?;
320370

321371
// Wait until data was sent
322372
while {
@@ -326,24 +376,122 @@ impl<I2C: Instance> I2c<I2C> {
326376
isr.tc().bit_is_clear()
327377
} {}
328378

329-
// Set up current address for reading
330-
self.i2c.cr2().modify(|_, w| {
331-
w.sadd().set(u16::from(addr) << 1);
332-
w.nbytes().set(buffer.len() as u8);
333-
w.rd_wrn().set_bit()
334-
});
379+
self.read(addr, buffer)
380+
}
335381

336-
// Send another START condition
337-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
382+
pub fn transaction<'a>(
383+
&mut self,
384+
addr: impl Into<Address>,
385+
mut ops: impl Iterator<Item = Hal1Operation<'a>>,
386+
) -> Result<(), Error> {
387+
let addr = addr.into();
388+
if let Some(mut prev_op) = ops.next() {
389+
// 1. Generate Start for operation
390+
match &prev_op {
391+
Hal1Operation::Read(buf) => self.prepare_read(addr, buf.len(), true)?,
392+
Hal1Operation::Write(data) => self.prepare_write(addr, data.len())?,
393+
};
394+
395+
for op in ops {
396+
// 2. Execute previous operations.
397+
match &mut prev_op {
398+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
399+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
400+
};
401+
// 3. If operation changes type we must generate new start
402+
match (&prev_op, &op) {
403+
(Hal1Operation::Read(_), Hal1Operation::Write(data)) => {
404+
self.prepare_write(addr, data.len())?
405+
}
406+
(Hal1Operation::Write(_), Hal1Operation::Read(buf)) => {
407+
self.prepare_read(addr, buf.len(), false)?
408+
}
409+
_ => {} // No changes if operation have not changed
410+
}
411+
412+
prev_op = op;
413+
}
338414

339-
// Send the autoend after setting the start to get a restart
340-
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
415+
// 4. Now, prev_op is last command use methods variations that will generate stop
416+
match prev_op {
417+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
418+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
419+
};
341420

342-
// Now read in all bytes
343-
for c in buffer.iter_mut() {
344-
*c = self.recv_byte()?;
421+
self.end_transaction()?;
345422
}
346423

347-
self.end_transaction()
424+
// Fallthrough is success
425+
Ok(())
426+
}
427+
428+
pub fn transaction_slice(
429+
&mut self,
430+
addr: impl Into<Address>,
431+
ops_slice: &mut [Hal1Operation<'_>],
432+
) -> Result<(), Error> {
433+
let addr = addr.into();
434+
transaction_impl!(self, addr, ops_slice, Hal1Operation);
435+
// Fallthrough is success
436+
Ok(())
437+
}
438+
439+
fn transaction_slice_hal_02(
440+
&mut self,
441+
addr: impl Into<Address>,
442+
ops_slice: &mut [Hal02Operation<'_>],
443+
) -> Result<(), Error> {
444+
let addr = addr.into();
445+
transaction_impl!(self, addr, ops_slice, Hal02Operation);
446+
// Fallthrough is success
447+
Ok(())
348448
}
349449
}
450+
451+
macro_rules! transaction_impl {
452+
($self:ident, $addr:ident, $ops_slice:ident, $Operation:ident) => {
453+
let i2c = $self;
454+
let addr = $addr;
455+
let mut ops = $ops_slice.iter_mut();
456+
457+
if let Some(mut prev_op) = ops.next() {
458+
// 1. Generate Start for operation
459+
match &prev_op {
460+
$Operation::Read(buf) => i2c.prepare_read(addr, buf.len(), true)?,
461+
$Operation::Write(data) => i2c.prepare_write(addr, data.len())?,
462+
};
463+
464+
for op in ops {
465+
// 2. Execute previous operations.
466+
match &mut prev_op {
467+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
468+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
469+
};
470+
// 3. If operation changes type we must generate new start
471+
match (&prev_op, &op) {
472+
($Operation::Read(_), $Operation::Write(data)) => {
473+
i2c.prepare_write(addr, data.len())?
474+
}
475+
($Operation::Write(_), $Operation::Read(buf)) => {
476+
i2c.prepare_read(addr, buf.len(), false)?
477+
}
478+
_ => {} // No changes if operation have not changed
479+
}
480+
481+
prev_op = op;
482+
}
483+
484+
// 4. Now, prev_op is last command use methods variations that will generate stop
485+
match prev_op {
486+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
487+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
488+
};
489+
490+
i2c.end_transaction()?;
491+
}
492+
};
493+
}
494+
use transaction_impl;
495+
496+
// Note: implementation is from f0xx-hal
497+
// TODO: check error handling. See https://github.com/stm32-rs/stm32f0xx-hal/pull/95/files

src/fmpi2c/hal_02.rs

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)