Skip to content

Commit 28bfb2c

Browse files
committed
transaction
1 parent 4aacb00 commit 28bfb2c

File tree

6 files changed

+253
-177
lines changed

6 files changed

+253
-177
lines changed

src/fmpi2c.rs

Lines changed: 160 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
use core::ops::Deref;
22

33
use crate::gpio;
4-
use crate::i2c::{Error, NoAcknowledgeSource};
4+
use crate::i2c::{Address, Error, Hal02Operation, Hal1Operation, NoAcknowledgeSource};
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/hal_02.rs"]
1112
mod hal_02;
13+
#[path = "i2c/hal_1.rs"]
1214
mod hal_1;
1315

1416
type I2cSel = rcc::dckcfgr2::FMPI2C1SEL;
@@ -364,6 +366,7 @@ impl<I2C: Instance> I2c<I2C> {
364366
self.i2c.cr1().modify(|_, w| w.pe().set_bit());
365367
}
366368

369+
#[inline(always)]
367370
fn check_and_clear_error_flags(&self, isr: &i2c1::isr::R) -> Result<(), Error> {
368371
// If we received a NACK, then this is an error
369372
if isr.nackf().bit_is_set() {
@@ -376,6 +379,7 @@ impl<I2C: Instance> I2c<I2C> {
376379
Ok(())
377380
}
378381

382+
#[inline(always)]
379383
fn end_transaction(&self) -> Result<(), Error> {
380384
// Check and clear flags if they somehow ended up set
381385
self.check_and_clear_error_flags(&self.i2c.isr().read())
@@ -385,11 +389,20 @@ impl<I2C: Instance> I2c<I2C> {
385389

386390
/// Sends START and Address for writing
387391
#[inline(always)]
388-
fn prepare_write(&self, addr: u8, datalen: u8) -> Result<(), Error> {
392+
fn prepare_write(&self, addr: Address, datalen: usize) -> Result<(), Error> {
389393
// Set up current slave address for writing and disable autoending
390394
self.i2c.cr2().modify(|_, w| {
391-
w.sadd().set(u16::from(addr) << 1);
392-
w.nbytes().set(datalen);
395+
match addr {
396+
Address::Seven(addr) => {
397+
w.add10().clear_bit();
398+
w.sadd().set(u16::from(addr) << 1);
399+
}
400+
Address::Ten(addr) => {
401+
w.add10().set_bit();
402+
w.sadd().set(addr);
403+
}
404+
}
405+
w.nbytes().set(datalen as u8);
393406
w.rd_wrn().clear_bit();
394407
w.autoend().clear_bit()
395408
});
@@ -409,11 +422,26 @@ impl<I2C: Instance> I2c<I2C> {
409422
}
410423

411424
/// Sends START and Address for reading
412-
fn prepare_read(&self, addr: u8, buflen: u8) -> Result<(), Error> {
425+
fn prepare_read(
426+
&self,
427+
addr: Address,
428+
buflen: usize,
429+
first_transaction: bool,
430+
) -> Result<(), Error> {
413431
// Set up current address for reading
414432
self.i2c.cr2().modify(|_, w| {
415-
w.sadd().set(u16::from(addr) << 1);
416-
w.nbytes().set(buflen);
433+
match addr {
434+
Address::Seven(addr) => {
435+
w.add10().clear_bit();
436+
w.sadd().set(u16::from(addr) << 1);
437+
}
438+
Address::Ten(addr) => {
439+
w.add10().set_bit();
440+
w.head10r().bit(!first_transaction);
441+
w.sadd().set(addr);
442+
}
443+
}
444+
w.nbytes().set(buflen as u8);
417445
w.rd_wrn().set_bit()
418446
});
419447

@@ -474,22 +502,28 @@ impl<I2C: Instance> I2c<I2C> {
474502
Ok(())
475503
}
476504

477-
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
478-
self.prepare_read(addr, buffer.len() as u8)?;
505+
pub fn read(&mut self, addr: impl Into<Address>, buffer: &mut [u8]) -> Result<(), Error> {
506+
self.prepare_read(addr.into(), buffer.len(), true)?;
479507
self.read_bytes(buffer)?;
480508

481509
self.end_transaction()
482510
}
483511

484-
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
485-
self.prepare_write(addr, bytes.len() as u8)?;
512+
pub fn write(&mut self, addr: impl Into<Address>, bytes: &[u8]) -> Result<(), Error> {
513+
self.prepare_write(addr.into(), bytes.len())?;
486514
self.write_bytes(bytes.iter().cloned())?;
487515

488516
self.end_transaction()
489517
}
490518

491-
pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
492-
self.prepare_write(addr, bytes.len() as u8)?;
519+
pub fn write_read(
520+
&mut self,
521+
addr: impl Into<Address>,
522+
bytes: &[u8],
523+
buffer: &mut [u8],
524+
) -> Result<(), Error> {
525+
let addr = addr.into();
526+
self.prepare_write(addr, bytes.len())?;
493527
self.write_bytes(bytes.iter().cloned())?;
494528

495529
// Wait until data was sent
@@ -502,7 +536,120 @@ impl<I2C: Instance> I2c<I2C> {
502536

503537
self.read(addr, buffer)
504538
}
539+
540+
pub fn transaction<'a>(
541+
&mut self,
542+
addr: impl Into<Address>,
543+
mut ops: impl Iterator<Item = Hal1Operation<'a>>,
544+
) -> Result<(), Error> {
545+
let addr = addr.into();
546+
if let Some(mut prev_op) = ops.next() {
547+
// 1. Generate Start for operation
548+
match &prev_op {
549+
Hal1Operation::Read(buf) => self.prepare_read(addr, buf.len(), true)?,
550+
Hal1Operation::Write(data) => self.prepare_write(addr, data.len())?,
551+
};
552+
553+
for op in ops {
554+
// 2. Execute previous operations.
555+
match &mut prev_op {
556+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
557+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
558+
};
559+
// 3. If operation changes type we must generate new start
560+
match (&prev_op, &op) {
561+
(Hal1Operation::Read(_), Hal1Operation::Write(data)) => {
562+
self.prepare_write(addr, data.len())?
563+
}
564+
(Hal1Operation::Write(_), Hal1Operation::Read(buf)) => {
565+
self.prepare_read(addr, buf.len(), false)?
566+
}
567+
_ => {} // No changes if operation have not changed
568+
}
569+
570+
prev_op = op;
571+
}
572+
573+
// 4. Now, prev_op is last command use methods variations that will generate stop
574+
match prev_op {
575+
Hal1Operation::Read(rb) => self.read_bytes(rb)?,
576+
Hal1Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
577+
};
578+
579+
self.end_transaction()?;
580+
}
581+
582+
// Fallthrough is success
583+
Ok(())
584+
}
585+
586+
pub fn transaction_slice(
587+
&mut self,
588+
addr: impl Into<Address>,
589+
ops_slice: &mut [Hal1Operation<'_>],
590+
) -> Result<(), Error> {
591+
let addr = addr.into();
592+
transaction_impl!(self, addr, ops_slice, Hal1Operation);
593+
// Fallthrough is success
594+
Ok(())
595+
}
596+
597+
fn transaction_slice_hal_02(
598+
&mut self,
599+
addr: impl Into<Address>,
600+
ops_slice: &mut [Hal02Operation<'_>],
601+
) -> Result<(), Error> {
602+
let addr = addr.into();
603+
transaction_impl!(self, addr, ops_slice, Hal02Operation);
604+
// Fallthrough is success
605+
Ok(())
606+
}
607+
}
608+
609+
macro_rules! transaction_impl {
610+
($self:ident, $addr:ident, $ops_slice:ident, $Operation:ident) => {
611+
let i2c = $self;
612+
let addr = $addr;
613+
let mut ops = $ops_slice.iter_mut();
614+
615+
if let Some(mut prev_op) = ops.next() {
616+
// 1. Generate Start for operation
617+
match &prev_op {
618+
$Operation::Read(buf) => i2c.prepare_read(addr, buf.len(), true)?,
619+
$Operation::Write(data) => i2c.prepare_write(addr, data.len())?,
620+
};
621+
622+
for op in ops {
623+
// 2. Execute previous operations.
624+
match &mut prev_op {
625+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
626+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
627+
};
628+
// 3. If operation changes type we must generate new start
629+
match (&prev_op, &op) {
630+
($Operation::Read(_), $Operation::Write(data)) => {
631+
i2c.prepare_write(addr, data.len())?
632+
}
633+
($Operation::Write(_), $Operation::Read(buf)) => {
634+
i2c.prepare_read(addr, buf.len(), false)?
635+
}
636+
_ => {} // No changes if operation have not changed
637+
}
638+
639+
prev_op = op;
640+
}
641+
642+
// 4. Now, prev_op is last command use methods variations that will generate stop
643+
match prev_op {
644+
$Operation::Read(rb) => i2c.read_bytes(rb)?,
645+
$Operation::Write(wb) => i2c.write_bytes(wb.iter().cloned())?,
646+
};
647+
648+
i2c.end_transaction()?;
649+
}
650+
};
505651
}
652+
use transaction_impl;
506653

507654
// Note: implementation is from f0xx-hal
508655
// TODO: check error handling. See https://github.com/stm32-rs/stm32f0xx-hal/pull/95/files

src/fmpi2c/hal_02.rs

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

src/fmpi2c/hal_1.rs

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

0 commit comments

Comments
 (0)