aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Goll <[email protected]>2024-03-21 00:30:53 +0100
committerSebastian Goll <[email protected]>2024-03-27 00:32:06 +0100
commitaccec7a84076ff26f9bdad388809b96537cf31da (patch)
tree06ec571272a7e6023ea78286471d2845a060ce28
parent9c00a40e73f49aa0d46a47259fe8adc8c3f248b8 (diff)
Implement asynchronous transaction for I2C v1
-rw-r--r--embassy-stm32/src/i2c/mod.rs4
-rw-r--r--embassy-stm32/src/i2c/v1.rs214
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
112fn operation_frames<'a, 'b: 'a>( 112fn 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
162impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 171impl<'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
848impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 878impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {