aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Goll <[email protected]>2024-03-27 00:33:04 +0100
committerSebastian Goll <[email protected]>2024-03-27 00:35:30 +0100
commit7e44db099ca6a475af9f22fd0ebb85845553a570 (patch)
tree438c9e7677e7f94d9d87574d61d21f04b744441c
parentb299266cd240d73bf6ec36d6a0710523ce5eb139 (diff)
Move FrameOptions and related function to module itself
-rw-r--r--embassy-stm32/src/i2c/mod.rs130
-rw-r--r--embassy-stm32/src/i2c/v1.rs129
2 files changed, 131 insertions, 128 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 6700f0f7d..85381047d 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -6,6 +6,7 @@
6mod _version; 6mod _version;
7 7
8use core::future::Future; 8use core::future::Future;
9use core::iter;
9use core::marker::PhantomData; 10use core::marker::PhantomData;
10 11
11use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 12use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
@@ -335,3 +336,132 @@ impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c:
335 self.transaction(address, operations).await 336 self.transaction(address, operations).await
336 } 337 }
337} 338}
339
340/// Frame type in I2C transaction.
341///
342/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
343/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
344/// ACK or NACK after the last byte received.
345///
346/// For write operations, the following options are identical because they differ only in the (N)ACK
347/// treatment relevant for read operations:
348///
349/// - `FirstFrame` and `FirstAndNextFrame`
350/// - `NextFrame` and `LastFrameNoStop`
351///
352/// Abbreviations used below:
353///
354/// - `ST` = start condition
355/// - `SR` = repeated start condition
356/// - `SP` = stop condition
357/// - `ACK`/`NACK` = last byte in read operation
358#[derive(Copy, Clone)]
359enum FrameOptions {
360 /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall.
361 FirstAndLastFrame,
362 /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
363 /// not the last frame overall.
364 FirstFrame,
365 /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
366 /// frame in a read operation.
367 FirstAndNextFrame,
368 /// `[ACK]` Middle frame in a read operation (neither first nor last).
369 NextFrame,
370 /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
371 LastFrame,
372 /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
373 LastFrameNoStop,
374}
375
376impl FrameOptions {
377 /// Sends start or repeated start condition before transfer.
378 fn send_start(self) -> bool {
379 match self {
380 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
381 Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
382 }
383 }
384
385 /// Sends stop condition after transfer.
386 fn send_stop(self) -> bool {
387 match self {
388 Self::FirstAndLastFrame | Self::LastFrame => true,
389 Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
390 }
391 }
392
393 /// Sends NACK after last byte received, indicating end of read operation.
394 fn send_nack(self) -> bool {
395 match self {
396 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
397 Self::FirstAndNextFrame | Self::NextFrame => false,
398 }
399 }
400}
401
402/// Iterates over operations in transaction.
403///
404/// Returns necessary frame options for each operation to uphold the [transaction contract] and have
405/// the right start/stop/(N)ACK conditions on the wire.
406///
407/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
408fn operation_frames<'a, 'b: 'a>(
409 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
410) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
411 use embedded_hal_1::i2c::Operation;
412
413 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an
414 // error in the middle of the transaction.
415 if operations.iter().any(|op| match op {
416 Operation::Read(read) => read.is_empty(),
417 Operation::Write(_) => false,
418 }) {
419 return Err(Error::Overrun);
420 }
421
422 let mut operations = operations.iter_mut().peekable();
423
424 let mut next_first_frame = true;
425
426 Ok(iter::from_fn(move || {
427 let Some(op) = operations.next() else {
428 return None;
429 };
430
431 // Is `op` first frame of its type?
432 let first_frame = next_first_frame;
433 let next_op = operations.peek();
434
435 // Get appropriate frame options as combination of the following properties:
436 //
437 // - For each first operation of its type, generate a (repeated) start condition.
438 // - For the last operation overall in the entire transaction, generate a stop condition.
439 // - For read operations, check the next operation: if it is also a read operation, we merge
440 // these and send ACK for all bytes in the current operation; send NACK only for the final
441 // read operation's last byte (before write or end of entire transaction) to indicate last
442 // byte read and release the bus for transmission of the bus master's next byte (or stop).
443 //
444 // We check the third property unconditionally, i.e. even for write opeartions. This is okay
445 // because the resulting frame options are identical for write operations.
446 let frame = match (first_frame, next_op) {
447 (true, None) => FrameOptions::FirstAndLastFrame,
448 (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame,
449 (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame,
450 //
451 (false, None) => FrameOptions::LastFrame,
452 (false, Some(Operation::Read(_))) => FrameOptions::NextFrame,
453 (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop,
454 };
455
456 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at
457 // the beginning of the loop because we hand out `op` as iterator value and cannot access it
458 // anymore in the next iteration.
459 next_first_frame = match (&op, next_op) {
460 (_, None) => false,
461 (Operation::Read(_), Some(Operation::Write(_))) | (Operation::Write(_), Some(Operation::Read(_))) => true,
462 (Operation::Read(_), Some(Operation::Read(_))) | (Operation::Write(_), Some(Operation::Write(_))) => false,
463 };
464
465 Some((op, frame))
466 }))
467}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 7c0bb31d6..be7f91a9a 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -5,7 +5,7 @@
5//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead. 5//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead.
6 6
7use core::future::poll_fn; 7use core::future::poll_fn;
8use core::{iter, task::Poll}; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
@@ -41,133 +41,6 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 41 });
42} 42}
43 43
44/// Frame type in I2C transaction.
45///
46/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
47/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
48/// ACK or NACK after the last byte received.
49///
50/// For write operations, the following options are identical because they differ only in the (N)ACK
51/// treatment relevant for read operations:
52///
53/// - `FirstFrame` and `FirstAndNextFrame`
54/// - `NextFrame` and `LastFrameNoStop`
55///
56/// Abbreviations used below:
57///
58/// - `ST` = start condition
59/// - `SR` = repeated start condition
60/// - `SP` = stop condition
61/// - `ACK`/`NACK` = last byte in read operation
62#[derive(Copy, Clone)]
63enum FrameOptions {
64 /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall.
65 FirstAndLastFrame,
66 /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
67 /// not the last frame overall.
68 FirstFrame,
69 /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
70 /// frame in a read operation.
71 FirstAndNextFrame,
72 /// `[ACK]` Middle frame in a read operation (neither first nor last).
73 NextFrame,
74 /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
75 LastFrame,
76 /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
77 LastFrameNoStop,
78}
79
80impl FrameOptions {
81 /// Sends start or repeated start condition before transfer.
82 fn send_start(self) -> bool {
83 match self {
84 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
85 Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
86 }
87 }
88
89 /// Sends stop condition after transfer.
90 fn send_stop(self) -> bool {
91 match self {
92 Self::FirstAndLastFrame | Self::LastFrame => true,
93 Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
94 }
95 }
96
97 /// Sends NACK after last byte received, indicating end of read operation.
98 fn send_nack(self) -> bool {
99 match self {
100 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
101 Self::FirstAndNextFrame | Self::NextFrame => false,
102 }
103 }
104}
105
106/// Iterates over operations in transaction.
107///
108/// Returns necessary frame options for each operation to uphold the [transaction contract] and have
109/// the right start/stop/(N)ACK conditions on the wire.
110///
111/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
112fn operation_frames<'a, 'b: 'a>(
113 operations: &'a mut [Operation<'b>],
114) -> Result<impl IntoIterator<Item = (&'a mut Operation<'b>, FrameOptions)>, Error> {
115 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an
116 // error in the middle of the transaction.
117 if operations.iter().any(|op| match op {
118 Operation::Read(read) => read.is_empty(),
119 Operation::Write(_) => false,
120 }) {
121 return Err(Error::Overrun);
122 }
123
124 let mut operations = operations.iter_mut().peekable();
125
126 let mut next_first_frame = true;
127
128 Ok(iter::from_fn(move || {
129 let Some(op) = operations.next() else {
130 return None;
131 };
132
133 // Is `op` first frame of its type?
134 let first_frame = next_first_frame;
135 let next_op = operations.peek();
136
137 // Get appropriate frame options as combination of the following properties:
138 //
139 // - For each first operation of its type, generate a (repeated) start condition.
140 // - For the last operation overall in the entire transaction, generate a stop condition.
141 // - For read operations, check the next operation: if it is also a read operation, we merge
142 // these and send ACK for all bytes in the current operation; send NACK only for the final
143 // read operation's last byte (before write or end of entire transaction) to indicate last
144 // byte read and release the bus for transmission of the bus master's next byte (or stop).
145 //
146 // We check the third property unconditionally, i.e. even for write opeartions. This is okay
147 // because the resulting frame options are identical for write operations.
148 let frame = match (first_frame, next_op) {
149 (true, None) => FrameOptions::FirstAndLastFrame,
150 (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame,
151 (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame,
152 //
153 (false, None) => FrameOptions::LastFrame,
154 (false, Some(Operation::Read(_))) => FrameOptions::NextFrame,
155 (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop,
156 };
157
158 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at
159 // the beginning of the loop because we hand out `op` as iterator value and cannot access it
160 // anymore in the next iteration.
161 next_first_frame = match (&op, next_op) {
162 (_, None) => false,
163 (Operation::Read(_), Some(Operation::Write(_))) | (Operation::Write(_), Some(Operation::Read(_))) => true,
164 (Operation::Read(_), Some(Operation::Read(_))) | (Operation::Write(_), Some(Operation::Write(_))) => false,
165 };
166
167 Some((op, frame))
168 }))
169}
170
171impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
172 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
173 T::regs().cr1().modify(|reg| { 46 T::regs().cr1().modify(|reg| {