aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/i2c/mod.rs6
-rw-r--r--embassy-stm32/src/i2c/v1.rs265
-rw-r--r--embassy-stm32/src/i2c/v2.rs12
3 files changed, 225 insertions, 58 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 cbbc201de..f1ed7ca40 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;
@@ -41,6 +42,68 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 42 });
42} 43}
43 44
45/// Frame type in I2C transaction.
46///
47/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
48/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
49/// ACK or NACK after the last byte received.
50///
51/// For write operations, the following options are identical because they differ only in the (N)ACK
52/// treatment relevant for read operations:
53///
54/// - `FirstFrame` and `FirstAndNextFrame`
55/// - `NextFrame` and `LastFrameNoStop`
56///
57/// Abbreviations used below:
58///
59/// - `ST` = start condition
60/// - `SR` = repeated start condition
61/// - `SP` = stop condition
62#[derive(Copy, Clone)]
63enum FrameOptions {
64 /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this
65 /// transaction.
66 FirstAndLastFrame,
67 /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
68 /// not the last frame overall.
69 FirstFrame,
70 /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
71 /// frame in a read operation.
72 FirstAndNextFrame,
73 /// `[ACK]` Middle frame in a read operation (neither first nor last).
74 NextFrame,
75 /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
76 LastFrame,
77 /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
78 LastFrameNoStop,
79}
80
81impl FrameOptions {
82 /// Sends start or repeated start condition before transfer.
83 fn send_start(self) -> bool {
84 match self {
85 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
86 Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
87 }
88 }
89
90 /// Sends stop condition after transfer.
91 fn send_stop(self) -> bool {
92 match self {
93 Self::FirstAndLastFrame | Self::LastFrame => true,
94 Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
95 }
96 }
97
98 /// Sends NACK after last byte received, indicating end of read operation.
99 fn send_nack(self) -> bool {
100 match self {
101 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
102 Self::FirstAndNextFrame | Self::NextFrame => false,
103 }
104 }
105}
106
44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 107impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 108 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
46 T::regs().cr1().modify(|reg| { 109 T::regs().cr1().modify(|reg| {
@@ -124,46 +187,57 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
124 Ok(sr1) 187 Ok(sr1)
125 } 188 }
126 189
127 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { 190 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> {
128 // Send a START condition 191 if frame.send_start() {
192 // Send a START condition
129 193
130 T::regs().cr1().modify(|reg| { 194 T::regs().cr1().modify(|reg| {
131 reg.set_start(true); 195 reg.set_start(true);
132 }); 196 });
133 197
134 // Wait until START condition was generated 198 // Wait until START condition was generated
135 while !Self::check_and_clear_error_flags()?.start() { 199 while !Self::check_and_clear_error_flags()?.start() {
136 timeout.check()?; 200 timeout.check()?;
137 } 201 }
138 202
139 // Also wait until signalled we're master and everything is waiting for us 203 // Also wait until signalled we're master and everything is waiting for us
140 while { 204 while {
141 Self::check_and_clear_error_flags()?; 205 Self::check_and_clear_error_flags()?;
142 206
143 let sr2 = T::regs().sr2().read(); 207 let sr2 = T::regs().sr2().read();
144 !sr2.msl() && !sr2.busy() 208 !sr2.msl() && !sr2.busy()
145 } { 209 } {
146 timeout.check()?; 210 timeout.check()?;
147 } 211 }
148 212
149 // Set up current address, we're trying to talk to 213 // Set up current address, we're trying to talk to
150 T::regs().dr().write(|reg| reg.set_dr(addr << 1)); 214 T::regs().dr().write(|reg| reg.set_dr(addr << 1));
151 215
152 // Wait until address was sent 216 // Wait until address was sent
153 // Wait for the address to be acknowledged 217 // Wait for the address to be acknowledged
154 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 218 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
155 while !Self::check_and_clear_error_flags()?.addr() { 219 while !Self::check_and_clear_error_flags()?.addr() {
156 timeout.check()?; 220 timeout.check()?;
157 } 221 }
158 222
159 // Clear condition by reading SR2 223 // Clear condition by reading SR2
160 let _ = T::regs().sr2().read(); 224 let _ = T::regs().sr2().read();
225 }
161 226
162 // Send bytes 227 // Send bytes
163 for c in bytes { 228 for c in bytes {
164 self.send_byte(*c, timeout)?; 229 self.send_byte(*c, timeout)?;
165 } 230 }
166 231
232 if frame.send_stop() {
233 // Send a STOP condition
234 T::regs().cr1().modify(|reg| reg.set_stop(true));
235 // Wait for STOP condition to transmit.
236 while T::regs().cr1().read().stop() {
237 timeout.check()?;
238 }
239 }
240
167 // Fallthrough is success 241 // Fallthrough is success
168 Ok(()) 242 Ok(())
169 } 243 }
@@ -205,8 +279,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
205 Ok(value) 279 Ok(value)
206 } 280 }
207 281
208 fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { 282 fn blocking_read_timeout(
209 if let Some((last, buffer)) = buffer.split_last_mut() { 283 &mut self,
284 addr: u8,
285 buffer: &mut [u8],
286 timeout: Timeout,
287 frame: FrameOptions,
288 ) -> Result<(), Error> {
289 let Some((last, buffer)) = buffer.split_last_mut() else {
290 return Err(Error::Overrun);
291 };
292
293 if frame.send_start() {
210 // Send a START condition and set ACK bit 294 // Send a START condition and set ACK bit
211 T::regs().cr1().modify(|reg| { 295 T::regs().cr1().modify(|reg| {
212 reg.set_start(true); 296 reg.set_start(true);
@@ -237,49 +321,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
237 321
238 // Clear condition by reading SR2 322 // Clear condition by reading SR2
239 let _ = T::regs().sr2().read(); 323 let _ = T::regs().sr2().read();
324 }
240 325
241 // Receive bytes into buffer 326 // Receive bytes into buffer
242 for c in buffer { 327 for c in buffer {
243 *c = self.recv_byte(timeout)?; 328 *c = self.recv_byte(timeout)?;
244 } 329 }
245 330
246 // Prepare to send NACK then STOP after next byte 331 // Prepare to send NACK then STOP after next byte
247 T::regs().cr1().modify(|reg| { 332 T::regs().cr1().modify(|reg| {
333 if frame.send_nack() {
248 reg.set_ack(false); 334 reg.set_ack(false);
335 }
336 if frame.send_stop() {
249 reg.set_stop(true); 337 reg.set_stop(true);
250 }); 338 }
339 });
251 340
252 // Receive last byte 341 // Receive last byte
253 *last = self.recv_byte(timeout)?; 342 *last = self.recv_byte(timeout)?;
254 343
344 if frame.send_stop() {
255 // Wait for the STOP to be sent. 345 // Wait for the STOP to be sent.
256 while T::regs().cr1().read().stop() { 346 while T::regs().cr1().read().stop() {
257 timeout.check()?; 347 timeout.check()?;
258 } 348 }
259
260 // Fallthrough is success
261 Ok(())
262 } else {
263 Err(Error::Overrun)
264 } 349 }
350
351 // Fallthrough is success
352 Ok(())
265 } 353 }
266 354
267 /// Blocking read. 355 /// Blocking read.
268 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 356 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
269 self.blocking_read_timeout(addr, read, self.timeout()) 357 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame)
270 } 358 }
271 359
272 /// Blocking write. 360 /// Blocking write.
273 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 361 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
274 let timeout = self.timeout(); 362 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?;
275
276 self.write_bytes(addr, write, timeout)?;
277 // Send a STOP condition
278 T::regs().cr1().modify(|reg| reg.set_stop(true));
279 // Wait for STOP condition to transmit.
280 while T::regs().cr1().read().stop() {
281 timeout.check()?;
282 }
283 363
284 // Fallthrough is success 364 // Fallthrough is success
285 Ok(()) 365 Ok(())
@@ -287,10 +367,85 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
287 367
288 /// Blocking write, restart, read. 368 /// Blocking write, restart, read.
289 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 369 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
370 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
371 // stop condition below.
372 if read.is_empty() {
373 return Err(Error::Overrun);
374 }
375
290 let timeout = self.timeout(); 376 let timeout = self.timeout();
291 377
292 self.write_bytes(addr, write, timeout)?; 378 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?;
293 self.blocking_read_timeout(addr, read, timeout)?; 379 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?;
380
381 Ok(())
382 }
383
384 /// Blocking transaction with operations.
385 ///
386 /// Consecutive operations of same type are merged. See [transaction contract] for details.
387 ///
388 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
389 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
390 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
391 // stop condition below.
392 if operations.iter().any(|op| match op {
393 Operation::Read(read) => read.is_empty(),
394 Operation::Write(_) => false,
395 }) {
396 return Err(Error::Overrun);
397 }
398
399 let timeout = self.timeout();
400
401 let mut operations = operations.iter_mut();
402
403 let mut prev_op: Option<&mut Operation<'_>> = None;
404 let mut next_op = operations.next();
405
406 while let Some(op) = next_op {
407 next_op = operations.next();
408
409 // Check if this is the first frame of this type. This is the case for the first overall
410 // frame in the transaction and whenever the type of operation changes.
411 let first_frame =
412 match (prev_op.as_ref(), &op) {
413 (None, _) => true,
414 (Some(Operation::Read(_)), Operation::Write(_))
415 | (Some(Operation::Write(_)), Operation::Read(_)) => true,
416 (Some(Operation::Read(_)), Operation::Read(_))
417 | (Some(Operation::Write(_)), Operation::Write(_)) => false,
418 };
419
420 let frame = match (first_frame, next_op.as_ref()) {
421 // If this is the first frame of this type, we generate a (repeated) start condition
422 // but have to consider the next operation: if it is the last, we generate the final
423 // stop condition. Otherwise, we branch on the operation: with read operations, only
424 // the last byte overall (before a write operation or the end of the transaction) is
425 // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte.
426 (true, None) => FrameOptions::FirstAndLastFrame,
427 // Make sure to keep sending ACK for last byte in read operation when it is followed
428 // by another consecutive read operation. If the current operation is write, this is
429 // identical to `FirstFrame`.
430 (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame,
431 // Otherwise, send NACK for last byte (in read operation). (For write, this does not
432 // matter and could also be `FirstAndNextFrame`.)
433 (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame,
434
435 // If this is not the first frame of its type, we do not generate a (repeated) start
436 // condition. Otherwise, we branch the same way as above.
437 (false, None) => FrameOptions::LastFrame,
438 (false, Some(Operation::Read(_))) => FrameOptions::NextFrame,
439 (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop,
440 };
441
442 match op {
443 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?,
444 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?,
445 }
446
447 prev_op = Some(op);
448 }
294 449
295 Ok(()) 450 Ok(())
296 } 451 }
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index bd3abaac1..1ac2740df 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -4,6 +4,7 @@ use core::task::Poll;
4 4
5use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7use embedded_hal_1::i2c::Operation;
7 8
8use super::*; 9use super::*;
9use crate::dma::Transfer; 10use crate::dma::Transfer;
@@ -579,6 +580,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
579 // Automatic Stop 580 // Automatic Stop
580 } 581 }
581 582
583 /// Blocking transaction with operations.
584 ///
585 /// Consecutive operations of same type are merged. See [transaction contract] for details.
586 ///
587 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
588 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
589 let _ = addr;
590 let _ = operations;
591 todo!()
592 }
593
582 /// Blocking write multiple buffers. 594 /// Blocking write multiple buffers.
583 /// 595 ///
584 /// The buffers are concatenated in a single write transaction. 596 /// The buffers are concatenated in a single write transaction.