aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/i2c/mod.rs6
-rw-r--r--embassy-stm32/src/i2c/v1.rs61
2 files changed, 64 insertions, 3 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 2416005b5..2c606c3c9 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -311,10 +311,10 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
311 311
312 fn transaction( 312 fn transaction(
313 &mut self, 313 &mut self,
314 _address: u8, 314 address: u8,
315 _operations: &mut [embedded_hal_1::i2c::Operation<'_>], 315 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
316 ) -> Result<(), Self::Error> { 316 ) -> Result<(), Self::Error> {
317 todo!(); 317 self.blocking_transaction(address, operations)
318 } 318 }
319} 319}
320 320
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 0843f45cf..678568706 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -10,6 +10,7 @@ use core::task::Poll;
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
12use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation;
13 14
14use super::*; 15use super::*;
15use crate::dma::Transfer; 16use crate::dma::Transfer;
@@ -374,6 +375,66 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
374 Ok(()) 375 Ok(())
375 } 376 }
376 377
378 /// Blocking transaction with operations.
379 ///
380 /// Consecutive operations of same type are merged. See [transaction contract] for details.
381 ///
382 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
383 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
384 let timeout = self.timeout();
385
386 let mut operations = operations.iter_mut();
387
388 let mut prev_op: Option<&mut Operation<'_>> = None;
389 let mut next_op = operations.next();
390
391 while let Some(mut op) = next_op {
392 next_op = operations.next();
393
394 // Check if this is the first frame of this type. This is the case for the first overall
395 // frame in the transaction and whenever the type of operation changes.
396 let first_frame =
397 match (prev_op.as_ref(), &op) {
398 (None, _) => true,
399 (Some(Operation::Read(_)), Operation::Write(_))
400 | (Some(Operation::Write(_)), Operation::Read(_)) => true,
401 (Some(Operation::Read(_)), Operation::Read(_))
402 | (Some(Operation::Write(_)), Operation::Write(_)) => false,
403 };
404
405 let frame = match (first_frame, next_op.as_ref()) {
406 // If this is the first frame of this type, we generate a (repeated) start condition
407 // but have to consider the next operation: if it is the last, we generate the final
408 // stop condition. Otherwise, we branch on the operation: with read operations, only
409 // the last byte overall (before a write operation or the end of the transaction) is
410 // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte.
411 (true, None) => FrameOptions::FirstAndLastFrame,
412 // Make sure to keep sending ACK for last byte in read operation when it is followed
413 // by another consecutive read operation. If the current operation is write, this is
414 // identical to `FirstFrame`.
415 (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame,
416 // Otherwise, send NACK for last byte (in read operation). (For write, this does not
417 // matter and could also be `FirstAndNextFrame`.)
418 (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame,
419
420 // If this is not the first frame of its type, we do not generate a (repeated) start
421 // condition. Otherwise, we branch the same way as above.
422 (false, None) => FrameOptions::LastFrame,
423 (false, Some(Operation::Read(_))) => FrameOptions::NextFrame,
424 (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop,
425 };
426
427 match &mut op {
428 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?,
429 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?,
430 }
431
432 prev_op = Some(op);
433 }
434
435 Ok(())
436 }
437
377 // Async 438 // Async
378 439
379 #[inline] // pretty sure this should always be inlined 440 #[inline] // pretty sure this should always be inlined