diff options
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 398 | ||||
| -rw-r--r-- | embassy-rp/src/i2c.rs | 400 | ||||
| -rw-r--r-- | examples/nrf/src/bin/uart_idle.rs | 7 | ||||
| -rw-r--r-- | examples/rp/Cargo.toml | 3 | ||||
| -rw-r--r-- | examples/rp/src/bin/i2c_async.rs | 102 |
5 files changed, 620 insertions, 290 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index d99599112..636d6c7a3 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -173,6 +173,61 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 173 | (self.tx, self.rx) | 173 | (self.tx, self.rx) |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | /// Split the Uarte into a transmitter and receiver that will | ||
| 177 | /// return on idle, which is determined as the time it takes | ||
| 178 | /// for two bytes to be received. | ||
| 179 | pub fn split_with_idle<U: TimerInstance>( | ||
| 180 | self, | ||
| 181 | timer: impl Peripheral<P = U> + 'd, | ||
| 182 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 183 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 184 | ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { | ||
| 185 | let mut timer = Timer::new(timer); | ||
| 186 | |||
| 187 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 188 | |||
| 189 | let r = T::regs(); | ||
| 190 | |||
| 191 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 192 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 193 | // | ||
| 194 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 195 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 196 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 197 | let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||
| 198 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 199 | |||
| 200 | timer.set_frequency(Frequency::F16MHz); | ||
| 201 | timer.cc(0).write(timeout); | ||
| 202 | timer.cc(0).short_compare_clear(); | ||
| 203 | timer.cc(0).short_compare_stop(); | ||
| 204 | |||
| 205 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 206 | ppi_ch1.map_into(), | ||
| 207 | Event::from_reg(&r.events_rxdrdy), | ||
| 208 | timer.task_clear(), | ||
| 209 | timer.task_start(), | ||
| 210 | ); | ||
| 211 | ppi_ch1.enable(); | ||
| 212 | |||
| 213 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 214 | ppi_ch2.map_into(), | ||
| 215 | timer.cc(0).event_compare(), | ||
| 216 | Task::from_reg(&r.tasks_stoprx), | ||
| 217 | ); | ||
| 218 | ppi_ch2.enable(); | ||
| 219 | |||
| 220 | ( | ||
| 221 | self.tx, | ||
| 222 | UarteRxWithIdle { | ||
| 223 | rx: self.rx, | ||
| 224 | timer, | ||
| 225 | ppi_ch1: ppi_ch1, | ||
| 226 | _ppi_ch2: ppi_ch2, | ||
| 227 | }, | ||
| 228 | ) | ||
| 229 | } | ||
| 230 | |||
| 176 | /// Return the endtx event for use with PPI | 231 | /// Return the endtx event for use with PPI |
| 177 | pub fn event_endtx(&self) -> Event { | 232 | pub fn event_endtx(&self) -> Event { |
| 178 | let r = T::regs(); | 233 | let r = T::regs(); |
| @@ -597,236 +652,14 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { | |||
| 597 | } | 652 | } |
| 598 | } | 653 | } |
| 599 | 654 | ||
| 600 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] | 655 | pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> { |
| 601 | pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | 656 | rx: UarteRx<'d, T>, |
| 602 | // Do nothing | 657 | timer: Timer<'d, U>, |
| 603 | } | ||
| 604 | |||
| 605 | #[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] | ||
| 606 | pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { | ||
| 607 | use core::ops::Deref; | ||
| 608 | |||
| 609 | // Apply workaround for anomalies: | ||
| 610 | // - nRF9160 - anomaly 23 | ||
| 611 | // - nRF5340 - anomaly 44 | ||
| 612 | let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; | ||
| 613 | let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; | ||
| 614 | |||
| 615 | // NB Safety: This is taken from Nordic's driver - | ||
| 616 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 617 | if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||
| 618 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 619 | } | ||
| 620 | |||
| 621 | // NB Safety: This is taken from Nordic's driver - | ||
| 622 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 623 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||
| 624 | r.enable.write(|w| w.enable().enabled()); | ||
| 625 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 626 | |||
| 627 | let mut workaround_succeded = false; | ||
| 628 | // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. | ||
| 629 | // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured | ||
| 630 | // (resulting in 12 bits per data byte sent), this may take up to 40 ms. | ||
| 631 | for _ in 0..40000 { | ||
| 632 | // NB Safety: This is taken from Nordic's driver - | ||
| 633 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 634 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { | ||
| 635 | workaround_succeded = true; | ||
| 636 | break; | ||
| 637 | } else { | ||
| 638 | // Need to sleep for 1us here | ||
| 639 | } | ||
| 640 | } | ||
| 641 | |||
| 642 | if !workaround_succeded { | ||
| 643 | panic!("Failed to apply workaround for UART"); | ||
| 644 | } | ||
| 645 | |||
| 646 | let errors = r.errorsrc.read().bits(); | ||
| 647 | // NB Safety: safe to write back the bits we just read to clear them | ||
| 648 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 649 | r.enable.write(|w| w.enable().disabled()); | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { | ||
| 654 | if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { | ||
| 655 | // Finally we can disable, and we do so for the peripheral | ||
| 656 | // i.e. not just rx concerns. | ||
| 657 | r.enable.write(|w| w.enable().disabled()); | ||
| 658 | |||
| 659 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 660 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 661 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 662 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 663 | |||
| 664 | trace!("uarte tx and rx drop: done"); | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, | ||
| 669 | /// allowing it to implement the ReadUntilIdle trait. | ||
| 670 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { | ||
| 671 | tx: UarteTx<'d, U>, | ||
| 672 | rx: UarteRxWithIdle<'d, U, T>, | ||
| 673 | } | ||
| 674 | |||
| 675 | impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { | ||
| 676 | /// Create a new UARTE without hardware flow control | ||
| 677 | pub fn new( | ||
| 678 | uarte: impl Peripheral<P = U> + 'd, | ||
| 679 | timer: impl Peripheral<P = T> + 'd, | ||
| 680 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 681 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 682 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 683 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 684 | txd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 685 | config: Config, | ||
| 686 | ) -> Self { | ||
| 687 | into_ref!(rxd, txd); | ||
| 688 | Self::new_inner( | ||
| 689 | uarte, | ||
| 690 | timer, | ||
| 691 | ppi_ch1, | ||
| 692 | ppi_ch2, | ||
| 693 | irq, | ||
| 694 | rxd.map_into(), | ||
| 695 | txd.map_into(), | ||
| 696 | None, | ||
| 697 | None, | ||
| 698 | config, | ||
| 699 | ) | ||
| 700 | } | ||
| 701 | |||
| 702 | /// Create a new UARTE with hardware flow control (RTS/CTS) | ||
| 703 | pub fn new_with_rtscts( | ||
| 704 | uarte: impl Peripheral<P = U> + 'd, | ||
| 705 | timer: impl Peripheral<P = T> + 'd, | ||
| 706 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 707 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 708 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 709 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 710 | txd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 711 | cts: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 712 | rts: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 713 | config: Config, | ||
| 714 | ) -> Self { | ||
| 715 | into_ref!(rxd, txd, cts, rts); | ||
| 716 | Self::new_inner( | ||
| 717 | uarte, | ||
| 718 | timer, | ||
| 719 | ppi_ch1, | ||
| 720 | ppi_ch2, | ||
| 721 | irq, | ||
| 722 | rxd.map_into(), | ||
| 723 | txd.map_into(), | ||
| 724 | Some(cts.map_into()), | ||
| 725 | Some(rts.map_into()), | ||
| 726 | config, | ||
| 727 | ) | ||
| 728 | } | ||
| 729 | |||
| 730 | fn new_inner( | ||
| 731 | uarte: impl Peripheral<P = U> + 'd, | ||
| 732 | timer: impl Peripheral<P = T> + 'd, | ||
| 733 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 734 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 735 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 736 | rxd: PeripheralRef<'d, AnyPin>, | ||
| 737 | txd: PeripheralRef<'d, AnyPin>, | ||
| 738 | cts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 739 | rts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 740 | config: Config, | ||
| 741 | ) -> Self { | ||
| 742 | let baudrate = config.baudrate; | ||
| 743 | let (tx, rx) = Uarte::new_inner(uarte, irq, rxd, txd, cts, rts, config).split(); | ||
| 744 | |||
| 745 | let mut timer = Timer::new(timer); | ||
| 746 | |||
| 747 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 748 | |||
| 749 | let r = U::regs(); | ||
| 750 | |||
| 751 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 752 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 753 | // | ||
| 754 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 755 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 756 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 757 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 758 | |||
| 759 | timer.set_frequency(Frequency::F16MHz); | ||
| 760 | timer.cc(0).write(timeout); | ||
| 761 | timer.cc(0).short_compare_clear(); | ||
| 762 | timer.cc(0).short_compare_stop(); | ||
| 763 | |||
| 764 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 765 | ppi_ch1.map_into(), | ||
| 766 | Event::from_reg(&r.events_rxdrdy), | ||
| 767 | timer.task_clear(), | ||
| 768 | timer.task_start(), | ||
| 769 | ); | ||
| 770 | ppi_ch1.enable(); | ||
| 771 | |||
| 772 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 773 | ppi_ch2.map_into(), | ||
| 774 | timer.cc(0).event_compare(), | ||
| 775 | Task::from_reg(&r.tasks_stoprx), | ||
| 776 | ); | ||
| 777 | ppi_ch2.enable(); | ||
| 778 | |||
| 779 | Self { | ||
| 780 | tx, | ||
| 781 | rx: UarteRxWithIdle { | ||
| 782 | rx, | ||
| 783 | timer, | ||
| 784 | ppi_ch1: ppi_ch1, | ||
| 785 | _ppi_ch2: ppi_ch2, | ||
| 786 | }, | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | /// Split the Uarte into a transmitter and receiver, which is | ||
| 791 | /// particuarly useful when having two tasks correlating to | ||
| 792 | /// transmitting and receiving. | ||
| 793 | pub fn split(self) -> (UarteTx<'d, U>, UarteRxWithIdle<'d, U, T>) { | ||
| 794 | (self.tx, self.rx) | ||
| 795 | } | ||
| 796 | |||
| 797 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 798 | self.rx.read(buffer).await | ||
| 799 | } | ||
| 800 | |||
| 801 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 802 | self.tx.write(buffer).await | ||
| 803 | } | ||
| 804 | |||
| 805 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 806 | self.rx.blocking_read(buffer) | ||
| 807 | } | ||
| 808 | |||
| 809 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 810 | self.tx.blocking_write(buffer) | ||
| 811 | } | ||
| 812 | |||
| 813 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | ||
| 814 | self.rx.read_until_idle(buffer).await | ||
| 815 | } | ||
| 816 | |||
| 817 | pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | ||
| 818 | self.rx.blocking_read_until_idle(buffer) | ||
| 819 | } | ||
| 820 | } | ||
| 821 | |||
| 822 | pub struct UarteRxWithIdle<'d, U: Instance, T: TimerInstance> { | ||
| 823 | rx: UarteRx<'d, U>, | ||
| 824 | timer: Timer<'d, T>, | ||
| 825 | ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, | 658 | ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, |
| 826 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, | 659 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, |
| 827 | } | 660 | } |
| 828 | 661 | ||
| 829 | impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | 662 | impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { |
| 830 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 663 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 831 | self.ppi_ch1.disable(); | 664 | self.ppi_ch1.disable(); |
| 832 | self.rx.read(buffer).await | 665 | self.rx.read(buffer).await |
| @@ -848,8 +681,8 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 848 | let ptr = buffer.as_ptr(); | 681 | let ptr = buffer.as_ptr(); |
| 849 | let len = buffer.len(); | 682 | let len = buffer.len(); |
| 850 | 683 | ||
| 851 | let r = U::regs(); | 684 | let r = T::regs(); |
| 852 | let s = U::state(); | 685 | let s = T::state(); |
| 853 | 686 | ||
| 854 | self.ppi_ch1.enable(); | 687 | self.ppi_ch1.enable(); |
| 855 | 688 | ||
| @@ -904,7 +737,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 904 | let ptr = buffer.as_ptr(); | 737 | let ptr = buffer.as_ptr(); |
| 905 | let len = buffer.len(); | 738 | let len = buffer.len(); |
| 906 | 739 | ||
| 907 | let r = U::regs(); | 740 | let r = T::regs(); |
| 908 | 741 | ||
| 909 | self.ppi_ch1.enable(); | 742 | self.ppi_ch1.enable(); |
| 910 | 743 | ||
| @@ -929,6 +762,75 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 929 | Ok(n) | 762 | Ok(n) |
| 930 | } | 763 | } |
| 931 | } | 764 | } |
| 765 | |||
| 766 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] | ||
| 767 | pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | ||
| 768 | // Do nothing | ||
| 769 | } | ||
| 770 | |||
| 771 | #[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] | ||
| 772 | pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { | ||
| 773 | use core::ops::Deref; | ||
| 774 | |||
| 775 | // Apply workaround for anomalies: | ||
| 776 | // - nRF9160 - anomaly 23 | ||
| 777 | // - nRF5340 - anomaly 44 | ||
| 778 | let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; | ||
| 779 | let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; | ||
| 780 | |||
| 781 | // NB Safety: This is taken from Nordic's driver - | ||
| 782 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 783 | if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||
| 784 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 785 | } | ||
| 786 | |||
| 787 | // NB Safety: This is taken from Nordic's driver - | ||
| 788 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 789 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||
| 790 | r.enable.write(|w| w.enable().enabled()); | ||
| 791 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 792 | |||
| 793 | let mut workaround_succeded = false; | ||
| 794 | // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. | ||
| 795 | // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured | ||
| 796 | // (resulting in 12 bits per data byte sent), this may take up to 40 ms. | ||
| 797 | for _ in 0..40000 { | ||
| 798 | // NB Safety: This is taken from Nordic's driver - | ||
| 799 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 800 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { | ||
| 801 | workaround_succeded = true; | ||
| 802 | break; | ||
| 803 | } else { | ||
| 804 | // Need to sleep for 1us here | ||
| 805 | } | ||
| 806 | } | ||
| 807 | |||
| 808 | if !workaround_succeded { | ||
| 809 | panic!("Failed to apply workaround for UART"); | ||
| 810 | } | ||
| 811 | |||
| 812 | let errors = r.errorsrc.read().bits(); | ||
| 813 | // NB Safety: safe to write back the bits we just read to clear them | ||
| 814 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 815 | r.enable.write(|w| w.enable().disabled()); | ||
| 816 | } | ||
| 817 | } | ||
| 818 | |||
| 819 | pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { | ||
| 820 | if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { | ||
| 821 | // Finally we can disable, and we do so for the peripheral | ||
| 822 | // i.e. not just rx concerns. | ||
| 823 | r.enable.write(|w| w.enable().disabled()); | ||
| 824 | |||
| 825 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 826 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 827 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 828 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 829 | |||
| 830 | trace!("uarte tx and rx drop: done"); | ||
| 831 | } | ||
| 832 | } | ||
| 833 | |||
| 932 | pub(crate) mod sealed { | 834 | pub(crate) mod sealed { |
| 933 | use core::sync::atomic::AtomicU8; | 835 | use core::sync::atomic::AtomicU8; |
| 934 | 836 | ||
| @@ -1006,18 +908,6 @@ mod eh02 { | |||
| 1006 | Ok(()) | 908 | Ok(()) |
| 1007 | } | 909 | } |
| 1008 | } | 910 | } |
| 1009 | |||
| 1010 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_02::blocking::serial::Write<u8> for UarteWithIdle<'d, U, T> { | ||
| 1011 | type Error = Error; | ||
| 1012 | |||
| 1013 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 1014 | self.blocking_write(buffer) | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | fn bflush(&mut self) -> Result<(), Self::Error> { | ||
| 1018 | Ok(()) | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | } | 911 | } |
| 1022 | 912 | ||
| 1023 | #[cfg(feature = "unstable-traits")] | 913 | #[cfg(feature = "unstable-traits")] |
| @@ -1067,10 +957,6 @@ mod eh1 { | |||
| 1067 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { | 957 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { |
| 1068 | type Error = Error; | 958 | type Error = Error; |
| 1069 | } | 959 | } |
| 1070 | |||
| 1071 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType for UarteWithIdle<'d, U, T> { | ||
| 1072 | type Error = Error; | ||
| 1073 | } | ||
| 1074 | } | 960 | } |
| 1075 | 961 | ||
| 1076 | #[cfg(all( | 962 | #[cfg(all( |
| @@ -1126,26 +1012,4 @@ mod eha { | |||
| 1126 | self.read(buffer) | 1012 | self.read(buffer) |
| 1127 | } | 1013 | } |
| 1128 | } | 1014 | } |
| 1129 | |||
| 1130 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read for UarteWithIdle<'d, U, T> { | ||
| 1131 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1132 | |||
| 1133 | fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 1134 | self.read(buffer) | ||
| 1135 | } | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Write for UarteWithIdle<'d, U, T> { | ||
| 1139 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1140 | |||
| 1141 | fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 1142 | self.write(buffer) | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1146 | |||
| 1147 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 1148 | async move { Ok(()) } | ||
| 1149 | } | ||
| 1150 | } | ||
| 1151 | } | 1015 | } |
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 52f910cef..68cfc653e 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | use core::future; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::task::Poll; | ||
| 2 | 4 | ||
| 5 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | 6 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 4 | use pac::i2c; | 8 | use pac::i2c; |
| 5 | 9 | ||
| 6 | use crate::dma::AnyChannel; | ||
| 7 | use crate::gpio::sealed::Pin; | 10 | use crate::gpio::sealed::Pin; |
| 8 | use crate::gpio::AnyPin; | 11 | use crate::gpio::AnyPin; |
| 9 | use crate::{pac, peripherals, Peripheral}; | 12 | use crate::{pac, peripherals, Peripheral}; |
| @@ -52,31 +55,278 @@ impl Default for Config { | |||
| 52 | const FIFO_SIZE: u8 = 16; | 55 | const FIFO_SIZE: u8 = 16; |
| 53 | 56 | ||
| 54 | pub struct I2c<'d, T: Instance, M: Mode> { | 57 | pub struct I2c<'d, T: Instance, M: Mode> { |
| 55 | _tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 56 | _rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 57 | _dma_buf: [u16; 256], | ||
| 58 | phantom: PhantomData<(&'d mut T, M)>, | 58 | phantom: PhantomData<(&'d mut T, M)>, |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | impl<'d, T: Instance> I2c<'d, T, Blocking> { | 61 | impl<'d, T: Instance> I2c<'d, T, Blocking> { |
| 62 | pub fn new_blocking( | 62 | pub fn new_blocking( |
| 63 | _peri: impl Peripheral<P = T> + 'd, | 63 | peri: impl Peripheral<P = T> + 'd, |
| 64 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | 64 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, |
| 65 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | 65 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |
| 66 | config: Config, | 66 | config: Config, |
| 67 | ) -> Self { | 67 | ) -> Self { |
| 68 | into_ref!(scl, sda); | 68 | into_ref!(scl, sda); |
| 69 | Self::new_inner(_peri, scl.map_into(), sda.map_into(), None, None, config) | 69 | Self::new_inner(peri, scl.map_into(), sda.map_into(), config) |
| 70 | } | 70 | } |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | 73 | static I2C_WAKER: AtomicWaker = AtomicWaker::new(); |
| 74 | |||
| 75 | impl<'d, T: Instance> I2c<'d, T, Async> { | ||
| 76 | pub fn new_async( | ||
| 77 | peri: impl Peripheral<P = T> + 'd, | ||
| 78 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 79 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 80 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 81 | config: Config, | ||
| 82 | ) -> Self { | ||
| 83 | into_ref!(scl, sda, irq); | ||
| 84 | |||
| 85 | let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); | ||
| 86 | |||
| 87 | irq.set_handler(Self::on_interrupt); | ||
| 88 | unsafe { | ||
| 89 | let i2c = T::regs(); | ||
| 90 | |||
| 91 | // mask everything initially | ||
| 92 | i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); | ||
| 93 | } | ||
| 94 | irq.unpend(); | ||
| 95 | debug_assert!(!irq.is_pending()); | ||
| 96 | irq.enable(); | ||
| 97 | |||
| 98 | i2c | ||
| 99 | } | ||
| 100 | |||
| 101 | /// Calls `f` to check if we are ready or not. | ||
| 102 | /// If not, `g` is called once the waker is set (to eg enable the required interrupts). | ||
| 103 | async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U | ||
| 104 | where | ||
| 105 | F: FnMut(&mut Self) -> Poll<U>, | ||
| 106 | G: FnMut(&mut Self), | ||
| 107 | { | ||
| 108 | future::poll_fn(|cx| { | ||
| 109 | let r = f(self); | ||
| 110 | |||
| 111 | if r.is_pending() { | ||
| 112 | I2C_WAKER.register(cx.waker()); | ||
| 113 | g(self); | ||
| 114 | } | ||
| 115 | r | ||
| 116 | }) | ||
| 117 | .await | ||
| 118 | } | ||
| 119 | |||
| 120 | // Mask interrupts and wake any task waiting for this interrupt | ||
| 121 | unsafe fn on_interrupt(_: *mut ()) { | ||
| 122 | let i2c = T::regs(); | ||
| 123 | i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); | ||
| 124 | |||
| 125 | I2C_WAKER.wake(); | ||
| 126 | } | ||
| 127 | |||
| 128 | async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { | ||
| 129 | if buffer.is_empty() { | ||
| 130 | return Err(Error::InvalidReadBufferLength); | ||
| 131 | } | ||
| 132 | |||
| 133 | let p = T::regs(); | ||
| 134 | |||
| 135 | let mut remaining = buffer.len(); | ||
| 136 | let mut remaining_queue = buffer.len(); | ||
| 137 | |||
| 138 | let mut abort_reason = Ok(()); | ||
| 139 | |||
| 140 | while remaining > 0 { | ||
| 141 | // Waggle SCK - basically the same as write | ||
| 142 | let tx_fifo_space = Self::tx_fifo_capacity(); | ||
| 143 | let mut batch = 0; | ||
| 144 | |||
| 145 | debug_assert!(remaining_queue > 0); | ||
| 146 | |||
| 147 | for _ in 0..remaining_queue.min(tx_fifo_space as usize) { | ||
| 148 | remaining_queue -= 1; | ||
| 149 | let last = remaining_queue == 0; | ||
| 150 | batch += 1; | ||
| 151 | |||
| 152 | unsafe { | ||
| 153 | p.ic_data_cmd().write(|w| { | ||
| 154 | w.set_restart(restart && remaining_queue == buffer.len() - 1); | ||
| 155 | w.set_stop(last && send_stop); | ||
| 156 | w.set_cmd(true); | ||
| 157 | }); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | // We've either run out of txfifo or just plain finished setting up | ||
| 162 | // the clocks for the message - either way we need to wait for rx | ||
| 163 | // data. | ||
| 164 | |||
| 165 | debug_assert!(batch > 0); | ||
| 166 | let res = self | ||
| 167 | .wait_on( | ||
| 168 | |me| { | ||
| 169 | let rxfifo = Self::rx_fifo_len(); | ||
| 170 | if let Err(abort_reason) = me.read_and_clear_abort_reason() { | ||
| 171 | Poll::Ready(Err(abort_reason)) | ||
| 172 | } else if rxfifo >= batch { | ||
| 173 | Poll::Ready(Ok(rxfifo)) | ||
| 174 | } else { | ||
| 175 | Poll::Pending | ||
| 176 | } | ||
| 177 | }, | ||
| 178 | |_me| unsafe { | ||
| 179 | // Set the read threshold to the number of bytes we're | ||
| 180 | // expecting so we don't get spurious interrupts. | ||
| 181 | p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); | ||
| 182 | |||
| 183 | p.ic_intr_mask().modify(|w| { | ||
| 184 | w.set_m_rx_full(true); | ||
| 185 | w.set_m_tx_abrt(true); | ||
| 186 | }); | ||
| 187 | }, | ||
| 188 | ) | ||
| 189 | .await; | ||
| 190 | |||
| 191 | match res { | ||
| 192 | Err(reason) => { | ||
| 193 | abort_reason = Err(reason); | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | Ok(rxfifo) => { | ||
| 197 | // Fetch things from rx fifo. We're assuming we're the only | ||
| 198 | // rxfifo reader, so nothing else can take things from it. | ||
| 199 | let rxbytes = (rxfifo as usize).min(remaining); | ||
| 200 | let received = buffer.len() - remaining; | ||
| 201 | for b in &mut buffer[received..received + rxbytes] { | ||
| 202 | *b = unsafe { p.ic_data_cmd().read().dat() }; | ||
| 203 | } | ||
| 204 | remaining -= rxbytes; | ||
| 205 | } | ||
| 206 | }; | ||
| 207 | } | ||
| 208 | |||
| 209 | self.wait_stop_det(abort_reason, send_stop).await | ||
| 210 | } | ||
| 211 | |||
| 212 | async fn write_async_internal( | ||
| 213 | &mut self, | ||
| 214 | bytes: impl IntoIterator<Item = u8>, | ||
| 215 | send_stop: bool, | ||
| 216 | ) -> Result<(), Error> { | ||
| 217 | let p = T::regs(); | ||
| 218 | |||
| 219 | let mut bytes = bytes.into_iter().peekable(); | ||
| 220 | |||
| 221 | let res = 'xmit: loop { | ||
| 222 | let tx_fifo_space = Self::tx_fifo_capacity(); | ||
| 223 | |||
| 224 | for _ in 0..tx_fifo_space { | ||
| 225 | if let Some(byte) = bytes.next() { | ||
| 226 | let last = bytes.peek().is_none(); | ||
| 227 | |||
| 228 | unsafe { | ||
| 229 | p.ic_data_cmd().write(|w| { | ||
| 230 | w.set_stop(last && send_stop); | ||
| 231 | w.set_cmd(false); | ||
| 232 | w.set_dat(byte); | ||
| 233 | }); | ||
| 234 | } | ||
| 235 | } else { | ||
| 236 | break 'xmit Ok(()); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | let res = self | ||
| 241 | .wait_on( | ||
| 242 | |me| { | ||
| 243 | if let abort_reason @ Err(_) = me.read_and_clear_abort_reason() { | ||
| 244 | Poll::Ready(abort_reason) | ||
| 245 | } else if !Self::tx_fifo_full() { | ||
| 246 | // resume if there's any space free in the tx fifo | ||
| 247 | Poll::Ready(Ok(())) | ||
| 248 | } else { | ||
| 249 | Poll::Pending | ||
| 250 | } | ||
| 251 | }, | ||
| 252 | |_me| unsafe { | ||
| 253 | // Set tx "free" threshold a little high so that we get | ||
| 254 | // woken before the fifo completely drains to minimize | ||
| 255 | // transfer stalls. | ||
| 256 | p.ic_tx_tl().write(|w| w.set_tx_tl(1)); | ||
| 257 | |||
| 258 | p.ic_intr_mask().modify(|w| { | ||
| 259 | w.set_m_tx_empty(true); | ||
| 260 | w.set_m_tx_abrt(true); | ||
| 261 | }) | ||
| 262 | }, | ||
| 263 | ) | ||
| 264 | .await; | ||
| 265 | if res.is_err() { | ||
| 266 | break res; | ||
| 267 | } | ||
| 268 | }; | ||
| 269 | |||
| 270 | self.wait_stop_det(res, send_stop).await | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Helper to wait for a stop bit, for both tx and rx. If we had an abort, | ||
| 274 | /// then we'll get a hardware-generated stop, otherwise wait for a stop if | ||
| 275 | /// we're expecting it. | ||
| 276 | /// | ||
| 277 | /// Also handles an abort which arises while processing the tx fifo. | ||
| 278 | async fn wait_stop_det(&mut self, had_abort: Result<(), Error>, do_stop: bool) -> Result<(), Error> { | ||
| 279 | if had_abort.is_err() || do_stop { | ||
| 280 | let p = T::regs(); | ||
| 281 | |||
| 282 | let had_abort2 = self | ||
| 283 | .wait_on( | ||
| 284 | |me| unsafe { | ||
| 285 | // We could see an abort while processing fifo backlog, | ||
| 286 | // so handle it here. | ||
| 287 | let abort = me.read_and_clear_abort_reason(); | ||
| 288 | if had_abort.is_ok() && abort.is_err() { | ||
| 289 | Poll::Ready(abort) | ||
| 290 | } else if p.ic_raw_intr_stat().read().stop_det() { | ||
| 291 | Poll::Ready(Ok(())) | ||
| 292 | } else { | ||
| 293 | Poll::Pending | ||
| 294 | } | ||
| 295 | }, | ||
| 296 | |_me| unsafe { | ||
| 297 | p.ic_intr_mask().modify(|w| { | ||
| 298 | w.set_m_stop_det(true); | ||
| 299 | w.set_m_tx_abrt(true); | ||
| 300 | }); | ||
| 301 | }, | ||
| 302 | ) | ||
| 303 | .await; | ||
| 304 | unsafe { | ||
| 305 | p.ic_clr_stop_det().read(); | ||
| 306 | } | ||
| 307 | |||
| 308 | had_abort.and(had_abort2) | ||
| 309 | } else { | ||
| 310 | had_abort | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 315 | Self::setup(addr)?; | ||
| 316 | self.read_async_internal(buffer, false, true).await | ||
| 317 | } | ||
| 318 | |||
| 319 | pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { | ||
| 320 | Self::setup(addr)?; | ||
| 321 | self.write_async_internal(bytes, true).await | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | ||
| 74 | fn new_inner( | 326 | fn new_inner( |
| 75 | _peri: impl Peripheral<P = T> + 'd, | 327 | _peri: impl Peripheral<P = T> + 'd, |
| 76 | scl: PeripheralRef<'d, AnyPin>, | 328 | scl: PeripheralRef<'d, AnyPin>, |
| 77 | sda: PeripheralRef<'d, AnyPin>, | 329 | sda: PeripheralRef<'d, AnyPin>, |
| 78 | _tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 79 | _rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 80 | config: Config, | 330 | config: Config, |
| 81 | ) -> Self { | 331 | ) -> Self { |
| 82 | into_ref!(_peri); | 332 | into_ref!(_peri); |
| @@ -87,6 +337,10 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 87 | let p = T::regs(); | 337 | let p = T::regs(); |
| 88 | 338 | ||
| 89 | unsafe { | 339 | unsafe { |
| 340 | let reset = T::reset(); | ||
| 341 | crate::reset::reset(reset); | ||
| 342 | crate::reset::unreset_wait(reset); | ||
| 343 | |||
| 90 | p.ic_enable().write(|w| w.set_enable(false)); | 344 | p.ic_enable().write(|w| w.set_enable(false)); |
| 91 | 345 | ||
| 92 | // Select controller mode & speed | 346 | // Select controller mode & speed |
| @@ -172,12 +426,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 172 | p.ic_enable().write(|w| w.set_enable(true)); | 426 | p.ic_enable().write(|w| w.set_enable(true)); |
| 173 | } | 427 | } |
| 174 | 428 | ||
| 175 | Self { | 429 | Self { phantom: PhantomData } |
| 176 | _tx_dma, | ||
| 177 | _rx_dma, | ||
| 178 | _dma_buf: [0; 256], | ||
| 179 | phantom: PhantomData, | ||
| 180 | } | ||
| 181 | } | 430 | } |
| 182 | 431 | ||
| 183 | fn setup(addr: u16) -> Result<(), Error> { | 432 | fn setup(addr: u16) -> Result<(), Error> { |
| @@ -198,6 +447,23 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 198 | Ok(()) | 447 | Ok(()) |
| 199 | } | 448 | } |
| 200 | 449 | ||
| 450 | #[inline] | ||
| 451 | fn tx_fifo_full() -> bool { | ||
| 452 | Self::tx_fifo_capacity() == 0 | ||
| 453 | } | ||
| 454 | |||
| 455 | #[inline] | ||
| 456 | fn tx_fifo_capacity() -> u8 { | ||
| 457 | let p = T::regs(); | ||
| 458 | unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } | ||
| 459 | } | ||
| 460 | |||
| 461 | #[inline] | ||
| 462 | fn rx_fifo_len() -> u8 { | ||
| 463 | let p = T::regs(); | ||
| 464 | unsafe { p.ic_rxflr().read().rxflr() } | ||
| 465 | } | ||
| 466 | |||
| 201 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | 467 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 202 | let p = T::regs(); | 468 | let p = T::regs(); |
| 203 | unsafe { | 469 | unsafe { |
| @@ -240,7 +506,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 240 | // NOTE(unsafe) We have &mut self | 506 | // NOTE(unsafe) We have &mut self |
| 241 | unsafe { | 507 | unsafe { |
| 242 | // wait until there is space in the FIFO to write the next byte | 508 | // wait until there is space in the FIFO to write the next byte |
| 243 | while p.ic_txflr().read().txflr() == FIFO_SIZE {} | 509 | while Self::tx_fifo_full() {} |
| 244 | 510 | ||
| 245 | p.ic_data_cmd().write(|w| { | 511 | p.ic_data_cmd().write(|w| { |
| 246 | w.set_restart(restart && first); | 512 | w.set_restart(restart && first); |
| @@ -249,7 +515,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 249 | w.set_cmd(true); | 515 | w.set_cmd(true); |
| 250 | }); | 516 | }); |
| 251 | 517 | ||
| 252 | while p.ic_rxflr().read().rxflr() == 0 { | 518 | while Self::rx_fifo_len() == 0 { |
| 253 | self.read_and_clear_abort_reason()?; | 519 | self.read_and_clear_abort_reason()?; |
| 254 | } | 520 | } |
| 255 | 521 | ||
| @@ -451,6 +717,91 @@ mod eh1 { | |||
| 451 | } | 717 | } |
| 452 | } | 718 | } |
| 453 | } | 719 | } |
| 720 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] | ||
| 721 | mod nightly { | ||
| 722 | use core::future::Future; | ||
| 723 | |||
| 724 | use embedded_hal_1::i2c::Operation; | ||
| 725 | use embedded_hal_async::i2c::AddressMode; | ||
| 726 | |||
| 727 | use super::*; | ||
| 728 | |||
| 729 | impl<'d, A, T> embedded_hal_async::i2c::I2c<A> for I2c<'d, T, Async> | ||
| 730 | where | ||
| 731 | A: AddressMode + Into<u16> + 'static, | ||
| 732 | T: Instance + 'd, | ||
| 733 | { | ||
| 734 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 735 | where Self: 'a; | ||
| 736 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 737 | where Self: 'a; | ||
| 738 | type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a | ||
| 739 | where Self: 'a; | ||
| 740 | type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Error>> + 'a | ||
| 741 | where Self: 'a, 'b: 'a; | ||
| 742 | |||
| 743 | fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 744 | let addr: u16 = address.into(); | ||
| 745 | |||
| 746 | async move { | ||
| 747 | Self::setup(addr)?; | ||
| 748 | self.read_async_internal(buffer, false, true).await | ||
| 749 | } | ||
| 750 | } | ||
| 751 | |||
| 752 | fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 753 | let addr: u16 = address.into(); | ||
| 754 | |||
| 755 | async move { | ||
| 756 | Self::setup(addr)?; | ||
| 757 | self.write_async_internal(write.iter().copied(), true).await | ||
| 758 | } | ||
| 759 | } | ||
| 760 | |||
| 761 | fn write_read<'a>( | ||
| 762 | &'a mut self, | ||
| 763 | address: A, | ||
| 764 | bytes: &'a [u8], | ||
| 765 | buffer: &'a mut [u8], | ||
| 766 | ) -> Self::WriteReadFuture<'a> { | ||
| 767 | let addr: u16 = address.into(); | ||
| 768 | |||
| 769 | async move { | ||
| 770 | Self::setup(addr)?; | ||
| 771 | self.write_async_internal(bytes.iter().cloned(), false).await?; | ||
| 772 | self.read_async_internal(buffer, false, true).await | ||
| 773 | } | ||
| 774 | } | ||
| 775 | |||
| 776 | fn transaction<'a, 'b>( | ||
| 777 | &'a mut self, | ||
| 778 | address: A, | ||
| 779 | operations: &'a mut [Operation<'b>], | ||
| 780 | ) -> Self::TransactionFuture<'a, 'b> { | ||
| 781 | let addr: u16 = address.into(); | ||
| 782 | |||
| 783 | async move { | ||
| 784 | let mut iterator = operations.iter_mut(); | ||
| 785 | |||
| 786 | while let Some(op) = iterator.next() { | ||
| 787 | let last = iterator.len() == 0; | ||
| 788 | |||
| 789 | match op { | ||
| 790 | Operation::Read(buffer) => { | ||
| 791 | Self::setup(addr)?; | ||
| 792 | self.read_async_internal(buffer, false, last).await?; | ||
| 793 | } | ||
| 794 | Operation::Write(buffer) => { | ||
| 795 | Self::setup(addr)?; | ||
| 796 | self.write_async_internal(buffer.into_iter().cloned(), last).await?; | ||
| 797 | } | ||
| 798 | } | ||
| 799 | } | ||
| 800 | Ok(()) | ||
| 801 | } | ||
| 802 | } | ||
| 803 | } | ||
| 804 | } | ||
| 454 | 805 | ||
| 455 | fn i2c_reserved_addr(addr: u16) -> bool { | 806 | fn i2c_reserved_addr(addr: u16) -> bool { |
| 456 | (addr & 0x78) == 0 || (addr & 0x78) == 0x78 | 807 | (addr & 0x78) == 0 || (addr & 0x78) == 0x78 |
| @@ -466,6 +817,7 @@ mod sealed { | |||
| 466 | type Interrupt: Interrupt; | 817 | type Interrupt: Interrupt; |
| 467 | 818 | ||
| 468 | fn regs() -> crate::pac::i2c::I2c; | 819 | fn regs() -> crate::pac::i2c::I2c; |
| 820 | fn reset() -> crate::pac::resets::regs::Peripherals; | ||
| 469 | } | 821 | } |
| 470 | 822 | ||
| 471 | pub trait Mode {} | 823 | pub trait Mode {} |
| @@ -492,23 +844,31 @@ impl_mode!(Async); | |||
| 492 | pub trait Instance: sealed::Instance {} | 844 | pub trait Instance: sealed::Instance {} |
| 493 | 845 | ||
| 494 | macro_rules! impl_instance { | 846 | macro_rules! impl_instance { |
| 495 | ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { | 847 | ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { |
| 496 | impl sealed::Instance for peripherals::$type { | 848 | impl sealed::Instance for peripherals::$type { |
| 497 | const TX_DREQ: u8 = $tx_dreq; | 849 | const TX_DREQ: u8 = $tx_dreq; |
| 498 | const RX_DREQ: u8 = $rx_dreq; | 850 | const RX_DREQ: u8 = $rx_dreq; |
| 499 | 851 | ||
| 500 | type Interrupt = crate::interrupt::$irq; | 852 | type Interrupt = crate::interrupt::$irq; |
| 501 | 853 | ||
| 854 | #[inline] | ||
| 502 | fn regs() -> pac::i2c::I2c { | 855 | fn regs() -> pac::i2c::I2c { |
| 503 | pac::$type | 856 | pac::$type |
| 504 | } | 857 | } |
| 858 | |||
| 859 | #[inline] | ||
| 860 | fn reset() -> pac::resets::regs::Peripherals { | ||
| 861 | let mut ret = pac::resets::regs::Peripherals::default(); | ||
| 862 | ret.$reset(true); | ||
| 863 | ret | ||
| 864 | } | ||
| 505 | } | 865 | } |
| 506 | impl Instance for peripherals::$type {} | 866 | impl Instance for peripherals::$type {} |
| 507 | }; | 867 | }; |
| 508 | } | 868 | } |
| 509 | 869 | ||
| 510 | impl_instance!(I2C0, I2C0_IRQ, 32, 33); | 870 | impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); |
| 511 | impl_instance!(I2C1, I2C1_IRQ, 34, 35); | 871 | impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); |
| 512 | 872 | ||
| 513 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | 873 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} |
| 514 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | 874 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} |
diff --git a/examples/nrf/src/bin/uart_idle.rs b/examples/nrf/src/bin/uart_idle.rs index 09ec624c0..6af4f7097 100644 --- a/examples/nrf/src/bin/uart_idle.rs +++ b/examples/nrf/src/bin/uart_idle.rs | |||
| @@ -15,7 +15,8 @@ async fn main(_spawner: Spawner) { | |||
| 15 | config.baudrate = uarte::Baudrate::BAUD115200; | 15 | config.baudrate = uarte::Baudrate::BAUD115200; |
| 16 | 16 | ||
| 17 | let irq = interrupt::take!(UARTE0_UART0); | 17 | let irq = interrupt::take!(UARTE0_UART0); |
| 18 | let mut uart = uarte::UarteWithIdle::new(p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, config); | 18 | let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config); |
| 19 | let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1); | ||
| 19 | 20 | ||
| 20 | info!("uarte initialized!"); | 21 | info!("uarte initialized!"); |
| 21 | 22 | ||
| @@ -23,12 +24,12 @@ async fn main(_spawner: Spawner) { | |||
| 23 | let mut buf = [0; 8]; | 24 | let mut buf = [0; 8]; |
| 24 | buf.copy_from_slice(b"Hello!\r\n"); | 25 | buf.copy_from_slice(b"Hello!\r\n"); |
| 25 | 26 | ||
| 26 | unwrap!(uart.write(&buf).await); | 27 | unwrap!(tx.write(&buf).await); |
| 27 | info!("wrote hello in uart!"); | 28 | info!("wrote hello in uart!"); |
| 28 | 29 | ||
| 29 | loop { | 30 | loop { |
| 30 | info!("reading..."); | 31 | info!("reading..."); |
| 31 | let n = unwrap!(uart.read_until_idle(&mut buf).await); | 32 | let n = unwrap!(rx.read_until_idle(&mut buf).await); |
| 32 | info!("got {} bytes", n); | 33 | info!("got {} bytes", n); |
| 33 | } | 34 | } |
| 34 | } | 35 | } |
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index a5af8b2f0..747dde515 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -31,3 +31,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | |||
| 31 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 31 | embedded-hal-async = { version = "0.1.0-alpha.1" } |
| 32 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } | 32 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } |
| 33 | static_cell = "1.0.0" | 33 | static_cell = "1.0.0" |
| 34 | |||
| 35 | [profile.release] | ||
| 36 | debug = true | ||
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs new file mode 100644 index 000000000..d1a2e3cd7 --- /dev/null +++ b/examples/rp/src/bin/i2c_async.rs | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::i2c::{self, Config}; | ||
| 8 | use embassy_rp::interrupt; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use embedded_hal_async::i2c::I2c; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[allow(dead_code)] | ||
| 14 | mod mcp23017 { | ||
| 15 | pub const ADDR: u8 = 0x20; // default addr | ||
| 16 | |||
| 17 | macro_rules! mcpregs { | ||
| 18 | ($($name:ident : $val:expr),* $(,)?) => { | ||
| 19 | $( | ||
| 20 | pub const $name: u8 = $val; | ||
| 21 | )* | ||
| 22 | |||
| 23 | pub fn regname(reg: u8) -> &'static str { | ||
| 24 | match reg { | ||
| 25 | $( | ||
| 26 | $val => stringify!($name), | ||
| 27 | )* | ||
| 28 | _ => panic!("bad reg"), | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | // These are correct for IOCON.BANK=0 | ||
| 35 | mcpregs! { | ||
| 36 | IODIRA: 0x00, | ||
| 37 | IPOLA: 0x02, | ||
| 38 | GPINTENA: 0x04, | ||
| 39 | DEFVALA: 0x06, | ||
| 40 | INTCONA: 0x08, | ||
| 41 | IOCONA: 0x0A, | ||
| 42 | GPPUA: 0x0C, | ||
| 43 | INTFA: 0x0E, | ||
| 44 | INTCAPA: 0x10, | ||
| 45 | GPIOA: 0x12, | ||
| 46 | OLATA: 0x14, | ||
| 47 | IODIRB: 0x01, | ||
| 48 | IPOLB: 0x03, | ||
| 49 | GPINTENB: 0x05, | ||
| 50 | DEFVALB: 0x07, | ||
| 51 | INTCONB: 0x09, | ||
| 52 | IOCONB: 0x0B, | ||
| 53 | GPPUB: 0x0D, | ||
| 54 | INTFB: 0x0F, | ||
| 55 | INTCAPB: 0x11, | ||
| 56 | GPIOB: 0x13, | ||
| 57 | OLATB: 0x15, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[embassy_executor::main] | ||
| 62 | async fn main(_spawner: Spawner) { | ||
| 63 | let p = embassy_rp::init(Default::default()); | ||
| 64 | |||
| 65 | let sda = p.PIN_14; | ||
| 66 | let scl = p.PIN_15; | ||
| 67 | let irq = interrupt::take!(I2C1_IRQ); | ||
| 68 | |||
| 69 | info!("set up i2c "); | ||
| 70 | let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, irq, Config::default()); | ||
| 71 | |||
| 72 | use mcp23017::*; | ||
| 73 | |||
| 74 | info!("init mcp23017 config for IxpandO"); | ||
| 75 | // init - a outputs, b inputs | ||
| 76 | i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap(); | ||
| 77 | i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap(); | ||
| 78 | i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups | ||
| 79 | |||
| 80 | let mut val = 1; | ||
| 81 | loop { | ||
| 82 | let mut portb = [0]; | ||
| 83 | |||
| 84 | i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap(); | ||
| 85 | info!("portb = {:02x}", portb[0]); | ||
| 86 | i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap(); | ||
| 87 | val = val.rotate_left(1); | ||
| 88 | |||
| 89 | // get a register dump | ||
| 90 | info!("getting register dump"); | ||
| 91 | let mut regs = [0; 22]; | ||
| 92 | i2c.write_read(ADDR, &[0], &mut regs).await.unwrap(); | ||
| 93 | // always get the regdump but only display it if portb'0 is set | ||
| 94 | if portb[0] & 1 != 0 { | ||
| 95 | for (idx, reg) in regs.into_iter().enumerate() { | ||
| 96 | info!("{} => {:02x}", regname(idx as u8), reg); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | Timer::after(Duration::from_millis(100)).await; | ||
| 101 | } | ||
| 102 | } | ||
