Skip to content

Commit fa634c0

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

File tree

4 files changed

+248
-100
lines changed

4 files changed

+248
-100
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: 219 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
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+
11+
#[path = "i2c/common.rs"]
12+
mod common;
13+
pub use common::{Address, Error, NoAcknowledgeSource};
14+
use common::{Hal02Operation, Hal1Operation};
15+
1016
// Old names
1117
pub use I2c as FmpI2c;
1218
pub use Mode as FmpMode;
1319

20+
#[path = "i2c/hal_02.rs"]
1421
mod hal_02;
22+
#[path = "i2c/hal_1.rs"]
1523
mod hal_1;
1624

1725
pub trait Instance:
@@ -222,6 +230,83 @@ impl<I2C: Instance> I2c<I2C> {
222230
Ok(())
223231
}
224232

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

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() {
339+
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
340+
// Receive bytes into buffer
341+
for c in buffer {
270342
*c = self.recv_byte()?;
271343
}
272344

273-
self.end_transaction()
345+
Ok(())
274346
}
275347

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-
}
348+
pub fn read(&mut self, addr: impl Into<Address>, buffer: &mut [u8]) -> Result<(), Error> {
349+
self.prepare_read(addr.into(), buffer.len(), true)?;
350+
self.read_bytes(buffer)?;
292351

293352
self.end_transaction()
294353
}
295354

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-
});
355+
pub fn write(&mut self, addr: impl Into<Address>, bytes: &[u8]) -> Result<(), Error> {
356+
self.prepare_write(addr.into(), bytes.len())?;
357+
self.write_bytes(bytes.iter().cloned())?;
304358

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

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-
}
362+
pub fn write_read(
363+
&mut self,
364+
addr: impl Into<Address>,
365+
bytes: &[u8],
366+
buffer: &mut [u8],
367+
) -> Result<(), Error> {
368+
let addr = addr.into();
369+
self.prepare_write(addr, bytes.len())?;
370+
self.write_bytes(bytes.iter().cloned())?;
320371

321372
// Wait until data was sent
322373
while {
@@ -326,24 +377,122 @@ impl<I2C: Instance> I2c<I2C> {
326377
isr.tc().bit_is_clear()
327378
} {}
328379

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-
});
380+
self.read(addr, buffer)
381+
}
335382

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

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

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

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

src/i2c.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,3 +658,30 @@ macro_rules! transaction_impl {
658658
};
659659
}
660660
use transaction_impl;
661+
662+
impl<I2C: Instance> embedded_hal_02::blocking::i2c::WriteIter for I2c<I2C> {
663+
type Error = Error;
664+
665+
fn write<B>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error>
666+
where
667+
B: IntoIterator<Item = u8>,
668+
{
669+
self.write_iter(addr, bytes)
670+
}
671+
}
672+
673+
impl<I2C: Instance> embedded_hal_02::blocking::i2c::WriteIterRead for I2c<I2C> {
674+
type Error = Error;
675+
676+
fn write_iter_read<B>(
677+
&mut self,
678+
addr: u8,
679+
bytes: B,
680+
buffer: &mut [u8],
681+
) -> Result<(), Self::Error>
682+
where
683+
B: IntoIterator<Item = u8>,
684+
{
685+
self.write_iter_read(addr, bytes, buffer)
686+
}
687+
}

0 commit comments

Comments
 (0)