Skip to content

Commit 6d0c292

Browse files
Merge #542
542: Transactional I2C r=burrbull a=SpeedCrash100 A transactional HAL API implementation for I2C. Closes #445. I have to rework i2c code to implement this: * `prepare_read`, `prepare_write` - methods to send start and address only * `write_wo_prepare`, `read_wo_prepare` - methods like old `read`, `write` but they do not send start and address. * `read_bytes`, `write_bytes` - this methods now only for send/receive. The do not send start, stop or address. * All public api's behaviour is untouched so there are no breaking changes for users. Note: I have to create duplicate methods `transaction_slice` and `transaction` because `Operation` doesn't implement Clone to send slice as iterator. Co-authored-by: SpeedCrash100 <[email protected]>
2 parents 99b34a0 + 1eacc02 commit 6d0c292

File tree

3 files changed

+164
-43
lines changed

3 files changed

+164
-43
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
4242
- example of using i2s in out with rtic and interrupt.
4343
- example of using USB CDC with interrupts.
4444
- Added non-blocking I2C based on DMA [#534]
45+
- Added Transactional I2C API [#542]
4546

4647
[#481]: https://github.com/stm32-rs/stm32f4xx-hal/pull/481
4748
[#489]: https://github.com/stm32-rs/stm32f4xx-hal/pull/489
@@ -59,6 +60,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
5960
[#536]: https://github.com/stm32-rs/stm32f4xx-hal/pull/536
6061
[#534]: https://github.com/stm32-rs/stm32f4xx-hal/pull/529
6162
[#540]: https://github.com/stm32-rs/stm32f4xx-hal/pull/540
63+
[#542]: https://github.com/stm32-rs/stm32f4xx-hal/pull/542
6264

6365
## [v0.13.2] - 2022-05-16
6466

src/i2c.rs

Lines changed: 156 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::gpio::{Const, OpenDrain, PinA, SetAlternate};
77
use crate::pac::RCC;
88

99
use crate::rcc::Clocks;
10+
use embedded_hal_one::i2c::blocking::Operation;
1011
use fugit::{HertzU32 as Hertz, RateExtU32};
1112

1213
mod hal_02;
@@ -313,7 +314,9 @@ impl<I2C: Instance, PINS> I2c<I2C, PINS> {
313314
Ok(sr1)
314315
}
315316

316-
fn write_bytes(&mut self, addr: u8, bytes: impl Iterator<Item = u8>) -> Result<(), Error> {
317+
/// Sends START and Address for writing
318+
#[inline(always)]
319+
fn prepare_write(&self, addr: u8) -> Result<(), Error> {
317320
// Send a START condition
318321
self.i2c.cr1.modify(|_, w| w.start().set_bit());
319322

@@ -351,6 +354,46 @@ impl<I2C: Instance, PINS> I2c<I2C, PINS> {
351354
// Clear condition by reading SR2
352355
self.i2c.sr2.read();
353356

357+
Ok(())
358+
}
359+
360+
/// Sends START and Address for reading
361+
fn prepare_read(&self, addr: u8) -> Result<(), Error> {
362+
// Send a START condition and set ACK bit
363+
self.i2c
364+
.cr1
365+
.modify(|_, w| w.start().set_bit().ack().set_bit());
366+
367+
// Wait until START condition was generated
368+
while self.i2c.sr1.read().sb().bit_is_clear() {}
369+
370+
// Also wait until signalled we're master and everything is waiting for us
371+
while {
372+
let sr2 = self.i2c.sr2.read();
373+
sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear()
374+
} {}
375+
376+
// Set up current address, we're trying to talk to
377+
self.i2c
378+
.dr
379+
.write(|w| unsafe { w.bits((u32::from(addr) << 1) + 1) });
380+
381+
// Wait until address was sent
382+
loop {
383+
self.check_and_clear_error_flags()
384+
.map_err(Error::nack_addr)?;
385+
if self.i2c.sr1.read().addr().bit_is_set() {
386+
break;
387+
}
388+
}
389+
390+
// Clear condition by reading SR2
391+
self.i2c.sr2.read();
392+
393+
Ok(())
394+
}
395+
396+
fn write_bytes(&mut self, bytes: impl Iterator<Item = u8>) -> Result<(), Error> {
354397
// Send bytes
355398
for c in bytes {
356399
self.send_byte(c)?;
@@ -400,43 +443,29 @@ impl<I2C: Instance, PINS> I2c<I2C, PINS> {
400443
Ok(value)
401444
}
402445

403-
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
404-
if let Some((last, buffer)) = buffer.split_last_mut() {
405-
// Send a START condition and set ACK bit
406-
self.i2c
407-
.cr1
408-
.modify(|_, w| w.start().set_bit().ack().set_bit());
409-
410-
// Wait until START condition was generated
411-
while self.i2c.sr1.read().sb().bit_is_clear() {}
446+
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
447+
// Receive bytes into buffer
448+
for c in buffer {
449+
*c = self.recv_byte()?;
450+
}
412451

413-
// Also wait until signalled we're master and everything is waiting for us
414-
while {
415-
let sr2 = self.i2c.sr2.read();
416-
sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear()
417-
} {}
452+
Ok(())
453+
}
418454

419-
// Set up current address, we're trying to talk to
420-
self.i2c
421-
.dr
422-
.write(|w| unsafe { w.bits((u32::from(addr) << 1) + 1) });
423-
424-
// Wait until address was sent
425-
loop {
426-
self.check_and_clear_error_flags()
427-
.map_err(Error::nack_addr)?;
428-
if self.i2c.sr1.read().addr().bit_is_set() {
429-
break;
430-
}
431-
}
455+
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
456+
if buffer.is_empty() {
457+
return Err(Error::Overrun);
458+
}
432459

433-
// Clear condition by reading SR2
434-
self.i2c.sr2.read();
460+
self.prepare_read(addr)?;
461+
self.read_wo_prepare(buffer)
462+
}
435463

436-
// Receive bytes into buffer
437-
for c in buffer {
438-
*c = self.recv_byte()?;
439-
}
464+
/// Reads like normal but does'n genereate start and don't send address
465+
fn read_wo_prepare(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
466+
if let Some((last, buffer)) = buffer.split_last_mut() {
467+
// Read all bytes but not last
468+
self.read_bytes(buffer)?;
440469

441470
// Prepare to send NACK then STOP after next byte
442471
self.i2c
@@ -457,7 +486,13 @@ impl<I2C: Instance, PINS> I2c<I2C, PINS> {
457486
}
458487

459488
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
460-
self.write_bytes(addr, bytes.iter().cloned())?;
489+
self.prepare_write(addr)?;
490+
self.write_wo_prepare(bytes)
491+
}
492+
493+
/// Writes like normal but does'n genereate start and don't send address
494+
fn write_wo_prepare(&mut self, bytes: &[u8]) -> Result<(), Error> {
495+
self.write_bytes(bytes.iter().cloned())?;
461496

462497
// Send a STOP condition
463498
self.i2c.cr1.modify(|_, w| w.stop().set_bit());
@@ -473,7 +508,8 @@ impl<I2C: Instance, PINS> I2c<I2C, PINS> {
473508
where
474509
B: IntoIterator<Item = u8>,
475510
{
476-
self.write_bytes(addr, bytes.into_iter())?;
511+
self.prepare_write(addr)?;
512+
self.write_bytes(bytes.into_iter())?;
477513

478514
// Send a STOP condition
479515
self.i2c.cr1.modify(|_, w| w.stop().set_bit());
@@ -486,15 +522,97 @@ impl<I2C: Instance, PINS> I2c<I2C, PINS> {
486522
}
487523

488524
pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
489-
self.write_bytes(addr, bytes.iter().cloned())?;
525+
self.prepare_write(addr)?;
526+
self.write_bytes(bytes.iter().cloned())?;
490527
self.read(addr, buffer)
491528
}
492529

493530
pub fn write_iter_read<B>(&mut self, addr: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Error>
494531
where
495532
B: IntoIterator<Item = u8>,
496533
{
497-
self.write_bytes(addr, bytes.into_iter())?;
534+
self.prepare_write(addr)?;
535+
self.write_bytes(bytes.into_iter())?;
498536
self.read(addr, buffer)
499537
}
538+
539+
pub fn transaction<'a>(
540+
&mut self,
541+
addr: u8,
542+
mut ops: impl Iterator<Item = Operation<'a>>,
543+
) -> Result<(), Error> {
544+
if let Some(mut prev_op) = ops.next() {
545+
// 1. Generate Start for operation
546+
match &prev_op {
547+
Operation::Read(_) => self.prepare_read(addr)?,
548+
Operation::Write(_) => self.prepare_write(addr)?,
549+
};
550+
551+
for op in ops {
552+
// 2. Execute previous operations.
553+
match &mut prev_op {
554+
Operation::Read(rb) => self.read_bytes(*rb)?,
555+
Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
556+
};
557+
// 3. If operation changes type we must generate new start
558+
match (&prev_op, &op) {
559+
(Operation::Read(_), Operation::Write(_)) => self.prepare_write(addr)?,
560+
(Operation::Write(_), Operation::Read(_)) => self.prepare_read(addr)?,
561+
_ => {} // No changes if operation have not changed
562+
}
563+
564+
prev_op = op;
565+
}
566+
567+
// 4. Now, prev_op is last command use methods variations that will generate stop
568+
match prev_op {
569+
Operation::Read(rb) => self.read_wo_prepare(rb)?,
570+
Operation::Write(wb) => self.write_wo_prepare(wb)?,
571+
};
572+
}
573+
574+
// Fallthrough is success
575+
Ok(())
576+
}
577+
578+
pub fn transaction_slice<'a>(
579+
&mut self,
580+
addr: u8,
581+
ops_slice: &mut [Operation<'a>],
582+
) -> Result<(), Error> {
583+
let mut ops = ops_slice.iter_mut();
584+
585+
if let Some(mut prev_op) = ops.next() {
586+
// 1. Generate Start for operation
587+
match &prev_op {
588+
Operation::Read(_) => self.prepare_read(addr)?,
589+
Operation::Write(_) => self.prepare_write(addr)?,
590+
};
591+
592+
for op in ops {
593+
// 2. Execute previous operations.
594+
match &mut prev_op {
595+
Operation::Read(rb) => self.read_bytes(*rb)?,
596+
Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?,
597+
};
598+
// 3. If operation changes type we must generate new start
599+
match (&prev_op, &op) {
600+
(Operation::Read(_), Operation::Write(_)) => self.prepare_write(addr)?,
601+
(Operation::Write(_), Operation::Read(_)) => self.prepare_read(addr)?,
602+
_ => {} // No changes if operation have not changed
603+
}
604+
605+
prev_op = op;
606+
}
607+
608+
// 4. Now, prev_op is last command use methods variations that will generate stop
609+
match prev_op {
610+
Operation::Read(rb) => self.read_wo_prepare(rb)?,
611+
Operation::Write(wb) => self.write_wo_prepare(wb)?,
612+
};
613+
}
614+
615+
// Fallthrough is success
616+
Ok(())
617+
}
500618
}

src/i2c/hal_1.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,18 @@ mod blocking {
5959

6060
fn transaction<'a>(
6161
&mut self,
62-
_addr: u8,
63-
_operations: &mut [Operation<'a>],
62+
addr: u8,
63+
operations: &mut [Operation<'a>],
6464
) -> Result<(), Self::Error> {
65-
todo!()
65+
self.transaction_slice(addr, operations)
6666
}
6767

68-
fn transaction_iter<'a, O>(&mut self, _addr: u8, _operations: O) -> Result<(), Self::Error>
68+
fn transaction_iter<'a, O>(&mut self, addr: u8, operations: O) -> Result<(), Self::Error>
6969
where
7070
O: IntoIterator<Item = Operation<'a>>,
7171
{
72-
todo!()
72+
let it = operations.into_iter();
73+
self.transaction(addr, it)
7374
}
7475
}
7576
}

0 commit comments

Comments
 (0)