diff options
| author | Sebastian Goll <[email protected]> | 2024-03-21 00:30:53 +0100 |
|---|---|---|
| committer | Sebastian Goll <[email protected]> | 2024-03-27 00:32:06 +0100 |
| commit | accec7a84076ff26f9bdad388809b96537cf31da (patch) | |
| tree | 06ec571272a7e6023ea78286471d2845a060ce28 | |
| parent | 9c00a40e73f49aa0d46a47259fe8adc8c3f248b8 (diff) | |
Implement asynchronous transaction for I2C v1
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 214 |
2 files changed, 123 insertions, 95 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index f1b11cc44..6700f0f7d 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -332,8 +332,6 @@ impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c: | |||
| 332 | address: u8, | 332 | address: u8, |
| 333 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], | 333 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], |
| 334 | ) -> Result<(), Self::Error> { | 334 | ) -> Result<(), Self::Error> { |
| 335 | let _ = address; | 335 | self.transaction(address, operations).await |
| 336 | let _ = operations; | ||
| 337 | todo!() | ||
| 338 | } | 336 | } |
| 339 | } | 337 | } |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index dd2cea6b8..a740ab834 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -111,12 +111,21 @@ impl FrameOptions { | |||
| 111 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 111 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 112 | fn operation_frames<'a, 'b: 'a>( | 112 | fn operation_frames<'a, 'b: 'a>( |
| 113 | operations: &'a mut [Operation<'b>], | 113 | operations: &'a mut [Operation<'b>], |
| 114 | ) -> impl IntoIterator<Item = (&'a mut Operation<'b>, FrameOptions)> { | 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 | |||
| 115 | let mut operations = operations.iter_mut().peekable(); | 124 | let mut operations = operations.iter_mut().peekable(); |
| 116 | 125 | ||
| 117 | let mut next_first_frame = true; | 126 | let mut next_first_frame = true; |
| 118 | 127 | ||
| 119 | iter::from_fn(move || { | 128 | Ok(iter::from_fn(move || { |
| 120 | let Some(op) = operations.next() else { | 129 | let Some(op) = operations.next() else { |
| 121 | return None; | 130 | return None; |
| 122 | }; | 131 | }; |
| @@ -156,7 +165,7 @@ fn operation_frames<'a, 'b: 'a>( | |||
| 156 | }; | 165 | }; |
| 157 | 166 | ||
| 158 | Some((op, frame)) | 167 | Some((op, frame)) |
| 159 | }) | 168 | })) |
| 160 | } | 169 | } |
| 161 | 170 | ||
| 162 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 171 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| @@ -442,18 +451,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 442 | /// | 451 | /// |
| 443 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 452 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 444 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 453 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 445 | // Check empty read buffer before starting transaction. Otherwise, we would not generate the | ||
| 446 | // stop condition below. | ||
| 447 | if operations.iter().any(|op| match op { | ||
| 448 | Operation::Read(read) => read.is_empty(), | ||
| 449 | Operation::Write(_) => false, | ||
| 450 | }) { | ||
| 451 | return Err(Error::Overrun); | ||
| 452 | } | ||
| 453 | |||
| 454 | let timeout = self.timeout(); | 454 | let timeout = self.timeout(); |
| 455 | 455 | ||
| 456 | for (op, frame) in operation_frames(operations) { | 456 | for (op, frame) in operation_frames(operations)? { |
| 457 | match op { | 457 | match op { |
| 458 | Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, | 458 | Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, |
| 459 | Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, | 459 | Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, |
| @@ -480,9 +480,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 480 | let dma_transfer = unsafe { | 480 | let dma_transfer = unsafe { |
| 481 | let regs = T::regs(); | 481 | let regs = T::regs(); |
| 482 | regs.cr2().modify(|w| { | 482 | regs.cr2().modify(|w| { |
| 483 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for reception. | ||
| 484 | w.set_itbufen(false); | ||
| 483 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | 485 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. |
| 484 | w.set_dmaen(true); | 486 | w.set_dmaen(true); |
| 485 | w.set_itbufen(false); | 487 | // Sending NACK is not necessary (nor possible) for write transfer. |
| 488 | w.set_last(false); | ||
| 486 | }); | 489 | }); |
| 487 | // 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. | 490 | // 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. |
| 488 | let dst = regs.dr().as_ptr() as *mut u8; | 491 | let dst = regs.dr().as_ptr() as *mut u8; |
| @@ -520,6 +523,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 520 | if sr1.start() { | 523 | if sr1.start() { |
| 521 | Poll::Ready(Ok(())) | 524 | Poll::Ready(Ok(())) |
| 522 | } else { | 525 | } else { |
| 526 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 527 | // can wake us up and we'll hang. | ||
| 528 | Self::enable_interrupts(); | ||
| 523 | Poll::Pending | 529 | Poll::Pending |
| 524 | } | 530 | } |
| 525 | } | 531 | } |
| @@ -537,6 +543,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 537 | Ok(_) => { | 543 | Ok(_) => { |
| 538 | let sr2 = T::regs().sr2().read(); | 544 | let sr2 = T::regs().sr2().read(); |
| 539 | if !sr2.msl() && !sr2.busy() { | 545 | if !sr2.msl() && !sr2.busy() { |
| 546 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 547 | // can wake us up and we'll hang. | ||
| 548 | Self::enable_interrupts(); | ||
| 540 | Poll::Pending | 549 | Poll::Pending |
| 541 | } else { | 550 | } else { |
| 542 | Poll::Ready(Ok(())) | 551 | Poll::Ready(Ok(())) |
| @@ -550,14 +559,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 550 | Self::enable_interrupts(); | 559 | Self::enable_interrupts(); |
| 551 | T::regs().dr().write(|reg| reg.set_dr(address << 1)); | 560 | T::regs().dr().write(|reg| reg.set_dr(address << 1)); |
| 552 | 561 | ||
| 562 | // Wait for the address to be acknowledged | ||
| 553 | poll_fn(|cx| { | 563 | poll_fn(|cx| { |
| 554 | state.waker.register(cx.waker()); | 564 | state.waker.register(cx.waker()); |
| 565 | |||
| 555 | match Self::check_and_clear_error_flags() { | 566 | match Self::check_and_clear_error_flags() { |
| 556 | Err(e) => Poll::Ready(Err(e)), | 567 | Err(e) => Poll::Ready(Err(e)), |
| 557 | Ok(sr1) => { | 568 | Ok(sr1) => { |
| 558 | if sr1.addr() { | 569 | if sr1.addr() { |
| 559 | // Clear the ADDR condition by reading SR2. | ||
| 560 | T::regs().sr2().read(); | ||
| 561 | Poll::Ready(Ok(())) | 570 | Poll::Ready(Ok(())) |
| 562 | } else { | 571 | } else { |
| 563 | // If we need to go around, then re-enable the interrupts, otherwise nothing | 572 | // If we need to go around, then re-enable the interrupts, otherwise nothing |
| @@ -569,8 +578,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 569 | } | 578 | } |
| 570 | }) | 579 | }) |
| 571 | .await?; | 580 | .await?; |
| 581 | |||
| 582 | // Clear condition by reading SR2 | ||
| 583 | T::regs().sr2().read(); | ||
| 572 | } | 584 | } |
| 573 | 585 | ||
| 586 | // Wait for bytes to be sent, or an error to occur. | ||
| 574 | Self::enable_interrupts(); | 587 | Self::enable_interrupts(); |
| 575 | let poll_error = poll_fn(|cx| { | 588 | let poll_error = poll_fn(|cx| { |
| 576 | state.waker.register(cx.waker()); | 589 | state.waker.register(cx.waker()); |
| @@ -579,7 +592,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 579 | // Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other | 592 | // Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other |
| 580 | // identical poll_fn check_and_clear matches. | 593 | // identical poll_fn check_and_clear matches. |
| 581 | Err(e) => Poll::Ready(Err::<T, Error>(e)), | 594 | Err(e) => Poll::Ready(Err::<T, Error>(e)), |
| 582 | Ok(_) => Poll::Pending, | 595 | Ok(_) => { |
| 596 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 597 | // can wake us up and we'll hang. | ||
| 598 | Self::enable_interrupts(); | ||
| 599 | Poll::Pending | ||
| 600 | } | ||
| 583 | } | 601 | } |
| 584 | }); | 602 | }); |
| 585 | 603 | ||
| @@ -589,52 +607,38 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 589 | _ => Ok(()), | 607 | _ => Ok(()), |
| 590 | }?; | 608 | }?; |
| 591 | 609 | ||
| 592 | // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. | ||
| 593 | |||
| 594 | // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA | ||
| 595 | // requests then wait for a BTF event before programming the Stop condition.” | ||
| 596 | |||
| 597 | // TODO: If this has to be done “in the interrupt routine after the EOT interrupt”, where to put it? | ||
| 598 | T::regs().cr2().modify(|w| { | 610 | T::regs().cr2().modify(|w| { |
| 599 | w.set_dmaen(false); | 611 | w.set_dmaen(false); |
| 600 | }); | 612 | }); |
| 601 | 613 | ||
| 602 | Self::enable_interrupts(); | ||
| 603 | poll_fn(|cx| { | ||
| 604 | state.waker.register(cx.waker()); | ||
| 605 | |||
| 606 | match Self::check_and_clear_error_flags() { | ||
| 607 | Err(e) => Poll::Ready(Err(e)), | ||
| 608 | Ok(sr1) => { | ||
| 609 | if sr1.btf() { | ||
| 610 | if frame.send_stop() { | ||
| 611 | T::regs().cr1().modify(|w| { | ||
| 612 | w.set_stop(true); | ||
| 613 | }); | ||
| 614 | } | ||
| 615 | |||
| 616 | Poll::Ready(Ok(())) | ||
| 617 | } else { | ||
| 618 | Poll::Pending | ||
| 619 | } | ||
| 620 | } | ||
| 621 | } | ||
| 622 | }) | ||
| 623 | .await?; | ||
| 624 | |||
| 625 | if frame.send_stop() { | 614 | if frame.send_stop() { |
| 626 | // Wait for STOP condition to transmit. | 615 | // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. |
| 616 | |||
| 617 | // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA | ||
| 618 | // requests then wait for a BTF event before programming the Stop condition.” | ||
| 627 | Self::enable_interrupts(); | 619 | Self::enable_interrupts(); |
| 628 | poll_fn(|cx| { | 620 | poll_fn(|cx| { |
| 629 | T::state().waker.register(cx.waker()); | 621 | state.waker.register(cx.waker()); |
| 630 | // TODO: error interrupts are enabled here, should we additional check for and return errors? | 622 | |
| 631 | if T::regs().cr1().read().stop() { | 623 | match Self::check_and_clear_error_flags() { |
| 632 | Poll::Pending | 624 | Err(e) => Poll::Ready(Err(e)), |
| 633 | } else { | 625 | Ok(sr1) => { |
| 634 | Poll::Ready(Ok(())) | 626 | if sr1.btf() { |
| 627 | Poll::Ready(Ok(())) | ||
| 628 | } else { | ||
| 629 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 630 | // can wake us up and we'll hang. | ||
| 631 | Self::enable_interrupts(); | ||
| 632 | Poll::Pending | ||
| 633 | } | ||
| 634 | } | ||
| 635 | } | 635 | } |
| 636 | }) | 636 | }) |
| 637 | .await?; | 637 | .await?; |
| 638 | |||
| 639 | T::regs().cr1().modify(|w| { | ||
| 640 | w.set_stop(true); | ||
| 641 | }); | ||
| 638 | } | 642 | } |
| 639 | 643 | ||
| 640 | drop(on_drop); | 644 | drop(on_drop); |
| @@ -669,15 +673,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 669 | where | 673 | where |
| 670 | RXDMA: crate::i2c::RxDma<T>, | 674 | RXDMA: crate::i2c::RxDma<T>, |
| 671 | { | 675 | { |
| 672 | let state = T::state(); | ||
| 673 | let buffer_len = buffer.len(); | 676 | let buffer_len = buffer.len(); |
| 674 | 677 | ||
| 675 | let dma_transfer = unsafe { | 678 | let dma_transfer = unsafe { |
| 676 | let regs = T::regs(); | 679 | let regs = T::regs(); |
| 677 | regs.cr2().modify(|w| { | 680 | regs.cr2().modify(|w| { |
| 678 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | 681 | // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for reception. |
| 679 | w.set_itbufen(false); | 682 | w.set_itbufen(false); |
| 683 | // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | ||
| 680 | w.set_dmaen(true); | 684 | w.set_dmaen(true); |
| 685 | // If, in the I2C_CR2 register, the LAST bit is set, I2C | ||
| 686 | // automatically sends a NACK after the next byte following EOT_1. The user can | ||
| 687 | // generate a Stop condition in the DMA Transfer Complete interrupt routine if enabled. | ||
| 688 | w.set_last(frame.send_nack() && buffer_len != 1); | ||
| 681 | }); | 689 | }); |
| 682 | // 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. | 690 | // 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. |
| 683 | let src = regs.dr().as_ptr() as *mut u8; | 691 | let src = regs.dr().as_ptr() as *mut u8; |
| @@ -696,6 +704,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 696 | }) | 704 | }) |
| 697 | }); | 705 | }); |
| 698 | 706 | ||
| 707 | let state = T::state(); | ||
| 708 | |||
| 699 | if frame.send_start() { | 709 | if frame.send_start() { |
| 700 | // Send a START condition and set ACK bit | 710 | // Send a START condition and set ACK bit |
| 701 | Self::enable_interrupts(); | 711 | Self::enable_interrupts(); |
| @@ -714,6 +724,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 714 | if sr1.start() { | 724 | if sr1.start() { |
| 715 | Poll::Ready(Ok(())) | 725 | Poll::Ready(Ok(())) |
| 716 | } else { | 726 | } else { |
| 727 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 728 | // can wake us up and we'll hang. | ||
| 729 | Self::enable_interrupts(); | ||
| 717 | Poll::Pending | 730 | Poll::Pending |
| 718 | } | 731 | } |
| 719 | } | 732 | } |
| @@ -733,6 +746,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 733 | Ok(_) => { | 746 | Ok(_) => { |
| 734 | let sr2 = T::regs().sr2().read(); | 747 | let sr2 = T::regs().sr2().read(); |
| 735 | if !sr2.msl() && !sr2.busy() { | 748 | if !sr2.msl() && !sr2.busy() { |
| 749 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 750 | // can wake us up and we'll hang. | ||
| 751 | Self::enable_interrupts(); | ||
| 736 | Poll::Pending | 752 | Poll::Pending |
| 737 | } else { | 753 | } else { |
| 738 | Poll::Ready(Ok(())) | 754 | Poll::Ready(Ok(())) |
| @@ -743,11 +759,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 743 | .await?; | 759 | .await?; |
| 744 | 760 | ||
| 745 | // Set up current address, we're trying to talk to | 761 | // Set up current address, we're trying to talk to |
| 762 | Self::enable_interrupts(); | ||
| 746 | T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); | 763 | T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); |
| 747 | 764 | ||
| 748 | // Wait for the address to be acknowledged | 765 | // Wait for the address to be acknowledged |
| 749 | |||
| 750 | Self::enable_interrupts(); | ||
| 751 | poll_fn(|cx| { | 766 | poll_fn(|cx| { |
| 752 | state.waker.register(cx.waker()); | 767 | state.waker.register(cx.waker()); |
| 753 | 768 | ||
| @@ -755,15 +770,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 755 | Err(e) => Poll::Ready(Err(e)), | 770 | Err(e) => Poll::Ready(Err(e)), |
| 756 | Ok(sr1) => { | 771 | Ok(sr1) => { |
| 757 | if sr1.addr() { | 772 | if sr1.addr() { |
| 758 | // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 | ||
| 759 | // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. | ||
| 760 | if buffer_len == 1 && frame.send_nack() { | ||
| 761 | T::regs().cr1().modify(|w| { | ||
| 762 | w.set_ack(false); | ||
| 763 | }); | ||
| 764 | } | ||
| 765 | Poll::Ready(Ok(())) | 773 | Poll::Ready(Ok(())) |
| 766 | } else { | 774 | } else { |
| 775 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 776 | // can wake us up and we'll hang. | ||
| 777 | Self::enable_interrupts(); | ||
| 767 | Poll::Pending | 778 | Poll::Pending |
| 768 | } | 779 | } |
| 769 | } | 780 | } |
| @@ -771,24 +782,29 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 771 | }) | 782 | }) |
| 772 | .await?; | 783 | .await?; |
| 773 | 784 | ||
| 774 | // Clear ADDR condition by reading SR2 | 785 | // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 |
| 786 | // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. | ||
| 787 | if frame.send_nack() && buffer_len == 1 { | ||
| 788 | T::regs().cr1().modify(|w| { | ||
| 789 | w.set_ack(false); | ||
| 790 | }); | ||
| 791 | } | ||
| 792 | |||
| 793 | // Clear condition by reading SR2 | ||
| 775 | T::regs().sr2().read(); | 794 | T::regs().sr2().read(); |
| 795 | } else if frame.send_nack() && buffer_len == 1 { | ||
| 796 | T::regs().cr1().modify(|w| { | ||
| 797 | w.set_ack(false); | ||
| 798 | }); | ||
| 776 | } | 799 | } |
| 777 | 800 | ||
| 778 | // 18.3.8: When a single byte must be received: [snip] Then the | 801 | // 18.3.8: When a single byte must be received: [snip] Then the |
| 779 | // user can program the STOP condition either after clearing ADDR flag, or in the | 802 | // user can program the STOP condition either after clearing ADDR flag, or in the |
| 780 | // DMA Transfer Complete interrupt routine. | 803 | // DMA Transfer Complete interrupt routine. |
| 781 | if buffer_len == 1 && frame.send_stop() { | 804 | if frame.send_stop() && buffer_len == 1 { |
| 782 | T::regs().cr1().modify(|w| { | 805 | T::regs().cr1().modify(|w| { |
| 783 | w.set_stop(true); | 806 | w.set_stop(true); |
| 784 | }); | 807 | }); |
| 785 | } else if buffer_len != 1 && frame.send_nack() { | ||
| 786 | // If, in the I2C_CR2 register, the LAST bit is set, I2C | ||
| 787 | // automatically sends a NACK after the next byte following EOT_1. The user can | ||
| 788 | // generate a Stop condition in the DMA Transfer Complete interrupt routine if enabled. | ||
| 789 | T::regs().cr2().modify(|w| { | ||
| 790 | w.set_last(true); | ||
| 791 | }); | ||
| 792 | } | 808 | } |
| 793 | 809 | ||
| 794 | // Wait for bytes to be received, or an error to occur. | 810 | // Wait for bytes to be received, or an error to occur. |
| @@ -798,7 +814,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 798 | 814 | ||
| 799 | match Self::check_and_clear_error_flags() { | 815 | match Self::check_and_clear_error_flags() { |
| 800 | Err(e) => Poll::Ready(Err::<T, Error>(e)), | 816 | Err(e) => Poll::Ready(Err::<T, Error>(e)), |
| 801 | _ => Poll::Pending, | 817 | _ => { |
| 818 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 819 | // can wake us up and we'll hang. | ||
| 820 | Self::enable_interrupts(); | ||
| 821 | Poll::Pending | ||
| 822 | } | ||
| 802 | } | 823 | } |
| 803 | }); | 824 | }); |
| 804 | 825 | ||
| @@ -807,25 +828,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 807 | _ => Ok(()), | 828 | _ => Ok(()), |
| 808 | }?; | 829 | }?; |
| 809 | 830 | ||
| 810 | if frame.send_stop() { | 831 | T::regs().cr2().modify(|w| { |
| 811 | if buffer_len != 1 { | 832 | w.set_dmaen(false); |
| 812 | T::regs().cr1().modify(|w| { | 833 | }); |
| 813 | w.set_stop(true); | ||
| 814 | }); | ||
| 815 | } | ||
| 816 | 834 | ||
| 817 | // Wait for the STOP to be sent (STOP bit cleared). | 835 | if frame.send_stop() && buffer_len != 1 { |
| 818 | Self::enable_interrupts(); | 836 | T::regs().cr1().modify(|w| { |
| 819 | poll_fn(|cx| { | 837 | w.set_stop(true); |
| 820 | state.waker.register(cx.waker()); | 838 | }); |
| 821 | // TODO: error interrupts are enabled here, should we additional check for and return errors? | ||
| 822 | if T::regs().cr1().read().stop() { | ||
| 823 | Poll::Pending | ||
| 824 | } else { | ||
| 825 | Poll::Ready(Ok(())) | ||
| 826 | } | ||
| 827 | }) | ||
| 828 | .await?; | ||
| 829 | } | 839 | } |
| 830 | 840 | ||
| 831 | drop(on_drop); | 841 | drop(on_drop); |
| @@ -843,6 +853,26 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 843 | self.write_frame(address, write, FrameOptions::FirstFrame).await?; | 853 | self.write_frame(address, write, FrameOptions::FirstFrame).await?; |
| 844 | self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await | 854 | self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await |
| 845 | } | 855 | } |
| 856 | |||
| 857 | /// Transaction with operations. | ||
| 858 | /// | ||
| 859 | /// Consecutive operations of same type are merged. See [transaction contract] for details. | ||
| 860 | /// | ||
| 861 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | ||
| 862 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> | ||
| 863 | where | ||
| 864 | RXDMA: crate::i2c::RxDma<T>, | ||
| 865 | TXDMA: crate::i2c::TxDma<T>, | ||
| 866 | { | ||
| 867 | for (op, frame) in operation_frames(operations)? { | ||
| 868 | match op { | ||
| 869 | Operation::Read(read) => self.read_frame(addr, read, frame).await?, | ||
| 870 | Operation::Write(write) => self.write_frame(addr, write, frame).await?, | ||
| 871 | } | ||
| 872 | } | ||
| 873 | |||
| 874 | Ok(()) | ||
| 875 | } | ||
| 846 | } | 876 | } |
| 847 | 877 | ||
| 848 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | 878 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { |
