diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-04-04 21:43:21 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-04 21:43:21 +0000 |
| commit | a0439479f70e0d50cc48d0e421a3034932a882b4 (patch) | |
| tree | 32efa09b6d22f6ac20e625f64c8057b16fb5058d | |
| parent | 921fa9af80b4f4c8e8c827f4104abceee795b630 (diff) | |
| parent | 6efac5562ad075f76121970a120e951ee8d2dd30 (diff) | |
Merge pull request #2742 from sgoll/i2c-async-transaction
stm32/i2c(v1): Implement asynchronous transactions
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 141 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 628 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 15 |
3 files changed, 414 insertions, 370 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index f1b11cc44..a46061d54 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | mod _version; | 6 | mod _version; |
| 7 | 7 | ||
| 8 | use core::future::Future; | 8 | use core::future::Future; |
| 9 | use core::iter; | ||
| 9 | use core::marker::PhantomData; | 10 | use core::marker::PhantomData; |
| 10 | 11 | ||
| 11 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 12 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| @@ -332,8 +333,142 @@ impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c: | |||
| 332 | address: u8, | 333 | address: u8, |
| 333 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], | 334 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], |
| 334 | ) -> Result<(), Self::Error> { | 335 | ) -> Result<(), Self::Error> { |
| 335 | let _ = address; | 336 | self.transaction(address, operations).await |
| 336 | let _ = operations; | ||
| 337 | todo!() | ||
| 338 | } | 337 | } |
| 339 | } | 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)] | ||
| 359 | #[allow(dead_code)] | ||
| 360 | enum FrameOptions { | ||
| 361 | /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall. | ||
| 362 | FirstAndLastFrame, | ||
| 363 | /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but | ||
| 364 | /// not the last frame overall. | ||
| 365 | FirstFrame, | ||
| 366 | /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last | ||
| 367 | /// frame in a read operation. | ||
| 368 | FirstAndNextFrame, | ||
| 369 | /// `[ACK]` Middle frame in a read operation (neither first nor last). | ||
| 370 | NextFrame, | ||
| 371 | /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame. | ||
| 372 | LastFrame, | ||
| 373 | /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction. | ||
| 374 | LastFrameNoStop, | ||
| 375 | } | ||
| 376 | |||
| 377 | #[allow(dead_code)] | ||
| 378 | impl FrameOptions { | ||
| 379 | /// Sends start or repeated start condition before transfer. | ||
| 380 | fn send_start(self) -> bool { | ||
| 381 | match self { | ||
| 382 | Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, | ||
| 383 | Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false, | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | /// Sends stop condition after transfer. | ||
| 388 | fn send_stop(self) -> bool { | ||
| 389 | match self { | ||
| 390 | Self::FirstAndLastFrame | Self::LastFrame => true, | ||
| 391 | Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false, | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | /// Sends NACK after last byte received, indicating end of read operation. | ||
| 396 | fn send_nack(self) -> bool { | ||
| 397 | match self { | ||
| 398 | Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, | ||
| 399 | Self::FirstAndNextFrame | Self::NextFrame => false, | ||
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /// Iterates over operations in transaction. | ||
| 405 | /// | ||
| 406 | /// Returns necessary frame options for each operation to uphold the [transaction contract] and have | ||
| 407 | /// the right start/stop/(N)ACK conditions on the wire. | ||
| 408 | /// | ||
| 409 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 410 | #[allow(dead_code)] | ||
| 411 | fn operation_frames<'a, 'b: 'a>( | ||
| 412 | operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], | ||
| 413 | ) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { | ||
| 414 | use embedded_hal_1::i2c::Operation::{Read, Write}; | ||
| 415 | |||
| 416 | // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an | ||
| 417 | // error in the middle of the transaction. | ||
| 418 | // | ||
| 419 | // In principle, we could allow empty read frames within consecutive read operations, as long as | ||
| 420 | // at least one byte remains in the final (merged) read operation, but that makes the logic more | ||
| 421 | // complicated and error-prone. | ||
| 422 | if operations.iter().any(|op| match op { | ||
| 423 | Read(read) => read.is_empty(), | ||
| 424 | Write(_) => false, | ||
| 425 | }) { | ||
| 426 | return Err(Error::Overrun); | ||
| 427 | } | ||
| 428 | |||
| 429 | let mut operations = operations.iter_mut().peekable(); | ||
| 430 | |||
| 431 | let mut next_first_frame = true; | ||
| 432 | |||
| 433 | Ok(iter::from_fn(move || { | ||
| 434 | let Some(op) = operations.next() else { | ||
| 435 | return None; | ||
| 436 | }; | ||
| 437 | |||
| 438 | // Is `op` first frame of its type? | ||
| 439 | let first_frame = next_first_frame; | ||
| 440 | let next_op = operations.peek(); | ||
| 441 | |||
| 442 | // Get appropriate frame options as combination of the following properties: | ||
| 443 | // | ||
| 444 | // - For each first operation of its type, generate a (repeated) start condition. | ||
| 445 | // - For the last operation overall in the entire transaction, generate a stop condition. | ||
| 446 | // - For read operations, check the next operation: if it is also a read operation, we merge | ||
| 447 | // these and send ACK for all bytes in the current operation; send NACK only for the final | ||
| 448 | // read operation's last byte (before write or end of entire transaction) to indicate last | ||
| 449 | // byte read and release the bus for transmission of the bus master's next byte (or stop). | ||
| 450 | // | ||
| 451 | // We check the third property unconditionally, i.e. even for write opeartions. This is okay | ||
| 452 | // because the resulting frame options are identical for write operations. | ||
| 453 | let frame = match (first_frame, next_op) { | ||
| 454 | (true, None) => FrameOptions::FirstAndLastFrame, | ||
| 455 | (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, | ||
| 456 | (true, Some(Write(_))) => FrameOptions::FirstFrame, | ||
| 457 | // | ||
| 458 | (false, None) => FrameOptions::LastFrame, | ||
| 459 | (false, Some(Read(_))) => FrameOptions::NextFrame, | ||
| 460 | (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, | ||
| 461 | }; | ||
| 462 | |||
| 463 | // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at | ||
| 464 | // the beginning of the loop because we hand out `op` as iterator value and cannot access it | ||
| 465 | // anymore in the next iteration. | ||
| 466 | next_first_frame = match (&op, next_op) { | ||
| 467 | (_, None) => false, | ||
| 468 | (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, | ||
| 469 | (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, | ||
| 470 | }; | ||
| 471 | |||
| 472 | Some((op, frame)) | ||
| 473 | })) | ||
| 474 | } | ||
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 9f29ed5e0..d45c48b24 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -41,68 +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 | #[derive(Copy, Clone)] | ||
| 62 | enum FrameOptions { | ||
| 63 | /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this | ||
| 64 | /// transaction. | ||
| 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 | |||
| 80 | impl 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 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 44 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 107 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { | 45 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 108 | T::regs().cr1().modify(|reg| { | 46 | T::regs().cr1().modify(|reg| { |
| @@ -199,17 +137,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 199 | timeout.check()?; | 137 | timeout.check()?; |
| 200 | } | 138 | } |
| 201 | 139 | ||
| 202 | // Also wait until signalled we're master and everything is waiting for us | 140 | // Check if we were the ones to generate START |
| 203 | while { | 141 | if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { |
| 204 | Self::check_and_clear_error_flags()?; | 142 | return Err(Error::Arbitration); |
| 205 | |||
| 206 | let sr2 = T::regs().sr2().read(); | ||
| 207 | !sr2.msl() && !sr2.busy() | ||
| 208 | } { | ||
| 209 | timeout.check()?; | ||
| 210 | } | 143 | } |
| 211 | 144 | ||
| 212 | // Set up current address, we're trying to talk to | 145 | // Set up current address we're trying to talk to |
| 213 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); | 146 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); |
| 214 | 147 | ||
| 215 | // Wait until address was sent | 148 | // Wait until address was sent |
| @@ -231,10 +164,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 231 | if frame.send_stop() { | 164 | if frame.send_stop() { |
| 232 | // Send a STOP condition | 165 | // Send a STOP condition |
| 233 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | 166 | T::regs().cr1().modify(|reg| reg.set_stop(true)); |
| 234 | // Wait for STOP condition to transmit. | ||
| 235 | while T::regs().cr1().read().stop() { | ||
| 236 | timeout.check()?; | ||
| 237 | } | ||
| 238 | } | 167 | } |
| 239 | 168 | ||
| 240 | // Fallthrough is success | 169 | // Fallthrough is success |
| @@ -301,15 +230,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 301 | timeout.check()?; | 230 | timeout.check()?; |
| 302 | } | 231 | } |
| 303 | 232 | ||
| 304 | // Also wait until signalled we're master and everything is waiting for us | 233 | // Check if we were the ones to generate START |
| 305 | while { | 234 | if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { |
| 306 | let sr2 = T::regs().sr2().read(); | 235 | return Err(Error::Arbitration); |
| 307 | !sr2.msl() && !sr2.busy() | ||
| 308 | } { | ||
| 309 | timeout.check()?; | ||
| 310 | } | 236 | } |
| 311 | 237 | ||
| 312 | // Set up current address, we're trying to talk to | 238 | // Set up current address we're trying to talk to |
| 313 | T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)); | 239 | T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)); |
| 314 | 240 | ||
| 315 | // Wait until address was sent | 241 | // Wait until address was sent |
| @@ -340,13 +266,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 340 | // Receive last byte | 266 | // Receive last byte |
| 341 | *last = self.recv_byte(timeout)?; | 267 | *last = self.recv_byte(timeout)?; |
| 342 | 268 | ||
| 343 | if frame.send_stop() { | ||
| 344 | // Wait for the STOP to be sent. | ||
| 345 | while T::regs().cr1().read().stop() { | ||
| 346 | timeout.check()?; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | // Fallthrough is success | 269 | // Fallthrough is success |
| 351 | Ok(()) | 270 | Ok(()) |
| 352 | } | 271 | } |
| @@ -386,64 +305,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 386 | /// | 305 | /// |
| 387 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 306 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 388 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 307 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 389 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | ||
| 390 | // stop condition below. | ||
| 391 | if operations.iter().any(|op| match op { | ||
| 392 | Operation::Read(read) => read.is_empty(), | ||
| 393 | Operation::Write(_) => false, | ||
| 394 | }) { | ||
| 395 | return Err(Error::Overrun); | ||
| 396 | } | ||
| 397 | |||
| 398 | let timeout = self.timeout(); | 308 | let timeout = self.timeout(); |
| 399 | 309 | ||
| 400 | let mut operations = operations.iter_mut(); | 310 | for (op, frame) in operation_frames(operations)? { |
| 401 | |||
| 402 | let mut prev_op: Option<&mut Operation<'_>> = None; | ||
| 403 | let mut next_op = operations.next(); | ||
| 404 | |||
| 405 | while let Some(op) = next_op { | ||
| 406 | next_op = operations.next(); | ||
| 407 | |||
| 408 | // Check if this is the first frame of this type. This is the case for the first overall | ||
| 409 | // frame in the transaction and whenever the type of operation changes. | ||
| 410 | let first_frame = | ||
| 411 | match (prev_op.as_ref(), &op) { | ||
| 412 | (None, _) => true, | ||
| 413 | (Some(Operation::Read(_)), Operation::Write(_)) | ||
| 414 | | (Some(Operation::Write(_)), Operation::Read(_)) => true, | ||
| 415 | (Some(Operation::Read(_)), Operation::Read(_)) | ||
| 416 | | (Some(Operation::Write(_)), Operation::Write(_)) => false, | ||
| 417 | }; | ||
| 418 | |||
| 419 | let frame = match (first_frame, next_op.as_ref()) { | ||
| 420 | // If this is the first frame of this type, we generate a (repeated) start condition | ||
| 421 | // but have to consider the next operation: if it is the last, we generate the final | ||
| 422 | // stop condition. Otherwise, we branch on the operation: with read operations, only | ||
| 423 | // the last byte overall (before a write operation or the end of the transaction) is | ||
| 424 | // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte. | ||
| 425 | (true, None) => FrameOptions::FirstAndLastFrame, | ||
| 426 | // Make sure to keep sending ACK for last byte in read operation when it is followed | ||
| 427 | // by another consecutive read operation. If the current operation is write, this is | ||
| 428 | // identical to `FirstFrame`. | ||
| 429 | (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame, | ||
| 430 | // Otherwise, send NACK for last byte (in read operation). (For write, this does not | ||
| 431 | // matter and could also be `FirstAndNextFrame`.) | ||
| 432 | (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame, | ||
| 433 | |||
| 434 | // If this is not the first frame of its type, we do not generate a (repeated) start | ||
| 435 | // condition. Otherwise, we branch the same way as above. | ||
| 436 | (false, None) => FrameOptions::LastFrame, | ||
| 437 | (false, Some(Operation::Read(_))) => FrameOptions::NextFrame, | ||
| 438 | (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop, | ||
| 439 | }; | ||
| 440 | |||
| 441 | match op { | 311 | match op { |
| 442 | Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, | 312 | Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, |
| 443 | Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, | 313 | Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, |
| 444 | } | 314 | } |
| 445 | |||
| 446 | prev_op = Some(op); | ||
| 447 | } | 315 | } |
| 448 | 316 | ||
| 449 | Ok(()) | 317 | Ok(()) |
| @@ -459,111 +327,110 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 459 | }); | 327 | }); |
| 460 | } | 328 | } |
| 461 | 329 | ||
| 462 | async fn write_with_stop(&mut self, address: u8, write: &[u8], send_stop: bool) -> Result<(), Error> | 330 | async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> |
| 463 | where | 331 | where |
| 464 | TXDMA: crate::i2c::TxDma<T>, | 332 | TXDMA: crate::i2c::TxDma<T>, |
| 465 | { | 333 | { |
| 466 | let dma_transfer = unsafe { | 334 | T::regs().cr2().modify(|w| { |
| 467 | let regs = T::regs(); | 335 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for |
| 468 | regs.cr2().modify(|w| { | 336 | // reception. |
| 469 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | 337 | w.set_itbufen(false); |
| 470 | w.set_dmaen(true); | 338 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 |
| 471 | w.set_itbufen(false); | 339 | // register. |
| 472 | }); | 340 | w.set_dmaen(true); |
| 473 | // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event. | 341 | // Sending NACK is not necessary (nor possible) for write transfer. |
| 474 | let dst = regs.dr().as_ptr() as *mut u8; | 342 | w.set_last(false); |
| 475 | 343 | }); | |
| 476 | let ch = &mut self.tx_dma; | ||
| 477 | let request = ch.request(); | ||
| 478 | Transfer::new_write(ch, request, write, dst, Default::default()) | ||
| 479 | }; | ||
| 480 | 344 | ||
| 345 | // Sentinel to disable transfer when an error occurs or future is canceled. | ||
| 346 | // TODO: Generate STOP condition on cancel? | ||
| 481 | let on_drop = OnDrop::new(|| { | 347 | let on_drop = OnDrop::new(|| { |
| 482 | let regs = T::regs(); | 348 | T::regs().cr2().modify(|w| { |
| 483 | regs.cr2().modify(|w| { | ||
| 484 | w.set_dmaen(false); | 349 | w.set_dmaen(false); |
| 485 | w.set_iterren(false); | 350 | w.set_iterren(false); |
| 486 | w.set_itevten(false); | 351 | w.set_itevten(false); |
| 487 | }) | 352 | }) |
| 488 | }); | 353 | }); |
| 489 | 354 | ||
| 490 | Self::enable_interrupts(); | ||
| 491 | |||
| 492 | // Send a START condition | ||
| 493 | T::regs().cr1().modify(|reg| { | ||
| 494 | reg.set_start(true); | ||
| 495 | }); | ||
| 496 | |||
| 497 | let state = T::state(); | 355 | let state = T::state(); |
| 498 | 356 | ||
| 499 | // Wait until START condition was generated | 357 | if frame.send_start() { |
| 500 | poll_fn(|cx| { | 358 | // Send a START condition |
| 501 | state.waker.register(cx.waker()); | 359 | T::regs().cr1().modify(|reg| { |
| 360 | reg.set_start(true); | ||
| 361 | }); | ||
| 502 | 362 | ||
| 503 | match Self::check_and_clear_error_flags() { | 363 | // Wait until START condition was generated |
| 504 | Err(e) => Poll::Ready(Err(e)), | 364 | poll_fn(|cx| { |
| 505 | Ok(sr1) => { | 365 | state.waker.register(cx.waker()); |
| 506 | if sr1.start() { | 366 | |
| 507 | Poll::Ready(Ok(())) | 367 | match Self::check_and_clear_error_flags() { |
| 508 | } else { | 368 | Err(e) => Poll::Ready(Err(e)), |
| 509 | Poll::Pending | 369 | Ok(sr1) => { |
| 370 | if sr1.start() { | ||
| 371 | Poll::Ready(Ok(())) | ||
| 372 | } else { | ||
| 373 | // When pending, (re-)enable interrupts to wake us up. | ||
| 374 | Self::enable_interrupts(); | ||
| 375 | Poll::Pending | ||
| 376 | } | ||
| 510 | } | 377 | } |
| 511 | } | 378 | } |
| 379 | }) | ||
| 380 | .await?; | ||
| 381 | |||
| 382 | // Check if we were the ones to generate START | ||
| 383 | if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { | ||
| 384 | return Err(Error::Arbitration); | ||
| 512 | } | 385 | } |
| 513 | }) | ||
| 514 | .await?; | ||
| 515 | 386 | ||
| 516 | // Also wait until signalled we're master and everything is waiting for us | 387 | // Set up current address we're trying to talk to |
| 517 | Self::enable_interrupts(); | 388 | T::regs().dr().write(|reg| reg.set_dr(address << 1)); |
| 518 | poll_fn(|cx| { | ||
| 519 | state.waker.register(cx.waker()); | ||
| 520 | 389 | ||
| 521 | match Self::check_and_clear_error_flags() { | 390 | // Wait for the address to be acknowledged |
| 522 | Err(e) => Poll::Ready(Err(e)), | 391 | poll_fn(|cx| { |
| 523 | Ok(_) => { | 392 | state.waker.register(cx.waker()); |
| 524 | let sr2 = T::regs().sr2().read(); | 393 | |
| 525 | if !sr2.msl() && !sr2.busy() { | 394 | match Self::check_and_clear_error_flags() { |
| 526 | Poll::Pending | 395 | Err(e) => Poll::Ready(Err(e)), |
| 527 | } else { | 396 | Ok(sr1) => { |
| 528 | Poll::Ready(Ok(())) | 397 | if sr1.addr() { |
| 398 | Poll::Ready(Ok(())) | ||
| 399 | } else { | ||
| 400 | // When pending, (re-)enable interrupts to wake us up. | ||
| 401 | Self::enable_interrupts(); | ||
| 402 | Poll::Pending | ||
| 403 | } | ||
| 529 | } | 404 | } |
| 530 | } | 405 | } |
| 531 | } | 406 | }) |
| 532 | }) | 407 | .await?; |
| 533 | .await?; | ||
| 534 | 408 | ||
| 535 | // Set up current address, we're trying to talk to | 409 | // Clear condition by reading SR2 |
| 536 | Self::enable_interrupts(); | 410 | T::regs().sr2().read(); |
| 537 | T::regs().dr().write(|reg| reg.set_dr(address << 1)); | 411 | } |
| 538 | 412 | ||
| 539 | poll_fn(|cx| { | 413 | let dma_transfer = unsafe { |
| 540 | state.waker.register(cx.waker()); | 414 | // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to |
| 541 | match Self::check_and_clear_error_flags() { | 415 | // this address from the memory after each TxE event. |
| 542 | Err(e) => Poll::Ready(Err(e)), | 416 | let dst = T::regs().dr().as_ptr() as *mut u8; |
| 543 | Ok(sr1) => { | 417 | |
| 544 | if sr1.addr() { | 418 | let ch = &mut self.tx_dma; |
| 545 | // Clear the ADDR condition by reading SR2. | 419 | let request = ch.request(); |
| 546 | T::regs().sr2().read(); | 420 | Transfer::new_write(ch, request, write, dst, Default::default()) |
| 547 | Poll::Ready(Ok(())) | 421 | }; |
| 548 | } else { | 422 | |
| 549 | // If we need to go around, then re-enable the interrupts, otherwise nothing | 423 | // Wait for bytes to be sent, or an error to occur. |
| 550 | // can wake us up and we'll hang. | ||
| 551 | Self::enable_interrupts(); | ||
| 552 | Poll::Pending | ||
| 553 | } | ||
| 554 | } | ||
| 555 | } | ||
| 556 | }) | ||
| 557 | .await?; | ||
| 558 | Self::enable_interrupts(); | ||
| 559 | let poll_error = poll_fn(|cx| { | 424 | let poll_error = poll_fn(|cx| { |
| 560 | state.waker.register(cx.waker()); | 425 | state.waker.register(cx.waker()); |
| 561 | 426 | ||
| 562 | match Self::check_and_clear_error_flags() { | 427 | match Self::check_and_clear_error_flags() { |
| 563 | // Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other | 428 | Err(e) => Poll::Ready(Err::<(), Error>(e)), |
| 564 | // identical poll_fn check_and_clear matches. | 429 | Ok(_) => { |
| 565 | Err(e) => Poll::Ready(Err::<T, Error>(e)), | 430 | // When pending, (re-)enable interrupts to wake us up. |
| 566 | Ok(_) => Poll::Pending, | 431 | Self::enable_interrupts(); |
| 432 | Poll::Pending | ||
| 433 | } | ||
| 567 | } | 434 | } |
| 568 | }); | 435 | }); |
| 569 | 436 | ||
| @@ -573,38 +440,37 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 573 | _ => Ok(()), | 440 | _ => Ok(()), |
| 574 | }?; | 441 | }?; |
| 575 | 442 | ||
| 576 | // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. | ||
| 577 | |||
| 578 | // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA | ||
| 579 | // requests then wait for a BTF event before programming the Stop condition.” | ||
| 580 | |||
| 581 | // TODO: If this has to be done “in the interrupt routine after the EOT interrupt”, where to put it? | ||
| 582 | T::regs().cr2().modify(|w| { | 443 | T::regs().cr2().modify(|w| { |
| 583 | w.set_dmaen(false); | 444 | w.set_dmaen(false); |
| 584 | }); | 445 | }); |
| 585 | 446 | ||
| 586 | Self::enable_interrupts(); | 447 | if frame.send_stop() { |
| 587 | poll_fn(|cx| { | 448 | // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. |
| 588 | state.waker.register(cx.waker()); | 449 | |
| 589 | 450 | // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA | |
| 590 | match Self::check_and_clear_error_flags() { | 451 | // requests then wait for a BTF event before programming the Stop condition.” |
| 591 | Err(e) => Poll::Ready(Err(e)), | 452 | poll_fn(|cx| { |
| 592 | Ok(sr1) => { | 453 | state.waker.register(cx.waker()); |
| 593 | if sr1.btf() { | 454 | |
| 594 | if send_stop { | 455 | match Self::check_and_clear_error_flags() { |
| 595 | T::regs().cr1().modify(|w| { | 456 | Err(e) => Poll::Ready(Err(e)), |
| 596 | w.set_stop(true); | 457 | Ok(sr1) => { |
| 597 | }); | 458 | if sr1.btf() { |
| 459 | Poll::Ready(Ok(())) | ||
| 460 | } else { | ||
| 461 | // When pending, (re-)enable interrupts to wake us up. | ||
| 462 | Self::enable_interrupts(); | ||
| 463 | Poll::Pending | ||
| 598 | } | 464 | } |
| 599 | |||
| 600 | Poll::Ready(Ok(())) | ||
| 601 | } else { | ||
| 602 | Poll::Pending | ||
| 603 | } | 465 | } |
| 604 | } | 466 | } |
| 605 | } | 467 | }) |
| 606 | }) | 468 | .await?; |
| 607 | .await?; | 469 | |
| 470 | T::regs().cr1().modify(|w| { | ||
| 471 | w.set_stop(true); | ||
| 472 | }); | ||
| 473 | } | ||
| 608 | 474 | ||
| 609 | drop(on_drop); | 475 | drop(on_drop); |
| 610 | 476 | ||
| @@ -617,20 +483,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 617 | where | 483 | where |
| 618 | TXDMA: crate::i2c::TxDma<T>, | 484 | TXDMA: crate::i2c::TxDma<T>, |
| 619 | { | 485 | { |
| 620 | self.write_with_stop(address, write, true).await?; | 486 | self.write_frame(address, write, FrameOptions::FirstAndLastFrame) |
| 621 | 487 | .await?; | |
| 622 | // Wait for STOP condition to transmit. | ||
| 623 | Self::enable_interrupts(); | ||
| 624 | poll_fn(|cx| { | ||
| 625 | T::state().waker.register(cx.waker()); | ||
| 626 | // TODO: error interrupts are enabled here, should we additional check for and return errors? | ||
| 627 | if T::regs().cr1().read().stop() { | ||
| 628 | Poll::Pending | ||
| 629 | } else { | ||
| 630 | Poll::Ready(Ok(())) | ||
| 631 | } | ||
| 632 | }) | ||
| 633 | .await?; | ||
| 634 | 488 | ||
| 635 | Ok(()) | 489 | Ok(()) |
| 636 | } | 490 | } |
| @@ -640,135 +494,151 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 640 | where | 494 | where |
| 641 | RXDMA: crate::i2c::RxDma<T>, | 495 | RXDMA: crate::i2c::RxDma<T>, |
| 642 | { | 496 | { |
| 643 | let state = T::state(); | 497 | self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) |
| 644 | let buffer_len = buffer.len(); | 498 | .await?; |
| 645 | 499 | ||
| 646 | let dma_transfer = unsafe { | 500 | Ok(()) |
| 647 | let regs = T::regs(); | 501 | } |
| 648 | regs.cr2().modify(|w| { | ||
| 649 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | ||
| 650 | w.set_itbufen(false); | ||
| 651 | w.set_dmaen(true); | ||
| 652 | }); | ||
| 653 | // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event. | ||
| 654 | let src = regs.dr().as_ptr() as *mut u8; | ||
| 655 | 502 | ||
| 656 | let ch = &mut self.rx_dma; | 503 | async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> |
| 657 | let request = ch.request(); | 504 | where |
| 658 | Transfer::new_read(ch, request, src, buffer, Default::default()) | 505 | RXDMA: crate::i2c::RxDma<T>, |
| 659 | }; | 506 | { |
| 507 | if buffer.is_empty() { | ||
| 508 | return Err(Error::Overrun); | ||
| 509 | } | ||
| 510 | |||
| 511 | // Some branches below depend on whether the buffer contains only a single byte. | ||
| 512 | let single_byte = buffer.len() == 1; | ||
| 513 | |||
| 514 | T::regs().cr2().modify(|w| { | ||
| 515 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for | ||
| 516 | // reception. | ||
| 517 | w.set_itbufen(false); | ||
| 518 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 | ||
| 519 | // register. | ||
| 520 | w.set_dmaen(true); | ||
| 521 | // If, in the I2C_CR2 register, the LAST bit is set, I2C automatically sends a NACK | ||
| 522 | // after the next byte following EOT_1. The user can generate a Stop condition in | ||
| 523 | // the DMA Transfer Complete interrupt routine if enabled. | ||
| 524 | w.set_last(frame.send_nack() && !single_byte); | ||
| 525 | }); | ||
| 660 | 526 | ||
| 527 | // Sentinel to disable transfer when an error occurs or future is canceled. | ||
| 528 | // TODO: Generate STOP condition on cancel? | ||
| 661 | let on_drop = OnDrop::new(|| { | 529 | let on_drop = OnDrop::new(|| { |
| 662 | let regs = T::regs(); | 530 | T::regs().cr2().modify(|w| { |
| 663 | regs.cr2().modify(|w| { | ||
| 664 | w.set_dmaen(false); | 531 | w.set_dmaen(false); |
| 665 | w.set_iterren(false); | 532 | w.set_iterren(false); |
| 666 | w.set_itevten(false); | 533 | w.set_itevten(false); |
| 667 | }) | 534 | }) |
| 668 | }); | 535 | }); |
| 669 | 536 | ||
| 670 | Self::enable_interrupts(); | 537 | let state = T::state(); |
| 671 | |||
| 672 | // Send a START condition and set ACK bit | ||
| 673 | T::regs().cr1().modify(|reg| { | ||
| 674 | reg.set_start(true); | ||
| 675 | reg.set_ack(true); | ||
| 676 | }); | ||
| 677 | 538 | ||
| 678 | // Wait until START condition was generated | 539 | if frame.send_start() { |
| 679 | poll_fn(|cx| { | 540 | // Send a START condition and set ACK bit |
| 680 | state.waker.register(cx.waker()); | 541 | T::regs().cr1().modify(|reg| { |
| 542 | reg.set_start(true); | ||
| 543 | reg.set_ack(true); | ||
| 544 | }); | ||
| 681 | 545 | ||
| 682 | match Self::check_and_clear_error_flags() { | 546 | // Wait until START condition was generated |
| 683 | Err(e) => Poll::Ready(Err(e)), | 547 | poll_fn(|cx| { |
| 684 | Ok(sr1) => { | 548 | state.waker.register(cx.waker()); |
| 685 | if sr1.start() { | 549 | |
| 686 | Poll::Ready(Ok(())) | 550 | match Self::check_and_clear_error_flags() { |
| 687 | } else { | 551 | Err(e) => Poll::Ready(Err(e)), |
| 688 | Poll::Pending | 552 | Ok(sr1) => { |
| 553 | if sr1.start() { | ||
| 554 | Poll::Ready(Ok(())) | ||
| 555 | } else { | ||
| 556 | // When pending, (re-)enable interrupts to wake us up. | ||
| 557 | Self::enable_interrupts(); | ||
| 558 | Poll::Pending | ||
| 559 | } | ||
| 689 | } | 560 | } |
| 690 | } | 561 | } |
| 691 | } | 562 | }) |
| 692 | }) | 563 | .await?; |
| 693 | .await?; | ||
| 694 | |||
| 695 | // Also wait until signalled we're master and everything is waiting for us | ||
| 696 | Self::enable_interrupts(); | ||
| 697 | poll_fn(|cx| { | ||
| 698 | state.waker.register(cx.waker()); | ||
| 699 | 564 | ||
| 700 | // blocking read didn’t have a check_and_clear call here, but blocking write did so | 565 | // Check if we were the ones to generate START |
| 701 | // I’m adding it here in case that was an oversight. | 566 | if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() { |
| 702 | match Self::check_and_clear_error_flags() { | 567 | return Err(Error::Arbitration); |
| 703 | Err(e) => Poll::Ready(Err(e)), | ||
| 704 | Ok(_) => { | ||
| 705 | let sr2 = T::regs().sr2().read(); | ||
| 706 | if !sr2.msl() && !sr2.busy() { | ||
| 707 | Poll::Pending | ||
| 708 | } else { | ||
| 709 | Poll::Ready(Ok(())) | ||
| 710 | } | ||
| 711 | } | ||
| 712 | } | 568 | } |
| 713 | }) | ||
| 714 | .await?; | ||
| 715 | 569 | ||
| 716 | // Set up current address, we're trying to talk to | 570 | // Set up current address we're trying to talk to |
| 717 | T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); | 571 | T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); |
| 718 | 572 | ||
| 719 | // Wait for the address to be acknowledged | 573 | // Wait for the address to be acknowledged |
| 720 | 574 | poll_fn(|cx| { | |
| 721 | Self::enable_interrupts(); | 575 | state.waker.register(cx.waker()); |
| 722 | poll_fn(|cx| { | 576 | |
| 723 | state.waker.register(cx.waker()); | 577 | match Self::check_and_clear_error_flags() { |
| 724 | 578 | Err(e) => Poll::Ready(Err(e)), | |
| 725 | match Self::check_and_clear_error_flags() { | 579 | Ok(sr1) => { |
| 726 | Err(e) => Poll::Ready(Err(e)), | 580 | if sr1.addr() { |
| 727 | Ok(sr1) => { | 581 | Poll::Ready(Ok(())) |
| 728 | if sr1.addr() { | 582 | } else { |
| 729 | // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 | 583 | // When pending, (re-)enable interrupts to wake us up. |
| 730 | // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. | 584 | Self::enable_interrupts(); |
| 731 | if buffer_len == 1 { | 585 | Poll::Pending |
| 732 | T::regs().cr1().modify(|w| { | ||
| 733 | w.set_ack(false); | ||
| 734 | }); | ||
| 735 | } | 586 | } |
| 736 | Poll::Ready(Ok(())) | ||
| 737 | } else { | ||
| 738 | Poll::Pending | ||
| 739 | } | 587 | } |
| 740 | } | 588 | } |
| 589 | }) | ||
| 590 | .await?; | ||
| 591 | |||
| 592 | // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 | ||
| 593 | // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. | ||
| 594 | if frame.send_nack() && single_byte { | ||
| 595 | T::regs().cr1().modify(|w| { | ||
| 596 | w.set_ack(false); | ||
| 597 | }); | ||
| 741 | } | 598 | } |
| 742 | }) | ||
| 743 | .await?; | ||
| 744 | 599 | ||
| 745 | // Clear ADDR condition by reading SR2 | 600 | // Clear condition by reading SR2 |
| 746 | T::regs().sr2().read(); | 601 | T::regs().sr2().read(); |
| 602 | } else { | ||
| 603 | // Before starting reception of single byte (but without START condition, i.e. in case | ||
| 604 | // of continued frame), program NACK to emit at end of this byte. | ||
| 605 | if frame.send_nack() && single_byte { | ||
| 606 | T::regs().cr1().modify(|w| { | ||
| 607 | w.set_ack(false); | ||
| 608 | }); | ||
| 609 | } | ||
| 610 | } | ||
| 747 | 611 | ||
| 748 | // 18.3.8: When a single byte must be received: [snip] Then the | 612 | // 18.3.8: When a single byte must be received: [snip] Then the user can program the STOP |
| 749 | // user can program the STOP condition either after clearing ADDR flag, or in the | 613 | // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt |
| 750 | // DMA Transfer Complete interrupt routine. | 614 | // routine. |
| 751 | if buffer_len == 1 { | 615 | if frame.send_stop() && single_byte { |
| 752 | T::regs().cr1().modify(|w| { | 616 | T::regs().cr1().modify(|w| { |
| 753 | w.set_stop(true); | 617 | w.set_stop(true); |
| 754 | }); | 618 | }); |
| 755 | } else { | ||
| 756 | // If, in the I2C_CR2 register, the LAST bit is set, I2C | ||
| 757 | // automatically sends a NACK after the next byte following EOT_1. The user can | ||
| 758 | // generate a Stop condition in the DMA Transfer Complete interrupt routine if enabled. | ||
| 759 | T::regs().cr2().modify(|w| { | ||
| 760 | w.set_last(true); | ||
| 761 | }) | ||
| 762 | } | 619 | } |
| 763 | 620 | ||
| 621 | let dma_transfer = unsafe { | ||
| 622 | // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved | ||
| 623 | // from this address from the memory after each RxE event. | ||
| 624 | let src = T::regs().dr().as_ptr() as *mut u8; | ||
| 625 | |||
| 626 | let ch = &mut self.rx_dma; | ||
| 627 | let request = ch.request(); | ||
| 628 | Transfer::new_read(ch, request, src, buffer, Default::default()) | ||
| 629 | }; | ||
| 630 | |||
| 764 | // Wait for bytes to be received, or an error to occur. | 631 | // Wait for bytes to be received, or an error to occur. |
| 765 | Self::enable_interrupts(); | ||
| 766 | let poll_error = poll_fn(|cx| { | 632 | let poll_error = poll_fn(|cx| { |
| 767 | state.waker.register(cx.waker()); | 633 | state.waker.register(cx.waker()); |
| 768 | 634 | ||
| 769 | match Self::check_and_clear_error_flags() { | 635 | match Self::check_and_clear_error_flags() { |
| 770 | Err(e) => Poll::Ready(Err::<T, Error>(e)), | 636 | Err(e) => Poll::Ready(Err::<(), Error>(e)), |
| 771 | _ => Poll::Pending, | 637 | _ => { |
| 638 | // When pending, (re-)enable interrupts to wake us up. | ||
| 639 | Self::enable_interrupts(); | ||
| 640 | Poll::Pending | ||
| 641 | } | ||
| 772 | } | 642 | } |
| 773 | }); | 643 | }); |
| 774 | 644 | ||
| @@ -777,18 +647,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 777 | _ => Ok(()), | 647 | _ => Ok(()), |
| 778 | }?; | 648 | }?; |
| 779 | 649 | ||
| 780 | // Wait for the STOP to be sent (STOP bit cleared). | 650 | T::regs().cr2().modify(|w| { |
| 781 | Self::enable_interrupts(); | 651 | w.set_dmaen(false); |
| 782 | poll_fn(|cx| { | 652 | }); |
| 783 | state.waker.register(cx.waker()); | 653 | |
| 784 | // TODO: error interrupts are enabled here, should we additional check for and return errors? | 654 | if frame.send_stop() && !single_byte { |
| 785 | if T::regs().cr1().read().stop() { | 655 | T::regs().cr1().modify(|w| { |
| 786 | Poll::Pending | 656 | w.set_stop(true); |
| 787 | } else { | 657 | }); |
| 788 | Poll::Ready(Ok(())) | 658 | } |
| 789 | } | 659 | |
| 790 | }) | ||
| 791 | .await?; | ||
| 792 | drop(on_drop); | 660 | drop(on_drop); |
| 793 | 661 | ||
| 794 | // Fallthrough is success | 662 | // Fallthrough is success |
| @@ -801,8 +669,34 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 801 | RXDMA: crate::i2c::RxDma<T>, | 669 | RXDMA: crate::i2c::RxDma<T>, |
| 802 | TXDMA: crate::i2c::TxDma<T>, | 670 | TXDMA: crate::i2c::TxDma<T>, |
| 803 | { | 671 | { |
| 804 | self.write_with_stop(address, write, false).await?; | 672 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the |
| 805 | self.read(address, read).await | 673 | // stop condition below. |
| 674 | if read.is_empty() { | ||
| 675 | return Err(Error::Overrun); | ||
| 676 | } | ||
| 677 | |||
| 678 | self.write_frame(address, write, FrameOptions::FirstFrame).await?; | ||
| 679 | self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await | ||
| 680 | } | ||
| 681 | |||
| 682 | /// Transaction with operations. | ||
| 683 | /// | ||
| 684 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 685 | /// | ||
| 686 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 687 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> | ||
| 688 | where | ||
| 689 | RXDMA: crate::i2c::RxDma<T>, | ||
| 690 | TXDMA: crate::i2c::TxDma<T>, | ||
| 691 | { | ||
| 692 | for (op, frame) in operation_frames(operations)? { | ||
| 693 | match op { | ||
| 694 | Operation::Read(read) => self.read_frame(addr, read, frame).await?, | ||
| 695 | Operation::Write(write) => self.write_frame(addr, write, frame).await?, | ||
| 696 | } | ||
| 697 | } | ||
| 698 | |||
| 699 | Ok(()) | ||
| 806 | } | 700 | } |
| 807 | } | 701 | } |
| 808 | 702 | ||
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8baf2849d..da3b0ee30 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -557,6 +557,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 557 | Ok(()) | 557 | Ok(()) |
| 558 | } | 558 | } |
| 559 | 559 | ||
| 560 | /// Transaction with operations. | ||
| 561 | /// | ||
| 562 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 563 | /// | ||
| 564 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 565 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> | ||
| 566 | where | ||
| 567 | RXDMA: crate::i2c::RxDma<T>, | ||
| 568 | TXDMA: crate::i2c::TxDma<T>, | ||
| 569 | { | ||
| 570 | let _ = addr; | ||
| 571 | let _ = operations; | ||
| 572 | todo!() | ||
| 573 | } | ||
| 574 | |||
| 560 | // ========================= | 575 | // ========================= |
| 561 | // Blocking public API | 576 | // Blocking public API |
| 562 | 577 | ||
