Skip to content

Commit c7e840b

Browse files
committed
FMPI2c embedded-hal implementations
1 parent c39a962 commit c7e840b

File tree

6 files changed

+247
-167
lines changed

6 files changed

+247
-167
lines changed

CHANGELOG.md

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

src/fmpi2c.rs

+218-70
Original file line numberDiff line numberDiff line change
@@ -1,18 +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, RCC};
77
use crate::rcc::{BusClock, Clocks, Enable, Reset};
88
use fugit::{HertzU32 as Hertz, RateExtU32};
99
use micromath::F32Ext;
1010

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

20+
#[path = "i2c/hal_02.rs"]
1521
mod hal_02;
22+
#[path = "i2c/hal_1.rs"]
1623
mod hal_1;
1724

1825
type I2cSel = rcc::dckcfgr2::FMPI2C1SEL;
@@ -403,6 +410,83 @@ impl<I2C: Instance> I2c<I2C> {
403410
Ok(())
404411
}
405412

413+
/// Sends START and Address for writing
414+
#[inline(always)]
415+
fn prepare_write(&self, addr: Address, datalen: usize) -> Result<(), Error> {
416+
// Set up current slave address for writing and disable autoending
417+
self.i2c.cr2().modify(|_, w| {
418+
match addr {
419+
Address::Seven(addr) => {
420+
w.add10().clear_bit();
421+
w.sadd().set(u16::from(addr) << 1);
422+
}
423+
Address::Ten(addr) => {
424+
w.add10().set_bit();
425+
w.sadd().set(addr);
426+
}
427+
}
428+
w.nbytes().set(datalen as u8);
429+
w.rd_wrn().clear_bit();
430+
w.autoend().clear_bit()
431+
});
432+
433+
// Send a START condition
434+
self.i2c.cr2().modify(|_, w| w.start().set_bit());
435+
436+
// Wait until address was sent
437+
while {
438+
let isr = self.i2c.isr().read();
439+
self.check_and_clear_error_flags(&isr)
440+
.map_err(Error::nack_addr)?;
441+
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
442+
} {}
443+
444+
Ok(())
445+
}
446+
447+
/// Sends START and Address for reading
448+
fn prepare_read(
449+
&self,
450+
addr: Address,
451+
buflen: usize,
452+
first_transaction: bool,
453+
) -> Result<(), Error> {
454+
// Set up current address for reading
455+
self.i2c.cr2().modify(|_, w| {
456+
match addr {
457+
Address::Seven(addr) => {
458+
w.add10().clear_bit();
459+
w.sadd().set(u16::from(addr) << 1);
460+
}
461+
Address::Ten(addr) => {
462+
w.add10().set_bit();
463+
w.head10r().bit(!first_transaction);
464+
w.sadd().set(addr);
465+
}
466+
}
467+
w.nbytes().set(buflen as u8);
468+
w.rd_wrn().set_bit()
469+
});
470+
471+
// Send a START condition
472+
self.i2c.cr2().modify(|_, w| w.start().set_bit());
473+
474+
// Send the autoend after setting the start to get a restart
475+
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
476+
477+
Ok(())
478+
}
479+
480+
fn write_bytes(&mut self, bytes: impl Iterator<Item = u8>) -> Result<(), Error> {
481+
// Send bytes
482+
for c in bytes {
483+
self.send_byte(c)?;
484+
}
485+
486+
// Fallthrough is success
487+
Ok(())
488+
}
489+
406490
fn send_byte(&self, byte: u8) -> Result<(), Error> {
407491
// Wait until we're ready for sending
408492
while {
@@ -432,72 +516,38 @@ impl<I2C: Instance> I2c<I2C> {
432516
Ok(value)
433517
}
434518

435-
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
436-
// Set up current address for reading
437-
self.i2c.cr2().modify(|_, w| {
438-
w.sadd().set(u16::from(addr) << 1);
439-
w.nbytes().set(buffer.len() as u8);
440-
w.rd_wrn().set_bit()
441-
});
442-
443-
// Send a START condition
444-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
445-
446-
// Send the autoend after setting the start to get a restart
447-
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
448-
449-
// Now read in all bytes
450-
for c in buffer.iter_mut() {
519+
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
520+
// Receive bytes into buffer
521+
for c in buffer {
451522
*c = self.recv_byte()?;
452523
}
453524

454-
self.end_transaction()
525+
Ok(())
455526
}
456527

457-
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
458-
// Set up current slave address for writing and enable autoending
459-
self.i2c.cr2().modify(|_, w| {
460-
w.sadd().set(u16::from(addr) << 1);
461-
w.nbytes().set(bytes.len() as u8);
462-
w.rd_wrn().clear_bit();
463-
w.autoend().set_bit()
464-
});
465-
466-
// Send a START condition
467-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
468-
469-
// Send out all individual bytes
470-
for c in bytes {
471-
self.send_byte(*c)?;
472-
}
528+
pub fn read(&mut self, addr: impl Into<Address>, buffer: &mut [u8]) -> Result<(), Error> {
529+
self.prepare_read(addr.into(), buffer.len(), true)?;
530+
self.read_bytes(buffer)?;
473531

474532
self.end_transaction()
475533
}
476534

477-
pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
478-
// Set up current slave address for writing and disable autoending
479-
self.i2c.cr2().modify(|_, w| {
480-
w.sadd().set(u16::from(addr) << 1);
481-
w.nbytes().set(bytes.len() as u8);
482-
w.rd_wrn().clear_bit();
483-
w.autoend().clear_bit()
484-
});
535+
pub fn write(&mut self, addr: impl Into<Address>, bytes: &[u8]) -> Result<(), Error> {
536+
self.prepare_write(addr.into(), bytes.len())?;
537+
self.write_bytes(bytes.iter().cloned())?;
485538

486-
// Send a START condition
487-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
488-
489-
// Wait until the transmit buffer is empty and there hasn't been any error condition
490-
while {
491-
let isr = self.i2c.isr().read();
492-
self.check_and_clear_error_flags(&isr)
493-
.map_err(Error::nack_addr)?;
494-
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
495-
} {}
539+
self.end_transaction()
540+
}
496541

497-
// Send out all individual bytes
498-
for c in bytes {
499-
self.send_byte(*c)?;
500-
}
542+
pub fn write_read(
543+
&mut self,
544+
addr: impl Into<Address>,
545+
bytes: &[u8],
546+
buffer: &mut [u8],
547+
) -> Result<(), Error> {
548+
let addr = addr.into();
549+
self.prepare_write(addr, bytes.len())?;
550+
self.write_bytes(bytes.iter().cloned())?;
501551

502552
// Wait until data was sent
503553
while {
@@ -507,24 +557,122 @@ impl<I2C: Instance> I2c<I2C> {
507557
isr.tc().bit_is_clear()
508558
} {}
509559

510-
// Set up current address for reading
511-
self.i2c.cr2().modify(|_, w| {
512-
w.sadd().set(u16::from(addr) << 1);
513-
w.nbytes().set(buffer.len() as u8);
514-
w.rd_wrn().set_bit()
515-
});
560+
self.read(addr, buffer)
561+
}
516562

517-
// Send another START condition
518-
self.i2c.cr2().modify(|_, w| w.start().set_bit());
563+
pub fn transaction<'a>(
564+
&mut self,
565+
addr: impl Into<Address>,
566+
mut ops: impl Iterator<Item = Hal1Operation<'a>>,
567+
) -> Result<(), Error> {
568+
let addr = addr.into();
569+
if let Some(mut prev_op) = ops.next() {
570+
// 1. Generate Start for operation
571+
match &prev_op {
572+
Hal1Operation::Read(buf) => self.prepare_read(addr, buf.len(), true)?,
573+
Hal1Operation::Write(data) => self.prepare_write(addr, data.len())?,
574+
};
575+
576+
for op in ops {
577+
// 2. Execute previous operations.
578+
match &mut prev_op {
579+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
580+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
581+
};
582+
// 3. If operation changes type we must generate new start
583+
match (&prev_op, &op) {
584+
(Hal1Operation::Read(_), Hal1Operation::Write(data)) => {
585+
self.prepare_write(addr, data.len())?
586+
}
587+
(Hal1Operation::Write(_), Hal1Operation::Read(buf)) => {
588+
self.prepare_read(addr, buf.len(), false)?
589+
}
590+
_ => {} // No changes if operation have not changed
591+
}
519592

520-
// Send the autoend after setting the start to get a restart
521-
self.i2c.cr2().modify(|_, w| w.autoend().set_bit());
593+
prev_op = op;
594+
}
522595

523-
// Now read in all bytes
524-
for c in buffer.iter_mut() {
525-
*c = self.recv_byte()?;
596+
// 4. Now, prev_op is last command use methods variations that will generate stop
597+
match prev_op {
598+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
599+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
600+
};
601+
602+
self.end_transaction()?;
526603
}
527604

528-
self.end_transaction()
605+
// Fallthrough is success
606+
Ok(())
607+
}
608+
609+
pub fn transaction_slice(
610+
&mut self,
611+
addr: impl Into<Address>,
612+
ops_slice: &mut [Hal1Operation<'_>],
613+
) -> Result<(), Error> {
614+
let addr = addr.into();
615+
transaction_impl!(self, addr, ops_slice, Hal1Operation);
616+
// Fallthrough is success
617+
Ok(())
618+
}
619+
620+
fn transaction_slice_hal_02(
621+
&mut self,
622+
addr: impl Into<Address>,
623+
ops_slice: &mut [Hal02Operation<'_>],
624+
) -> Result<(), Error> {
625+
let addr = addr.into();
626+
transaction_impl!(self, addr, ops_slice, Hal02Operation);
627+
// Fallthrough is success
628+
Ok(())
529629
}
530630
}
631+
632+
macro_rules! transaction_impl {
633+
($self:ident, $addr:ident, $ops_slice:ident, $Operation:ident) => {
634+
let i2c = $self;
635+
let addr = $addr;
636+
let mut ops = $ops_slice.iter_mut();
637+
638+
if let Some(mut prev_op) = ops.next() {
639+
// 1. Generate Start for operation
640+
match &prev_op {
641+
$Operation::Read(buf) => i2c.prepare_read(addr, buf.len(), true)?,
642+
$Operation::Write(data) => i2c.prepare_write(addr, data.len())?,
643+
};
644+
645+
for op in ops {
646+
// 2. Execute previous operations.
647+
match &mut prev_op {
648+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
649+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
650+
};
651+
// 3. If operation changes type we must generate new start
652+
match (&prev_op, &op) {
653+
($Operation::Read(_), $Operation::Write(data)) => {
654+
i2c.prepare_write(addr, data.len())?
655+
}
656+
($Operation::Write(_), $Operation::Read(buf)) => {
657+
i2c.prepare_read(addr, buf.len(), false)?
658+
}
659+
_ => {} // No changes if operation have not changed
660+
}
661+
662+
prev_op = op;
663+
}
664+
665+
// 4. Now, prev_op is last command use methods variations that will generate stop
666+
match prev_op {
667+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
668+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
669+
};
670+
671+
i2c.end_transaction()?;
672+
}
673+
};
674+
}
675+
use transaction_impl;
676+
677+
// Note: implementation is from f0xx-hal
678+
// TODO: check error handling. See https://github.com/stm32-rs/stm32f0xx-hal/pull/95/files

src/fmpi2c/hal_02.rs

-28
This file was deleted.

0 commit comments

Comments
 (0)