diff options
| -rw-r--r-- | embassy-rp/Cargo.toml | 2 | ||||
| -rw-r--r-- | embassy-rp/src/adc.rs | 120 | ||||
| -rw-r--r-- | embassy-rp/src/clocks.rs | 82 | ||||
| -rw-r--r-- | embassy-rp/src/critical_section_impl.rs | 19 | ||||
| -rw-r--r-- | embassy-rp/src/dma.rs | 48 | ||||
| -rw-r--r-- | embassy-rp/src/flash.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/float/div.rs | 78 | ||||
| -rw-r--r-- | embassy-rp/src/gpio.rs | 170 | ||||
| -rw-r--r-- | embassy-rp/src/i2c.rs | 334 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 30 | ||||
| -rw-r--r-- | embassy-rp/src/multicore.rs | 56 | ||||
| -rw-r--r-- | embassy-rp/src/pio.rs | 450 | ||||
| -rw-r--r-- | embassy-rp/src/pwm.rs | 90 | ||||
| -rw-r--r-- | embassy-rp/src/reset.rs | 4 | ||||
| -rw-r--r-- | embassy-rp/src/rtc/mod.rs | 89 | ||||
| -rw-r--r-- | embassy-rp/src/spi.rs | 219 | ||||
| -rw-r--r-- | embassy-rp/src/timer.rs | 30 | ||||
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 269 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 307 | ||||
| -rw-r--r-- | embassy-rp/src/usb.rs | 295 | ||||
| -rw-r--r-- | embassy-rp/src/watchdog.rs | 60 | ||||
| -rw-r--r-- | tests/rp/src/bin/float.rs | 10 |
22 files changed, 1255 insertions, 1509 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index b68f95385..49aa6a4d5 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -76,7 +76,7 @@ embedded-storage = { version = "0.3" } | |||
| 76 | rand_core = "0.6.4" | 76 | rand_core = "0.6.4" |
| 77 | fixed = "1.23.1" | 77 | fixed = "1.23.1" |
| 78 | 78 | ||
| 79 | rp-pac = { version = "4" } | 79 | rp-pac = { version = "5" } |
| 80 | 80 | ||
| 81 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 81 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 82 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} | 82 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} |
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index f29c4dfe1..b96d5a4a8 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs | |||
| @@ -50,16 +50,14 @@ impl<'d> Adc<'d> { | |||
| 50 | _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, | 50 | _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, |
| 51 | _config: Config, | 51 | _config: Config, |
| 52 | ) -> Self { | 52 | ) -> Self { |
| 53 | unsafe { | 53 | let reset = Self::reset(); |
| 54 | let reset = Self::reset(); | 54 | crate::reset::reset(reset); |
| 55 | crate::reset::reset(reset); | 55 | crate::reset::unreset_wait(reset); |
| 56 | crate::reset::unreset_wait(reset); | 56 | let r = Self::regs(); |
| 57 | let r = Self::regs(); | 57 | // Enable ADC |
| 58 | // Enable ADC | 58 | r.cs().write(|w| w.set_en(true)); |
| 59 | r.cs().write(|w| w.set_en(true)); | 59 | // Wait for ADC ready |
| 60 | // Wait for ADC ready | 60 | while !r.cs().read().ready() {} |
| 61 | while !r.cs().read().ready() {} | ||
| 62 | } | ||
| 63 | 61 | ||
| 64 | // Setup IRQ | 62 | // Setup IRQ |
| 65 | interrupt::ADC_IRQ_FIFO.unpend(); | 63 | interrupt::ADC_IRQ_FIFO.unpend(); |
| @@ -70,80 +68,70 @@ impl<'d> Adc<'d> { | |||
| 70 | 68 | ||
| 71 | async fn wait_for_ready() { | 69 | async fn wait_for_ready() { |
| 72 | let r = Self::regs(); | 70 | let r = Self::regs(); |
| 73 | unsafe { | 71 | r.inte().write(|w| w.set_fifo(true)); |
| 74 | r.inte().write(|w| w.set_fifo(true)); | 72 | compiler_fence(Ordering::SeqCst); |
| 75 | compiler_fence(Ordering::SeqCst); | 73 | poll_fn(|cx| { |
| 76 | poll_fn(|cx| { | 74 | WAKER.register(cx.waker()); |
| 77 | WAKER.register(cx.waker()); | 75 | if r.cs().read().ready() { |
| 78 | if r.cs().read().ready() { | 76 | return Poll::Ready(()); |
| 79 | return Poll::Ready(()); | 77 | } |
| 80 | } | 78 | Poll::Pending |
| 81 | Poll::Pending | 79 | }) |
| 82 | }) | 80 | .await; |
| 83 | .await; | ||
| 84 | } | ||
| 85 | } | 81 | } |
| 86 | 82 | ||
| 87 | pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { | 83 | pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { |
| 88 | let r = Self::regs(); | 84 | let r = Self::regs(); |
| 89 | unsafe { | 85 | // disable pull-down and pull-up resistors |
| 90 | // disable pull-down and pull-up resistors | 86 | // pull-down resistors are enabled by default |
| 91 | // pull-down resistors are enabled by default | 87 | pin.pad_ctrl().modify(|w| { |
| 92 | pin.pad_ctrl().modify(|w| { | 88 | w.set_ie(true); |
| 93 | w.set_ie(true); | 89 | let (pu, pd) = (false, false); |
| 94 | let (pu, pd) = (false, false); | 90 | w.set_pue(pu); |
| 95 | w.set_pue(pu); | 91 | w.set_pde(pd); |
| 96 | w.set_pde(pd); | 92 | }); |
| 97 | }); | 93 | r.cs().modify(|w| { |
| 98 | r.cs().modify(|w| { | 94 | w.set_ainsel(PIN::channel()); |
| 99 | w.set_ainsel(PIN::channel()); | 95 | w.set_start_once(true) |
| 100 | w.set_start_once(true) | 96 | }); |
| 101 | }); | 97 | Self::wait_for_ready().await; |
| 102 | Self::wait_for_ready().await; | 98 | r.result().read().result().into() |
| 103 | r.result().read().result().into() | ||
| 104 | } | ||
| 105 | } | 99 | } |
| 106 | 100 | ||
| 107 | pub async fn read_temperature(&mut self) -> u16 { | 101 | pub async fn read_temperature(&mut self) -> u16 { |
| 108 | let r = Self::regs(); | 102 | let r = Self::regs(); |
| 109 | unsafe { | 103 | r.cs().modify(|w| w.set_ts_en(true)); |
| 110 | r.cs().modify(|w| w.set_ts_en(true)); | 104 | if !r.cs().read().ready() { |
| 111 | if !r.cs().read().ready() { | ||
| 112 | Self::wait_for_ready().await; | ||
| 113 | } | ||
| 114 | r.cs().modify(|w| { | ||
| 115 | w.set_ainsel(4); | ||
| 116 | w.set_start_once(true) | ||
| 117 | }); | ||
| 118 | Self::wait_for_ready().await; | 105 | Self::wait_for_ready().await; |
| 119 | r.result().read().result().into() | ||
| 120 | } | 106 | } |
| 107 | r.cs().modify(|w| { | ||
| 108 | w.set_ainsel(4); | ||
| 109 | w.set_start_once(true) | ||
| 110 | }); | ||
| 111 | Self::wait_for_ready().await; | ||
| 112 | r.result().read().result().into() | ||
| 121 | } | 113 | } |
| 122 | 114 | ||
| 123 | pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { | 115 | pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { |
| 124 | let r = Self::regs(); | 116 | let r = Self::regs(); |
| 125 | unsafe { | 117 | r.cs().modify(|w| { |
| 126 | r.cs().modify(|w| { | 118 | w.set_ainsel(PIN::channel()); |
| 127 | w.set_ainsel(PIN::channel()); | 119 | w.set_start_once(true) |
| 128 | w.set_start_once(true) | 120 | }); |
| 129 | }); | 121 | while !r.cs().read().ready() {} |
| 130 | while !r.cs().read().ready() {} | 122 | r.result().read().result().into() |
| 131 | r.result().read().result().into() | ||
| 132 | } | ||
| 133 | } | 123 | } |
| 134 | 124 | ||
| 135 | pub fn blocking_read_temperature(&mut self) -> u16 { | 125 | pub fn blocking_read_temperature(&mut self) -> u16 { |
| 136 | let r = Self::regs(); | 126 | let r = Self::regs(); |
| 137 | unsafe { | 127 | r.cs().modify(|w| w.set_ts_en(true)); |
| 138 | r.cs().modify(|w| w.set_ts_en(true)); | 128 | while !r.cs().read().ready() {} |
| 139 | while !r.cs().read().ready() {} | 129 | r.cs().modify(|w| { |
| 140 | r.cs().modify(|w| { | 130 | w.set_ainsel(4); |
| 141 | w.set_ainsel(4); | 131 | w.set_start_once(true) |
| 142 | w.set_start_once(true) | 132 | }); |
| 143 | }); | 133 | while !r.cs().read().ready() {} |
| 144 | while !r.cs().read().ready() {} | 134 | r.result().read().result().into() |
| 145 | r.result().read().result().into() | ||
| 146 | } | ||
| 147 | } | 135 | } |
| 148 | } | 136 | } |
| 149 | 137 | ||
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 67439fda3..4c6223107 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs | |||
| @@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { | |||
| 542 | reset::unreset_wait(peris); | 542 | reset::unreset_wait(peris); |
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | unsafe fn configure_rosc(config: RoscConfig) -> u32 { | 545 | fn configure_rosc(config: RoscConfig) -> u32 { |
| 546 | let p = pac::ROSC; | 546 | let p = pac::ROSC; |
| 547 | 547 | ||
| 548 | p.freqa().write(|w| { | 548 | p.freqa().write(|w| { |
| @@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 { | |||
| 620 | CLOCKS.rtc.load(Ordering::Relaxed) | 620 | CLOCKS.rtc.load(Ordering::Relaxed) |
| 621 | } | 621 | } |
| 622 | 622 | ||
| 623 | unsafe fn start_xosc(crystal_hz: u32) { | 623 | fn start_xosc(crystal_hz: u32) { |
| 624 | pac::XOSC | 624 | pac::XOSC |
| 625 | .ctrl() | 625 | .ctrl() |
| 626 | .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); | 626 | .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); |
| @@ -635,7 +635,7 @@ unsafe fn start_xosc(crystal_hz: u32) { | |||
| 635 | } | 635 | } |
| 636 | 636 | ||
| 637 | #[inline(always)] | 637 | #[inline(always)] |
| 638 | unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { | 638 | fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { |
| 639 | let ref_freq = input_freq / config.refdiv as u32; | 639 | let ref_freq = input_freq / config.refdiv as u32; |
| 640 | assert!(config.fbdiv >= 16 && config.fbdiv <= 320); | 640 | assert!(config.fbdiv >= 16 && config.fbdiv <= 320); |
| 641 | assert!(config.post_div1 >= 1 && config.post_div1 <= 7); | 641 | assert!(config.post_div1 >= 1 && config.post_div1 <= 7); |
| @@ -700,9 +700,7 @@ impl<'d, T: Pin> Gpin<'d, T> { | |||
| 700 | pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { | 700 | pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { |
| 701 | into_ref!(gpin); | 701 | into_ref!(gpin); |
| 702 | 702 | ||
| 703 | unsafe { | 703 | gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); |
| 704 | gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); | ||
| 705 | } | ||
| 706 | 704 | ||
| 707 | Gpin { | 705 | Gpin { |
| 708 | gpin: gpin.map_into(), | 706 | gpin: gpin.map_into(), |
| @@ -717,12 +715,10 @@ impl<'d, T: Pin> Gpin<'d, T> { | |||
| 717 | 715 | ||
| 718 | impl<'d, T: Pin> Drop for Gpin<'d, T> { | 716 | impl<'d, T: Pin> Drop for Gpin<'d, T> { |
| 719 | fn drop(&mut self) { | 717 | fn drop(&mut self) { |
| 720 | unsafe { | 718 | self.gpin |
| 721 | self.gpin | 719 | .io() |
| 722 | .io() | 720 | .ctrl() |
| 723 | .ctrl() | 721 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); |
| 724 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); | ||
| 725 | } | ||
| 726 | } | 722 | } |
| 727 | } | 723 | } |
| 728 | 724 | ||
| @@ -768,53 +764,43 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||
| 768 | pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { | 764 | pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { |
| 769 | into_ref!(gpout); | 765 | into_ref!(gpout); |
| 770 | 766 | ||
| 771 | unsafe { | 767 | gpout.io().ctrl().write(|w| w.set_funcsel(0x08)); |
| 772 | gpout.io().ctrl().write(|w| w.set_funcsel(0x08)); | ||
| 773 | } | ||
| 774 | 768 | ||
| 775 | Self { gpout } | 769 | Self { gpout } |
| 776 | } | 770 | } |
| 777 | 771 | ||
| 778 | pub fn set_div(&self, int: u32, frac: u8) { | 772 | pub fn set_div(&self, int: u32, frac: u8) { |
| 779 | unsafe { | 773 | let c = pac::CLOCKS; |
| 780 | let c = pac::CLOCKS; | 774 | c.clk_gpout_div(self.gpout.number()).write(|w| { |
| 781 | c.clk_gpout_div(self.gpout.number()).write(|w| { | 775 | w.set_int(int); |
| 782 | w.set_int(int); | 776 | w.set_frac(frac); |
| 783 | w.set_frac(frac); | 777 | }); |
| 784 | }); | ||
| 785 | } | ||
| 786 | } | 778 | } |
| 787 | 779 | ||
| 788 | pub fn set_src(&self, src: GpoutSrc) { | 780 | pub fn set_src(&self, src: GpoutSrc) { |
| 789 | unsafe { | 781 | let c = pac::CLOCKS; |
| 790 | let c = pac::CLOCKS; | 782 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |
| 791 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | 783 | w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); |
| 792 | w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); | 784 | }); |
| 793 | }); | ||
| 794 | } | ||
| 795 | } | 785 | } |
| 796 | 786 | ||
| 797 | pub fn enable(&self) { | 787 | pub fn enable(&self) { |
| 798 | unsafe { | 788 | let c = pac::CLOCKS; |
| 799 | let c = pac::CLOCKS; | 789 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |
| 800 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | 790 | w.set_enable(true); |
| 801 | w.set_enable(true); | 791 | }); |
| 802 | }); | ||
| 803 | } | ||
| 804 | } | 792 | } |
| 805 | 793 | ||
| 806 | pub fn disable(&self) { | 794 | pub fn disable(&self) { |
| 807 | unsafe { | 795 | let c = pac::CLOCKS; |
| 808 | let c = pac::CLOCKS; | 796 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |
| 809 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | 797 | w.set_enable(false); |
| 810 | w.set_enable(false); | 798 | }); |
| 811 | }); | ||
| 812 | } | ||
| 813 | } | 799 | } |
| 814 | 800 | ||
| 815 | pub fn get_freq(&self) -> u32 { | 801 | pub fn get_freq(&self) -> u32 { |
| 816 | let c = pac::CLOCKS; | 802 | let c = pac::CLOCKS; |
| 817 | let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() }; | 803 | let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc(); |
| 818 | 804 | ||
| 819 | let base = match src { | 805 | let base = match src { |
| 820 | ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), | 806 | ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), |
| @@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||
| 831 | _ => unreachable!(), | 817 | _ => unreachable!(), |
| 832 | }; | 818 | }; |
| 833 | 819 | ||
| 834 | let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; | 820 | let div = c.clk_gpout_div(self.gpout.number()).read(); |
| 835 | let int = if div.int() == 0 { 65536 } else { div.int() } as u64; | 821 | let int = if div.int() == 0 { 65536 } else { div.int() } as u64; |
| 836 | let frac = div.frac() as u64; | 822 | let frac = div.frac() as u64; |
| 837 | 823 | ||
| @@ -842,12 +828,10 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||
| 842 | impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { | 828 | impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { |
| 843 | fn drop(&mut self) { | 829 | fn drop(&mut self) { |
| 844 | self.disable(); | 830 | self.disable(); |
| 845 | unsafe { | 831 | self.gpout |
| 846 | self.gpout | 832 | .io() |
| 847 | .io() | 833 | .ctrl() |
| 848 | .ctrl() | 834 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); |
| 849 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); | ||
| 850 | } | ||
| 851 | } | 835 | } |
| 852 | } | 836 | } |
| 853 | 837 | ||
| @@ -864,7 +848,7 @@ impl RoscRng { | |||
| 864 | let mut acc = 0; | 848 | let mut acc = 0; |
| 865 | for _ in 0..u8::BITS { | 849 | for _ in 0..u8::BITS { |
| 866 | acc <<= 1; | 850 | acc <<= 1; |
| 867 | acc |= unsafe { random_reg.read().randombit() as u8 }; | 851 | acc |= random_reg.read().randombit() as u8; |
| 868 | } | 852 | } |
| 869 | acc | 853 | acc |
| 870 | } | 854 | } |
diff --git a/embassy-rp/src/critical_section_impl.rs b/embassy-rp/src/critical_section_impl.rs index ce284c856..d233e6fab 100644 --- a/embassy-rp/src/critical_section_impl.rs +++ b/embassy-rp/src/critical_section_impl.rs | |||
| @@ -103,14 +103,11 @@ where | |||
| 103 | /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is | 103 | /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is |
| 104 | /// already in use somewhere else. | 104 | /// already in use somewhere else. |
| 105 | pub fn try_claim() -> Option<Self> { | 105 | pub fn try_claim() -> Option<Self> { |
| 106 | // Safety: We're only reading from this register | 106 | let lock = pac::SIO.spinlock(N).read(); |
| 107 | unsafe { | 107 | if lock > 0 { |
| 108 | let lock = pac::SIO.spinlock(N).read(); | 108 | Some(Self(core::marker::PhantomData)) |
| 109 | if lock > 0 { | 109 | } else { |
| 110 | Some(Self(core::marker::PhantomData)) | 110 | None |
| 111 | } else { | ||
| 112 | None | ||
| 113 | } | ||
| 114 | } | 111 | } |
| 115 | } | 112 | } |
| 116 | 113 | ||
| @@ -120,10 +117,8 @@ where | |||
| 120 | /// | 117 | /// |
| 121 | /// Only call this function if you hold the spin-lock. | 118 | /// Only call this function if you hold the spin-lock. |
| 122 | pub unsafe fn release() { | 119 | pub unsafe fn release() { |
| 123 | unsafe { | 120 | // Write (any value): release the lock |
| 124 | // Write (any value): release the lock | 121 | pac::SIO.spinlock(N).write_value(1); |
| 125 | pac::SIO.spinlock(N).write_value(1); | ||
| 126 | } | ||
| 127 | } | 122 | } |
| 128 | } | 123 | } |
| 129 | 124 | ||
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 25819f03e..1a458778c 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -14,7 +14,7 @@ use crate::{interrupt, pac, peripherals}; | |||
| 14 | 14 | ||
| 15 | #[cfg(feature = "rt")] | 15 | #[cfg(feature = "rt")] |
| 16 | #[interrupt] | 16 | #[interrupt] |
| 17 | unsafe fn DMA_IRQ_0() { | 17 | fn DMA_IRQ_0() { |
| 18 | let ints0 = pac::DMA.ints0().read().ints0(); | 18 | let ints0 = pac::DMA.ints0().read().ints0(); |
| 19 | for channel in 0..CHANNEL_COUNT { | 19 | for channel in 0..CHANNEL_COUNT { |
| 20 | let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); | 20 | let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); |
| @@ -128,28 +128,26 @@ fn copy_inner<'a, C: Channel>( | |||
| 128 | ) -> Transfer<'a, C> { | 128 | ) -> Transfer<'a, C> { |
| 129 | into_ref!(ch); | 129 | into_ref!(ch); |
| 130 | 130 | ||
| 131 | unsafe { | 131 | let p = ch.regs(); |
| 132 | let p = ch.regs(); | ||
| 133 | 132 | ||
| 134 | p.read_addr().write_value(from as u32); | 133 | p.read_addr().write_value(from as u32); |
| 135 | p.write_addr().write_value(to as u32); | 134 | p.write_addr().write_value(to as u32); |
| 136 | p.trans_count().write_value(len as u32); | 135 | p.trans_count().write_value(len as u32); |
| 137 | 136 | ||
| 138 | compiler_fence(Ordering::SeqCst); | 137 | compiler_fence(Ordering::SeqCst); |
| 139 | 138 | ||
| 140 | p.ctrl_trig().write(|w| { | 139 | p.ctrl_trig().write(|w| { |
| 141 | // TODO: Add all DREQ options to pac vals::TreqSel, and use | 140 | // TODO: Add all DREQ options to pac vals::TreqSel, and use |
| 142 | // `set_treq:sel` | 141 | // `set_treq:sel` |
| 143 | w.0 = ((dreq as u32) & 0x3f) << 15usize; | 142 | w.0 = ((dreq as u32) & 0x3f) << 15usize; |
| 144 | w.set_data_size(data_size); | 143 | w.set_data_size(data_size); |
| 145 | w.set_incr_read(incr_read); | 144 | w.set_incr_read(incr_read); |
| 146 | w.set_incr_write(incr_write); | 145 | w.set_incr_write(incr_write); |
| 147 | w.set_chain_to(ch.number()); | 146 | w.set_chain_to(ch.number()); |
| 148 | w.set_en(true); | 147 | w.set_en(true); |
| 149 | }); | 148 | }); |
| 150 | 149 | ||
| 151 | compiler_fence(Ordering::SeqCst); | 150 | compiler_fence(Ordering::SeqCst); |
| 152 | } | ||
| 153 | Transfer::new(ch) | 151 | Transfer::new(ch) |
| 154 | } | 152 | } |
| 155 | 153 | ||
| @@ -169,12 +167,10 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 169 | impl<'a, C: Channel> Drop for Transfer<'a, C> { | 167 | impl<'a, C: Channel> Drop for Transfer<'a, C> { |
| 170 | fn drop(&mut self) { | 168 | fn drop(&mut self) { |
| 171 | let p = self.channel.regs(); | 169 | let p = self.channel.regs(); |
| 172 | unsafe { | 170 | pac::DMA |
| 173 | pac::DMA | 171 | .chan_abort() |
| 174 | .chan_abort() | 172 | .modify(|m| m.set_chan_abort(1 << self.channel.number())); |
| 175 | .modify(|m| m.set_chan_abort(1 << self.channel.number())); | 173 | while p.ctrl_trig().read().busy() {} |
| 176 | while p.ctrl_trig().read().busy() {} | ||
| 177 | } | ||
| 178 | } | 174 | } |
| 179 | } | 175 | } |
| 180 | 176 | ||
| @@ -186,7 +182,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { | |||
| 186 | // calls to wake will deregister the waker. | 182 | // calls to wake will deregister the waker. |
| 187 | CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); | 183 | CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); |
| 188 | 184 | ||
| 189 | if unsafe { self.channel.regs().ctrl_trig().read().busy() } { | 185 | if self.channel.regs().ctrl_trig().read().busy() { |
| 190 | Poll::Pending | 186 | Poll::Pending |
| 191 | } else { | 187 | } else { |
| 192 | Poll::Ready(()) | 188 | Poll::Ready(()) |
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 5d928abad..96d2d4541 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs | |||
| @@ -167,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 167 | /// - DMA must not access flash memory | 167 | /// - DMA must not access flash memory |
| 168 | unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { | 168 | unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { |
| 169 | // Make sure we're running on CORE0 | 169 | // Make sure we're running on CORE0 |
| 170 | let core_id: u32 = unsafe { pac::SIO.cpuid().read() }; | 170 | let core_id: u32 = pac::SIO.cpuid().read(); |
| 171 | if core_id != 0 { | 171 | if core_id != 0 { |
| 172 | return Err(Error::InvalidCore); | 172 | return Err(Error::InvalidCore); |
| 173 | } | 173 | } |
diff --git a/embassy-rp/src/float/div.rs b/embassy-rp/src/float/div.rs index 094dec446..aff0dcb07 100644 --- a/embassy-rp/src/float/div.rs +++ b/embassy-rp/src/float/div.rs | |||
| @@ -17,45 +17,43 @@ where | |||
| 17 | { | 17 | { |
| 18 | let sio = rp_pac::SIO; | 18 | let sio = rp_pac::SIO; |
| 19 | 19 | ||
| 20 | unsafe { | 20 | // Since we can't save the signed-ness of the calculation, we have to make |
| 21 | // Since we can't save the signed-ness of the calculation, we have to make | 21 | // sure that there's at least an 8 cycle delay before we read the result. |
| 22 | // sure that there's at least an 8 cycle delay before we read the result. | 22 | // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. |
| 23 | // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. | 23 | // Since we can't be sure the Rust implementation will optimize to the same, |
| 24 | // Since we can't be sure the Rust implementation will optimize to the same, | 24 | // just use an explicit wait. |
| 25 | // just use an explicit wait. | 25 | while !sio.div().csr().read().ready() {} |
| 26 | while !sio.div().csr().read().ready() {} | 26 | |
| 27 | 27 | // Read the quotient last, since that's what clears the dirty flag | |
| 28 | // Read the quotient last, since that's what clears the dirty flag | 28 | let dividend = sio.div().udividend().read(); |
| 29 | let dividend = sio.div().udividend().read(); | 29 | let divisor = sio.div().udivisor().read(); |
| 30 | let divisor = sio.div().udivisor().read(); | 30 | let remainder = sio.div().remainder().read(); |
| 31 | let remainder = sio.div().remainder().read(); | 31 | let quotient = sio.div().quotient().read(); |
| 32 | let quotient = sio.div().quotient().read(); | 32 | |
| 33 | 33 | // If we get interrupted here (before a write sets the DIRTY flag) its fine, since | |
| 34 | // If we get interrupted here (before a write sets the DIRTY flag) its fine, since | 34 | // we have the full state, so the interruptor doesn't have to restore it. Once the |
| 35 | // we have the full state, so the interruptor doesn't have to restore it. Once the | 35 | // write happens and the DIRTY flag is set, the interruptor becomes responsible for |
| 36 | // write happens and the DIRTY flag is set, the interruptor becomes responsible for | 36 | // restoring our state. |
| 37 | // restoring our state. | 37 | let result = f(); |
| 38 | let result = f(); | 38 | |
| 39 | 39 | // If we are interrupted here, then the interruptor will start an incorrect calculation | |
| 40 | // If we are interrupted here, then the interruptor will start an incorrect calculation | 40 | // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. |
| 41 | // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. | 41 | // This sets DIRTY, so any interruptor will save the state. |
| 42 | // This sets DIRTY, so any interruptor will save the state. | 42 | sio.div().udividend().write_value(dividend); |
| 43 | sio.div().udividend().write_value(dividend); | 43 | // If we are interrupted here, the the interruptor may start the calculation using |
| 44 | // If we are interrupted here, the the interruptor may start the calculation using | 44 | // incorrectly signed inputs, but we'll restore the result ourselves. |
| 45 | // incorrectly signed inputs, but we'll restore the result ourselves. | 45 | // This sets DIRTY, so any interruptor will save the state. |
| 46 | // This sets DIRTY, so any interruptor will save the state. | 46 | sio.div().udivisor().write_value(divisor); |
| 47 | sio.div().udivisor().write_value(divisor); | 47 | // If we are interrupted here, the interruptor will have restored everything but the |
| 48 | // If we are interrupted here, the interruptor will have restored everything but the | 48 | // quotient may be wrongly signed. If the calculation started by the above writes is |
| 49 | // quotient may be wrongly signed. If the calculation started by the above writes is | 49 | // still ongoing it is stopped, so it won't replace the result we're restoring. |
| 50 | // still ongoing it is stopped, so it won't replace the result we're restoring. | 50 | // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. |
| 51 | // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. | 51 | sio.div().remainder().write_value(remainder); |
| 52 | sio.div().remainder().write_value(remainder); | 52 | // State fully restored after the quotient write. This sets both DIRTY and READY, so |
| 53 | // State fully restored after the quotient write. This sets both DIRTY and READY, so | 53 | // whatever we may have interrupted can read the result. |
| 54 | // whatever we may have interrupted can read the result. | 54 | sio.div().quotient().write_value(quotient); |
| 55 | sio.div().quotient().write_value(quotient); | 55 | |
| 56 | 56 | result | |
| 57 | result | ||
| 58 | } | ||
| 59 | } | 57 | } |
| 60 | 58 | ||
| 61 | fn save_divider<F, R>(f: F) -> R | 59 | fn save_divider<F, R>(f: F) -> R |
| @@ -63,7 +61,7 @@ where | |||
| 63 | F: FnOnce() -> R, | 61 | F: FnOnce() -> R, |
| 64 | { | 62 | { |
| 65 | let sio = rp_pac::SIO; | 63 | let sio = rp_pac::SIO; |
| 66 | if unsafe { !sio.div().csr().read().dirty() } { | 64 | if !sio.div().csr().read().dirty() { |
| 67 | // Not dirty, so nothing is waiting for the calculation. So we can just | 65 | // Not dirty, so nothing is waiting for the calculation. So we can just |
| 68 | // issue it directly without a save/restore. | 66 | // issue it directly without a save/restore. |
| 69 | f() | 67 | f() |
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 66faa2489..ce0d02557 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs | |||
| @@ -144,7 +144,7 @@ pub(crate) unsafe fn init() { | |||
| 144 | 144 | ||
| 145 | #[cfg(feature = "rt")] | 145 | #[cfg(feature = "rt")] |
| 146 | #[interrupt] | 146 | #[interrupt] |
| 147 | unsafe fn IO_IRQ_BANK0() { | 147 | fn IO_IRQ_BANK0() { |
| 148 | let cpu = SIO.cpuid().read() as usize; | 148 | let cpu = SIO.cpuid().read() as usize; |
| 149 | // There are two sets of interrupt registers, one for cpu0 and one for cpu1 | 149 | // There are two sets of interrupt registers, one for cpu0 and one for cpu1 |
| 150 | // and here we are selecting the set that belongs to the currently executing | 150 | // and here we are selecting the set that belongs to the currently executing |
| @@ -185,47 +185,45 @@ struct InputFuture<'a, T: Pin> { | |||
| 185 | impl<'d, T: Pin> InputFuture<'d, T> { | 185 | impl<'d, T: Pin> InputFuture<'d, T> { |
| 186 | pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { | 186 | pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { |
| 187 | into_ref!(pin); | 187 | into_ref!(pin); |
| 188 | unsafe { | 188 | let pin_group = (pin.pin() % 8) as usize; |
| 189 | let pin_group = (pin.pin() % 8) as usize; | 189 | // first, clear the INTR register bits. without this INTR will still |
| 190 | // first, clear the INTR register bits. without this INTR will still | 190 | // contain reports of previous edges, causing the IRQ to fire early |
| 191 | // contain reports of previous edges, causing the IRQ to fire early | 191 | // on stale state. clearing these means that we can only detect edges |
| 192 | // on stale state. clearing these means that we can only detect edges | 192 | // that occur *after* the clear happened, but since both this and the |
| 193 | // that occur *after* the clear happened, but since both this and the | 193 | // alternative are fundamentally racy it's probably fine. |
| 194 | // alternative are fundamentally racy it's probably fine. | 194 | // (the alternative being checking the current level and waiting for |
| 195 | // (the alternative being checking the current level and waiting for | 195 | // its inverse, but that requires reading the current level and thus |
| 196 | // its inverse, but that requires reading the current level and thus | 196 | // missing anything that happened before the level was read.) |
| 197 | // missing anything that happened before the level was read.) | 197 | pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { |
| 198 | pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { | 198 | w.set_edge_high(pin_group, true); |
| 199 | w.set_edge_high(pin_group, true); | 199 | w.set_edge_low(pin_group, true); |
| 200 | w.set_edge_low(pin_group, true); | 200 | }); |
| 201 | |||
| 202 | // Each INTR register is divided into 8 groups, one group for each | ||
| 203 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, | ||
| 204 | // and EGDE_HIGH. | ||
| 205 | pin.int_proc() | ||
| 206 | .inte((pin.pin() / 8) as usize) | ||
| 207 | .write_set(|w| match level { | ||
| 208 | InterruptTrigger::LevelHigh => { | ||
| 209 | trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); | ||
| 210 | w.set_level_high(pin_group, true); | ||
| 211 | } | ||
| 212 | InterruptTrigger::LevelLow => { | ||
| 213 | w.set_level_low(pin_group, true); | ||
| 214 | } | ||
| 215 | InterruptTrigger::EdgeHigh => { | ||
| 216 | w.set_edge_high(pin_group, true); | ||
| 217 | } | ||
| 218 | InterruptTrigger::EdgeLow => { | ||
| 219 | w.set_edge_low(pin_group, true); | ||
| 220 | } | ||
| 221 | InterruptTrigger::AnyEdge => { | ||
| 222 | w.set_edge_high(pin_group, true); | ||
| 223 | w.set_edge_low(pin_group, true); | ||
| 224 | } | ||
| 201 | }); | 225 | }); |
| 202 | 226 | ||
| 203 | // Each INTR register is divided into 8 groups, one group for each | ||
| 204 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, | ||
| 205 | // and EGDE_HIGH. | ||
| 206 | pin.int_proc() | ||
| 207 | .inte((pin.pin() / 8) as usize) | ||
| 208 | .write_set(|w| match level { | ||
| 209 | InterruptTrigger::LevelHigh => { | ||
| 210 | trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); | ||
| 211 | w.set_level_high(pin_group, true); | ||
| 212 | } | ||
| 213 | InterruptTrigger::LevelLow => { | ||
| 214 | w.set_level_low(pin_group, true); | ||
| 215 | } | ||
| 216 | InterruptTrigger::EdgeHigh => { | ||
| 217 | w.set_edge_high(pin_group, true); | ||
| 218 | } | ||
| 219 | InterruptTrigger::EdgeLow => { | ||
| 220 | w.set_edge_low(pin_group, true); | ||
| 221 | } | ||
| 222 | InterruptTrigger::AnyEdge => { | ||
| 223 | w.set_edge_high(pin_group, true); | ||
| 224 | w.set_edge_low(pin_group, true); | ||
| 225 | } | ||
| 226 | }); | ||
| 227 | } | ||
| 228 | |||
| 229 | Self { pin, level } | 227 | Self { pin, level } |
| 230 | } | 228 | } |
| 231 | } | 229 | } |
| @@ -242,7 +240,7 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { | |||
| 242 | // then we want to access the interrupt enable register for our | 240 | // then we want to access the interrupt enable register for our |
| 243 | // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and | 241 | // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and |
| 244 | // PROC0_INTE3 per cpu). | 242 | // PROC0_INTE3 per cpu). |
| 245 | let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() }; | 243 | let inte: pac::io::regs::Int = self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read(); |
| 246 | // The register is divided into groups of four, one group for | 244 | // The register is divided into groups of four, one group for |
| 247 | // each pin. Each group consists of four trigger levels LEVEL_LOW, | 245 | // each pin. Each group consists of four trigger levels LEVEL_LOW, |
| 248 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. | 246 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. |
| @@ -449,15 +447,13 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 449 | pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { | 447 | pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { |
| 450 | into_ref!(pin); | 448 | into_ref!(pin); |
| 451 | 449 | ||
| 452 | unsafe { | 450 | pin.pad_ctrl().write(|w| { |
| 453 | pin.pad_ctrl().write(|w| { | 451 | w.set_ie(true); |
| 454 | w.set_ie(true); | 452 | }); |
| 455 | }); | ||
| 456 | 453 | ||
| 457 | pin.io().ctrl().write(|w| { | 454 | pin.io().ctrl().write(|w| { |
| 458 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); | 455 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); |
| 459 | }); | 456 | }); |
| 460 | } | ||
| 461 | 457 | ||
| 462 | Self { pin } | 458 | Self { pin } |
| 463 | } | 459 | } |
| @@ -470,43 +466,37 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 470 | /// Set the pin's pull. | 466 | /// Set the pin's pull. |
| 471 | #[inline] | 467 | #[inline] |
| 472 | pub fn set_pull(&mut self, pull: Pull) { | 468 | pub fn set_pull(&mut self, pull: Pull) { |
| 473 | unsafe { | 469 | self.pin.pad_ctrl().modify(|w| { |
| 474 | self.pin.pad_ctrl().modify(|w| { | 470 | w.set_ie(true); |
| 475 | w.set_ie(true); | 471 | let (pu, pd) = match pull { |
| 476 | let (pu, pd) = match pull { | 472 | Pull::Up => (true, false), |
| 477 | Pull::Up => (true, false), | 473 | Pull::Down => (false, true), |
| 478 | Pull::Down => (false, true), | 474 | Pull::None => (false, false), |
| 479 | Pull::None => (false, false), | 475 | }; |
| 480 | }; | 476 | w.set_pue(pu); |
| 481 | w.set_pue(pu); | 477 | w.set_pde(pd); |
| 482 | w.set_pde(pd); | 478 | }); |
| 483 | }); | ||
| 484 | } | ||
| 485 | } | 479 | } |
| 486 | 480 | ||
| 487 | /// Set the pin's drive strength. | 481 | /// Set the pin's drive strength. |
| 488 | #[inline] | 482 | #[inline] |
| 489 | pub fn set_drive_strength(&mut self, strength: Drive) { | 483 | pub fn set_drive_strength(&mut self, strength: Drive) { |
| 490 | unsafe { | 484 | self.pin.pad_ctrl().modify(|w| { |
| 491 | self.pin.pad_ctrl().modify(|w| { | 485 | w.set_drive(match strength { |
| 492 | w.set_drive(match strength { | 486 | Drive::_2mA => pac::pads::vals::Drive::_2MA, |
| 493 | Drive::_2mA => pac::pads::vals::Drive::_2MA, | 487 | Drive::_4mA => pac::pads::vals::Drive::_4MA, |
| 494 | Drive::_4mA => pac::pads::vals::Drive::_4MA, | 488 | Drive::_8mA => pac::pads::vals::Drive::_8MA, |
| 495 | Drive::_8mA => pac::pads::vals::Drive::_8MA, | 489 | Drive::_12mA => pac::pads::vals::Drive::_12MA, |
| 496 | Drive::_12mA => pac::pads::vals::Drive::_12MA, | ||
| 497 | }); | ||
| 498 | }); | 490 | }); |
| 499 | } | 491 | }); |
| 500 | } | 492 | } |
| 501 | 493 | ||
| 502 | // Set the pin's slew rate. | 494 | // Set the pin's slew rate. |
| 503 | #[inline] | 495 | #[inline] |
| 504 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | 496 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |
| 505 | unsafe { | 497 | self.pin.pad_ctrl().modify(|w| { |
| 506 | self.pin.pad_ctrl().modify(|w| { | 498 | w.set_slewfast(slew_rate == SlewRate::Fast); |
| 507 | w.set_slewfast(slew_rate == SlewRate::Fast); | 499 | }); |
| 508 | }); | ||
| 509 | } | ||
| 510 | } | 500 | } |
| 511 | 501 | ||
| 512 | /// Put the pin into input mode. | 502 | /// Put the pin into input mode. |
| @@ -514,7 +504,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 514 | /// The pull setting is left unchanged. | 504 | /// The pull setting is left unchanged. |
| 515 | #[inline] | 505 | #[inline] |
| 516 | pub fn set_as_input(&mut self) { | 506 | pub fn set_as_input(&mut self) { |
| 517 | unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) } | 507 | self.pin.sio_oe().value_clr().write_value(self.bit()) |
| 518 | } | 508 | } |
| 519 | 509 | ||
| 520 | /// Put the pin into output mode. | 510 | /// Put the pin into output mode. |
| @@ -523,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 523 | /// at a specific level, call `set_high`/`set_low` on the pin first. | 513 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 524 | #[inline] | 514 | #[inline] |
| 525 | pub fn set_as_output(&mut self) { | 515 | pub fn set_as_output(&mut self) { |
| 526 | unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) } | 516 | self.pin.sio_oe().value_set().write_value(self.bit()) |
| 527 | } | 517 | } |
| 528 | 518 | ||
| 529 | #[inline] | 519 | #[inline] |
| 530 | fn is_set_as_output(&self) -> bool { | 520 | fn is_set_as_output(&self) -> bool { |
| 531 | unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 } | 521 | (self.pin.sio_oe().value().read() & self.bit()) != 0 |
| 532 | } | 522 | } |
| 533 | 523 | ||
| 534 | #[inline] | 524 | #[inline] |
| 535 | pub fn toggle_set_as_output(&mut self) { | 525 | pub fn toggle_set_as_output(&mut self) { |
| 536 | unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) } | 526 | self.pin.sio_oe().value_xor().write_value(self.bit()) |
| 537 | } | 527 | } |
| 538 | 528 | ||
| 539 | #[inline] | 529 | #[inline] |
| @@ -543,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 543 | 533 | ||
| 544 | #[inline] | 534 | #[inline] |
| 545 | pub fn is_low(&self) -> bool { | 535 | pub fn is_low(&self) -> bool { |
| 546 | unsafe { self.pin.sio_in().read() & self.bit() == 0 } | 536 | self.pin.sio_in().read() & self.bit() == 0 |
| 547 | } | 537 | } |
| 548 | 538 | ||
| 549 | /// Returns current pin level | 539 | /// Returns current pin level |
| @@ -555,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 555 | /// Set the output as high. | 545 | /// Set the output as high. |
| 556 | #[inline] | 546 | #[inline] |
| 557 | pub fn set_high(&mut self) { | 547 | pub fn set_high(&mut self) { |
| 558 | unsafe { self.pin.sio_out().value_set().write_value(self.bit()) } | 548 | self.pin.sio_out().value_set().write_value(self.bit()) |
| 559 | } | 549 | } |
| 560 | 550 | ||
| 561 | /// Set the output as low. | 551 | /// Set the output as low. |
| 562 | #[inline] | 552 | #[inline] |
| 563 | pub fn set_low(&mut self) { | 553 | pub fn set_low(&mut self) { |
| 564 | unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) } | 554 | self.pin.sio_out().value_clr().write_value(self.bit()) |
| 565 | } | 555 | } |
| 566 | 556 | ||
| 567 | /// Set the output level. | 557 | /// Set the output level. |
| @@ -576,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 576 | /// Is the output level high? | 566 | /// Is the output level high? |
| 577 | #[inline] | 567 | #[inline] |
| 578 | pub fn is_set_high(&self) -> bool { | 568 | pub fn is_set_high(&self) -> bool { |
| 579 | unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 } | 569 | (self.pin.sio_out().value().read() & self.bit()) == 0 |
| 580 | } | 570 | } |
| 581 | 571 | ||
| 582 | /// Is the output level low? | 572 | /// Is the output level low? |
| @@ -594,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 594 | /// Toggle pin output | 584 | /// Toggle pin output |
| 595 | #[inline] | 585 | #[inline] |
| 596 | pub fn toggle(&mut self) { | 586 | pub fn toggle(&mut self) { |
| 597 | unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) } | 587 | self.pin.sio_out().value_xor().write_value(self.bit()) |
| 598 | } | 588 | } |
| 599 | 589 | ||
| 600 | #[inline] | 590 | #[inline] |
| @@ -626,12 +616,10 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 626 | impl<'d, T: Pin> Drop for Flex<'d, T> { | 616 | impl<'d, T: Pin> Drop for Flex<'d, T> { |
| 627 | #[inline] | 617 | #[inline] |
| 628 | fn drop(&mut self) { | 618 | fn drop(&mut self) { |
| 629 | unsafe { | 619 | self.pin.pad_ctrl().write(|_| {}); |
| 630 | self.pin.pad_ctrl().write(|_| {}); | 620 | self.pin.io().ctrl().write(|w| { |
| 631 | self.pin.io().ctrl().write(|w| { | 621 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); |
| 632 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); | 622 | }); |
| 633 | }); | ||
| 634 | } | ||
| 635 | } | 623 | } |
| 636 | } | 624 | } |
| 637 | 625 | ||
| @@ -688,7 +676,7 @@ pub(crate) mod sealed { | |||
| 688 | Bank::Bank0 => crate::pac::IO_BANK0, | 676 | Bank::Bank0 => crate::pac::IO_BANK0, |
| 689 | Bank::Qspi => crate::pac::IO_QSPI, | 677 | Bank::Qspi => crate::pac::IO_QSPI, |
| 690 | }; | 678 | }; |
| 691 | let proc = unsafe { SIO.cpuid().read() }; | 679 | let proc = SIO.cpuid().read(); |
| 692 | io_block.int_proc(proc as _) | 680 | io_block.int_proc(proc as _) |
| 693 | } | 681 | } |
| 694 | } | 682 | } |
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index ce9a082a2..791c64554 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -85,7 +85,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 85 | let r = T::regs(); | 85 | let r = T::regs(); |
| 86 | 86 | ||
| 87 | // mask everything initially | 87 | // mask everything initially |
| 88 | unsafe { r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)) } | 88 | r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); |
| 89 | T::Interrupt::unpend(); | 89 | T::Interrupt::unpend(); |
| 90 | unsafe { T::Interrupt::enable() }; | 90 | unsafe { T::Interrupt::enable() }; |
| 91 | 91 | ||
| @@ -135,13 +135,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 135 | let last = remaining_queue == 0; | 135 | let last = remaining_queue == 0; |
| 136 | batch += 1; | 136 | batch += 1; |
| 137 | 137 | ||
| 138 | unsafe { | 138 | p.ic_data_cmd().write(|w| { |
| 139 | p.ic_data_cmd().write(|w| { | 139 | w.set_restart(restart && remaining_queue == buffer.len() - 1); |
| 140 | w.set_restart(restart && remaining_queue == buffer.len() - 1); | 140 | w.set_stop(last && send_stop); |
| 141 | w.set_stop(last && send_stop); | 141 | w.set_cmd(true); |
| 142 | w.set_cmd(true); | 142 | }); |
| 143 | }); | ||
| 144 | } | ||
| 145 | } | 143 | } |
| 146 | 144 | ||
| 147 | // We've either run out of txfifo or just plain finished setting up | 145 | // We've either run out of txfifo or just plain finished setting up |
| @@ -161,7 +159,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 161 | Poll::Pending | 159 | Poll::Pending |
| 162 | } | 160 | } |
| 163 | }, | 161 | }, |
| 164 | |_me| unsafe { | 162 | |_me| { |
| 165 | // Set the read threshold to the number of bytes we're | 163 | // Set the read threshold to the number of bytes we're |
| 166 | // expecting so we don't get spurious interrupts. | 164 | // expecting so we don't get spurious interrupts. |
| 167 | p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); | 165 | p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); |
| @@ -185,7 +183,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 185 | let rxbytes = (rxfifo as usize).min(remaining); | 183 | let rxbytes = (rxfifo as usize).min(remaining); |
| 186 | let received = buffer.len() - remaining; | 184 | let received = buffer.len() - remaining; |
| 187 | for b in &mut buffer[received..received + rxbytes] { | 185 | for b in &mut buffer[received..received + rxbytes] { |
| 188 | *b = unsafe { p.ic_data_cmd().read().dat() }; | 186 | *b = p.ic_data_cmd().read().dat(); |
| 189 | } | 187 | } |
| 190 | remaining -= rxbytes; | 188 | remaining -= rxbytes; |
| 191 | } | 189 | } |
| @@ -211,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 211 | if let Some(byte) = bytes.next() { | 209 | if let Some(byte) = bytes.next() { |
| 212 | let last = bytes.peek().is_none(); | 210 | let last = bytes.peek().is_none(); |
| 213 | 211 | ||
| 214 | unsafe { | 212 | p.ic_data_cmd().write(|w| { |
| 215 | p.ic_data_cmd().write(|w| { | 213 | w.set_stop(last && send_stop); |
| 216 | w.set_stop(last && send_stop); | 214 | w.set_cmd(false); |
| 217 | w.set_cmd(false); | 215 | w.set_dat(byte); |
| 218 | w.set_dat(byte); | 216 | }); |
| 219 | }); | ||
| 220 | } | ||
| 221 | } else { | 217 | } else { |
| 222 | break 'xmit Ok(()); | 218 | break 'xmit Ok(()); |
| 223 | } | 219 | } |
| @@ -235,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 235 | Poll::Pending | 231 | Poll::Pending |
| 236 | } | 232 | } |
| 237 | }, | 233 | }, |
| 238 | |_me| unsafe { | 234 | |_me| { |
| 239 | // Set tx "free" threshold a little high so that we get | 235 | // Set tx "free" threshold a little high so that we get |
| 240 | // woken before the fifo completely drains to minimize | 236 | // woken before the fifo completely drains to minimize |
| 241 | // transfer stalls. | 237 | // transfer stalls. |
| @@ -267,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 267 | 263 | ||
| 268 | let had_abort2 = self | 264 | let had_abort2 = self |
| 269 | .wait_on( | 265 | .wait_on( |
| 270 | |me| unsafe { | 266 | |me| { |
| 271 | // We could see an abort while processing fifo backlog, | 267 | // We could see an abort while processing fifo backlog, |
| 272 | // so handle it here. | 268 | // so handle it here. |
| 273 | let abort = me.read_and_clear_abort_reason(); | 269 | let abort = me.read_and_clear_abort_reason(); |
| @@ -279,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 279 | Poll::Pending | 275 | Poll::Pending |
| 280 | } | 276 | } |
| 281 | }, | 277 | }, |
| 282 | |_me| unsafe { | 278 | |_me| { |
| 283 | p.ic_intr_mask().modify(|w| { | 279 | p.ic_intr_mask().modify(|w| { |
| 284 | w.set_m_stop_det(true); | 280 | w.set_m_stop_det(true); |
| 285 | w.set_m_tx_abrt(true); | 281 | w.set_m_tx_abrt(true); |
| @@ -287,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 287 | }, | 283 | }, |
| 288 | ) | 284 | ) |
| 289 | .await; | 285 | .await; |
| 290 | unsafe { | 286 | p.ic_clr_stop_det().read(); |
| 291 | p.ic_clr_stop_det().read(); | ||
| 292 | } | ||
| 293 | 287 | ||
| 294 | had_abort.and(had_abort2) | 288 | had_abort.and(had_abort2) |
| 295 | } else { | 289 | } else { |
| @@ -336,95 +330,93 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 336 | 330 | ||
| 337 | let p = T::regs(); | 331 | let p = T::regs(); |
| 338 | 332 | ||
| 339 | unsafe { | 333 | let reset = T::reset(); |
| 340 | let reset = T::reset(); | 334 | crate::reset::reset(reset); |
| 341 | crate::reset::reset(reset); | 335 | crate::reset::unreset_wait(reset); |
| 342 | crate::reset::unreset_wait(reset); | 336 | |
| 343 | 337 | p.ic_enable().write(|w| w.set_enable(false)); | |
| 344 | p.ic_enable().write(|w| w.set_enable(false)); | 338 | |
| 345 | 339 | // Select controller mode & speed | |
| 346 | // Select controller mode & speed | 340 | p.ic_con().modify(|w| { |
| 347 | p.ic_con().modify(|w| { | 341 | // Always use "fast" mode (<= 400 kHz, works fine for standard |
| 348 | // Always use "fast" mode (<= 400 kHz, works fine for standard | 342 | // mode too) |
| 349 | // mode too) | 343 | w.set_speed(i2c::vals::Speed::FAST); |
| 350 | w.set_speed(i2c::vals::Speed::FAST); | 344 | w.set_master_mode(true); |
| 351 | w.set_master_mode(true); | 345 | w.set_ic_slave_disable(true); |
| 352 | w.set_ic_slave_disable(true); | 346 | w.set_ic_restart_en(true); |
| 353 | w.set_ic_restart_en(true); | 347 | w.set_tx_empty_ctrl(true); |
| 354 | w.set_tx_empty_ctrl(true); | 348 | }); |
| 355 | }); | 349 | |
| 356 | 350 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | |
| 357 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | 351 | // by a register value of 0. |
| 358 | // by a register value of 0. | 352 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); |
| 359 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); | 353 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); |
| 360 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); | 354 | |
| 361 | 355 | // Configure SCL & SDA pins | |
| 362 | // Configure SCL & SDA pins | 356 | scl.io().ctrl().write(|w| w.set_funcsel(3)); |
| 363 | scl.io().ctrl().write(|w| w.set_funcsel(3)); | 357 | sda.io().ctrl().write(|w| w.set_funcsel(3)); |
| 364 | sda.io().ctrl().write(|w| w.set_funcsel(3)); | 358 | |
| 365 | 359 | scl.pad_ctrl().write(|w| { | |
| 366 | scl.pad_ctrl().write(|w| { | 360 | w.set_schmitt(true); |
| 367 | w.set_schmitt(true); | 361 | w.set_ie(true); |
| 368 | w.set_ie(true); | 362 | w.set_od(false); |
| 369 | w.set_od(false); | 363 | w.set_pue(true); |
| 370 | w.set_pue(true); | 364 | w.set_pde(false); |
| 371 | w.set_pde(false); | 365 | }); |
| 372 | }); | 366 | sda.pad_ctrl().write(|w| { |
| 373 | sda.pad_ctrl().write(|w| { | 367 | w.set_schmitt(true); |
| 374 | w.set_schmitt(true); | 368 | w.set_ie(true); |
| 375 | w.set_ie(true); | 369 | w.set_od(false); |
| 376 | w.set_od(false); | 370 | w.set_pue(true); |
| 377 | w.set_pue(true); | 371 | w.set_pde(false); |
| 378 | w.set_pde(false); | 372 | }); |
| 379 | }); | 373 | |
| 374 | // Configure baudrate | ||
| 375 | |||
| 376 | // There are some subtleties to I2C timing which we are completely | ||
| 377 | // ignoring here See: | ||
| 378 | // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 | ||
| 379 | let clk_base = crate::clocks::clk_peri_freq(); | ||
| 380 | |||
| 381 | let period = (clk_base + config.frequency / 2) / config.frequency; | ||
| 382 | let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low | ||
| 383 | let hcnt = period - lcnt; // and 2/5 (40%) of the period high | ||
| 384 | |||
| 385 | // Check for out-of-range divisors: | ||
| 386 | assert!(hcnt <= 0xffff); | ||
| 387 | assert!(lcnt <= 0xffff); | ||
| 388 | assert!(hcnt >= 8); | ||
| 389 | assert!(lcnt >= 8); | ||
| 390 | |||
| 391 | // Per I2C-bus specification a device in standard or fast mode must | ||
| 392 | // internally provide a hold time of at least 300ns for the SDA | ||
| 393 | // signal to bridge the undefined region of the falling edge of SCL. | ||
| 394 | // A smaller hold time of 120ns is used for fast mode plus. | ||
| 395 | let sda_tx_hold_count = if config.frequency < 1_000_000 { | ||
| 396 | // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / | ||
| 397 | // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't | ||
| 398 | // fit in uint. Add 1 to avoid division truncation. | ||
| 399 | ((clk_base * 3) / 10_000_000) + 1 | ||
| 400 | } else { | ||
| 401 | // fast mode plus requires a clk_base > 32MHz | ||
| 402 | assert!(clk_base >= 32_000_000); | ||
| 380 | 403 | ||
| 381 | // Configure baudrate | 404 | // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / |
| 382 | 405 | // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't | |
| 383 | // There are some subtleties to I2C timing which we are completely | 406 | // fit in uint. Add 1 to avoid division truncation. |
| 384 | // ignoring here See: | 407 | ((clk_base * 3) / 25_000_000) + 1 |
| 385 | // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 | 408 | }; |
| 386 | let clk_base = crate::clocks::clk_peri_freq(); | 409 | assert!(sda_tx_hold_count <= lcnt - 2); |
| 387 | |||
| 388 | let period = (clk_base + config.frequency / 2) / config.frequency; | ||
| 389 | let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low | ||
| 390 | let hcnt = period - lcnt; // and 2/5 (40%) of the period high | ||
| 391 | |||
| 392 | // Check for out-of-range divisors: | ||
| 393 | assert!(hcnt <= 0xffff); | ||
| 394 | assert!(lcnt <= 0xffff); | ||
| 395 | assert!(hcnt >= 8); | ||
| 396 | assert!(lcnt >= 8); | ||
| 397 | |||
| 398 | // Per I2C-bus specification a device in standard or fast mode must | ||
| 399 | // internally provide a hold time of at least 300ns for the SDA | ||
| 400 | // signal to bridge the undefined region of the falling edge of SCL. | ||
| 401 | // A smaller hold time of 120ns is used for fast mode plus. | ||
| 402 | let sda_tx_hold_count = if config.frequency < 1_000_000 { | ||
| 403 | // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / | ||
| 404 | // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't | ||
| 405 | // fit in uint. Add 1 to avoid division truncation. | ||
| 406 | ((clk_base * 3) / 10_000_000) + 1 | ||
| 407 | } else { | ||
| 408 | // fast mode plus requires a clk_base > 32MHz | ||
| 409 | assert!(clk_base >= 32_000_000); | ||
| 410 | 410 | ||
| 411 | // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / | 411 | p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); |
| 412 | // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't | 412 | p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); |
| 413 | // fit in uint. Add 1 to avoid division truncation. | 413 | p.ic_fs_spklen() |
| 414 | ((clk_base * 3) / 25_000_000) + 1 | 414 | .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); |
| 415 | }; | 415 | p.ic_sda_hold() |
| 416 | assert!(sda_tx_hold_count <= lcnt - 2); | 416 | .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); |
| 417 | 417 | ||
| 418 | p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); | 418 | // Enable I2C block |
| 419 | p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); | 419 | p.ic_enable().write(|w| w.set_enable(true)); |
| 420 | p.ic_fs_spklen() | ||
| 421 | .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); | ||
| 422 | p.ic_sda_hold() | ||
| 423 | .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); | ||
| 424 | |||
| 425 | // Enable I2C block | ||
| 426 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 427 | } | ||
| 428 | 420 | ||
| 429 | Self { phantom: PhantomData } | 421 | Self { phantom: PhantomData } |
| 430 | } | 422 | } |
| @@ -439,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 439 | } | 431 | } |
| 440 | 432 | ||
| 441 | let p = T::regs(); | 433 | let p = T::regs(); |
| 442 | unsafe { | 434 | p.ic_enable().write(|w| w.set_enable(false)); |
| 443 | p.ic_enable().write(|w| w.set_enable(false)); | 435 | p.ic_tar().write(|w| w.set_ic_tar(addr)); |
| 444 | p.ic_tar().write(|w| w.set_ic_tar(addr)); | 436 | p.ic_enable().write(|w| w.set_enable(true)); |
| 445 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 446 | } | ||
| 447 | Ok(()) | 437 | Ok(()) |
| 448 | } | 438 | } |
| 449 | 439 | ||
| @@ -455,40 +445,38 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 455 | #[inline] | 445 | #[inline] |
| 456 | fn tx_fifo_capacity() -> u8 { | 446 | fn tx_fifo_capacity() -> u8 { |
| 457 | let p = T::regs(); | 447 | let p = T::regs(); |
| 458 | unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } | 448 | FIFO_SIZE - p.ic_txflr().read().txflr() |
| 459 | } | 449 | } |
| 460 | 450 | ||
| 461 | #[inline] | 451 | #[inline] |
| 462 | fn rx_fifo_len() -> u8 { | 452 | fn rx_fifo_len() -> u8 { |
| 463 | let p = T::regs(); | 453 | let p = T::regs(); |
| 464 | unsafe { p.ic_rxflr().read().rxflr() } | 454 | p.ic_rxflr().read().rxflr() |
| 465 | } | 455 | } |
| 466 | 456 | ||
| 467 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | 457 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 468 | let p = T::regs(); | 458 | let p = T::regs(); |
| 469 | unsafe { | 459 | let abort_reason = p.ic_tx_abrt_source().read(); |
| 470 | let abort_reason = p.ic_tx_abrt_source().read(); | 460 | if abort_reason.0 != 0 { |
| 471 | if abort_reason.0 != 0 { | 461 | // Note clearing the abort flag also clears the reason, and this |
| 472 | // Note clearing the abort flag also clears the reason, and this | 462 | // instance of flag is clear-on-read! Note also the |
| 473 | // instance of flag is clear-on-read! Note also the | 463 | // IC_CLR_TX_ABRT register always reads as 0. |
| 474 | // IC_CLR_TX_ABRT register always reads as 0. | 464 | p.ic_clr_tx_abrt().read(); |
| 475 | p.ic_clr_tx_abrt().read(); | 465 | |
| 476 | 466 | let reason = if abort_reason.abrt_7b_addr_noack() | |
| 477 | let reason = if abort_reason.abrt_7b_addr_noack() | 467 | | abort_reason.abrt_10addr1_noack() |
| 478 | | abort_reason.abrt_10addr1_noack() | 468 | | abort_reason.abrt_10addr2_noack() |
| 479 | | abort_reason.abrt_10addr2_noack() | 469 | { |
| 480 | { | 470 | AbortReason::NoAcknowledge |
| 481 | AbortReason::NoAcknowledge | 471 | } else if abort_reason.arb_lost() { |
| 482 | } else if abort_reason.arb_lost() { | 472 | AbortReason::ArbitrationLoss |
| 483 | AbortReason::ArbitrationLoss | ||
| 484 | } else { | ||
| 485 | AbortReason::Other(abort_reason.0) | ||
| 486 | }; | ||
| 487 | |||
| 488 | Err(Error::Abort(reason)) | ||
| 489 | } else { | 473 | } else { |
| 490 | Ok(()) | 474 | AbortReason::Other(abort_reason.0) |
| 491 | } | 475 | }; |
| 476 | |||
| 477 | Err(Error::Abort(reason)) | ||
| 478 | } else { | ||
| 479 | Ok(()) | ||
| 492 | } | 480 | } |
| 493 | } | 481 | } |
| 494 | 482 | ||
| @@ -503,24 +491,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 503 | let first = i == 0; | 491 | let first = i == 0; |
| 504 | let last = i == lastindex; | 492 | let last = i == lastindex; |
| 505 | 493 | ||
| 506 | // NOTE(unsafe) We have &mut self | 494 | // wait until there is space in the FIFO to write the next byte |
| 507 | unsafe { | 495 | while Self::tx_fifo_full() {} |
| 508 | // wait until there is space in the FIFO to write the next byte | ||
| 509 | while Self::tx_fifo_full() {} | ||
| 510 | |||
| 511 | p.ic_data_cmd().write(|w| { | ||
| 512 | w.set_restart(restart && first); | ||
| 513 | w.set_stop(send_stop && last); | ||
| 514 | 496 | ||
| 515 | w.set_cmd(true); | 497 | p.ic_data_cmd().write(|w| { |
| 516 | }); | 498 | w.set_restart(restart && first); |
| 499 | w.set_stop(send_stop && last); | ||
| 517 | 500 | ||
| 518 | while Self::rx_fifo_len() == 0 { | 501 | w.set_cmd(true); |
| 519 | self.read_and_clear_abort_reason()?; | 502 | }); |
| 520 | } | ||
| 521 | 503 | ||
| 522 | *byte = p.ic_data_cmd().read().dat(); | 504 | while Self::rx_fifo_len() == 0 { |
| 505 | self.read_and_clear_abort_reason()?; | ||
| 523 | } | 506 | } |
| 507 | |||
| 508 | *byte = p.ic_data_cmd().read().dat(); | ||
| 524 | } | 509 | } |
| 525 | 510 | ||
| 526 | Ok(()) | 511 | Ok(()) |
| @@ -536,36 +521,33 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 536 | for (i, byte) in write.iter().enumerate() { | 521 | for (i, byte) in write.iter().enumerate() { |
| 537 | let last = i == write.len() - 1; | 522 | let last = i == write.len() - 1; |
| 538 | 523 | ||
| 539 | // NOTE(unsafe) We have &mut self | 524 | p.ic_data_cmd().write(|w| { |
| 540 | unsafe { | 525 | w.set_stop(send_stop && last); |
| 541 | p.ic_data_cmd().write(|w| { | 526 | w.set_dat(*byte); |
| 542 | w.set_stop(send_stop && last); | 527 | }); |
| 543 | w.set_dat(*byte); | ||
| 544 | }); | ||
| 545 | 528 | ||
| 546 | // Wait until the transmission of the address/data from the | 529 | // Wait until the transmission of the address/data from the |
| 547 | // internal shift register has completed. For this to function | 530 | // internal shift register has completed. For this to function |
| 548 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | 531 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The |
| 549 | // TX_EMPTY_CTRL flag was set in i2c_init. | 532 | // TX_EMPTY_CTRL flag was set in i2c_init. |
| 550 | while !p.ic_raw_intr_stat().read().tx_empty() {} | 533 | while !p.ic_raw_intr_stat().read().tx_empty() {} |
| 551 | 534 | ||
| 552 | let abort_reason = self.read_and_clear_abort_reason(); | 535 | let abort_reason = self.read_and_clear_abort_reason(); |
| 553 | 536 | ||
| 554 | if abort_reason.is_err() || (send_stop && last) { | 537 | if abort_reason.is_err() || (send_stop && last) { |
| 555 | // If the transaction was aborted or if it completed | 538 | // If the transaction was aborted or if it completed |
| 556 | // successfully wait until the STOP condition has occurred. | 539 | // successfully wait until the STOP condition has occurred. |
| 557 | 540 | ||
| 558 | while !p.ic_raw_intr_stat().read().stop_det() {} | 541 | while !p.ic_raw_intr_stat().read().stop_det() {} |
| 559 | 542 | ||
| 560 | p.ic_clr_stop_det().read().clr_stop_det(); | 543 | p.ic_clr_stop_det().read().clr_stop_det(); |
| 561 | } | ||
| 562 | |||
| 563 | // Note the hardware issues a STOP automatically on an abort | ||
| 564 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 565 | // TX on abort, ecause we set hwparam | ||
| 566 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 567 | abort_reason?; | ||
| 568 | } | 544 | } |
| 545 | |||
| 546 | // Note the hardware issues a STOP automatically on an abort | ||
| 547 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 548 | // TX on abort, ecause we set hwparam | ||
| 549 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 550 | abort_reason?; | ||
| 569 | } | 551 | } |
| 570 | Ok(()) | 552 | Ok(()) |
| 571 | } | 553 | } |
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index d6f73219f..4fd3cb46a 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -261,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 261 | 261 | ||
| 262 | /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. | 262 | /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. |
| 263 | trait RegExt<T: Copy> { | 263 | trait RegExt<T: Copy> { |
| 264 | unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 264 | fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 265 | unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 265 | fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 266 | unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 266 | fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { | 269 | impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { |
| 270 | unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | 270 | fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { |
| 271 | let mut val = Default::default(); | 271 | let mut val = Default::default(); |
| 272 | let res = f(&mut val); | 272 | let res = f(&mut val); |
| 273 | let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T; | 273 | unsafe { |
| 274 | ptr.write_volatile(val); | 274 | let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T; |
| 275 | ptr.write_volatile(val); | ||
| 276 | } | ||
| 275 | res | 277 | res |
| 276 | } | 278 | } |
| 277 | 279 | ||
| 278 | unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | 280 | fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { |
| 279 | let mut val = Default::default(); | 281 | let mut val = Default::default(); |
| 280 | let res = f(&mut val); | 282 | let res = f(&mut val); |
| 281 | let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T; | 283 | unsafe { |
| 282 | ptr.write_volatile(val); | 284 | let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T; |
| 285 | ptr.write_volatile(val); | ||
| 286 | } | ||
| 283 | res | 287 | res |
| 284 | } | 288 | } |
| 285 | 289 | ||
| 286 | unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | 290 | fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { |
| 287 | let mut val = Default::default(); | 291 | let mut val = Default::default(); |
| 288 | let res = f(&mut val); | 292 | let res = f(&mut val); |
| 289 | let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T; | 293 | unsafe { |
| 290 | ptr.write_volatile(val); | 294 | let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T; |
| 295 | ptr.write_volatile(val); | ||
| 296 | } | ||
| 291 | res | 297 | res |
| 292 | } | 298 | } |
| 293 | } | 299 | } |
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 2a7e4822a..468e8470a 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs | |||
| @@ -163,14 +163,12 @@ where | |||
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | // Reset the core | 165 | // Reset the core |
| 166 | unsafe { | 166 | let psm = pac::PSM; |
| 167 | let psm = pac::PSM; | 167 | psm.frce_off().modify(|w| w.set_proc1(true)); |
| 168 | psm.frce_off().modify(|w| w.set_proc1(true)); | 168 | while !psm.frce_off().read().proc1() { |
| 169 | while !psm.frce_off().read().proc1() { | 169 | cortex_m::asm::nop(); |
| 170 | cortex_m::asm::nop(); | ||
| 171 | } | ||
| 172 | psm.frce_off().modify(|w| w.set_proc1(false)); | ||
| 173 | } | 170 | } |
| 171 | psm.frce_off().modify(|w| w.set_proc1(false)); | ||
| 174 | 172 | ||
| 175 | // The ARM AAPCS ABI requires 8-byte stack alignment. | 173 | // The ARM AAPCS ABI requires 8-byte stack alignment. |
| 176 | // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be | 174 | // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be |
| @@ -270,14 +268,12 @@ pub fn resume_core1() { | |||
| 270 | // Push a value to the inter-core FIFO, block until space is available | 268 | // Push a value to the inter-core FIFO, block until space is available |
| 271 | #[inline(always)] | 269 | #[inline(always)] |
| 272 | fn fifo_write(value: u32) { | 270 | fn fifo_write(value: u32) { |
| 273 | unsafe { | 271 | let sio = pac::SIO; |
| 274 | let sio = pac::SIO; | 272 | // Wait for the FIFO to have enough space |
| 275 | // Wait for the FIFO to have enough space | 273 | while !sio.fifo().st().read().rdy() { |
| 276 | while !sio.fifo().st().read().rdy() { | 274 | cortex_m::asm::nop(); |
| 277 | cortex_m::asm::nop(); | ||
| 278 | } | ||
| 279 | sio.fifo().wr().write_value(value); | ||
| 280 | } | 275 | } |
| 276 | sio.fifo().wr().write_value(value); | ||
| 281 | // Fire off an event to the other core. | 277 | // Fire off an event to the other core. |
| 282 | // This is required as the other core may be `wfe` (waiting for event) | 278 | // This is required as the other core may be `wfe` (waiting for event) |
| 283 | cortex_m::asm::sev(); | 279 | cortex_m::asm::sev(); |
| @@ -286,38 +282,32 @@ fn fifo_write(value: u32) { | |||
| 286 | // Pop a value from inter-core FIFO, block until available | 282 | // Pop a value from inter-core FIFO, block until available |
| 287 | #[inline(always)] | 283 | #[inline(always)] |
| 288 | fn fifo_read() -> u32 { | 284 | fn fifo_read() -> u32 { |
| 289 | unsafe { | 285 | let sio = pac::SIO; |
| 290 | let sio = pac::SIO; | 286 | // Wait until FIFO has data |
| 291 | // Wait until FIFO has data | 287 | while !sio.fifo().st().read().vld() { |
| 292 | while !sio.fifo().st().read().vld() { | 288 | cortex_m::asm::nop(); |
| 293 | cortex_m::asm::nop(); | ||
| 294 | } | ||
| 295 | sio.fifo().rd().read() | ||
| 296 | } | 289 | } |
| 290 | sio.fifo().rd().read() | ||
| 297 | } | 291 | } |
| 298 | 292 | ||
| 299 | // Pop a value from inter-core FIFO, `wfe` until available | 293 | // Pop a value from inter-core FIFO, `wfe` until available |
| 300 | #[inline(always)] | 294 | #[inline(always)] |
| 301 | #[allow(unused)] | 295 | #[allow(unused)] |
| 302 | fn fifo_read_wfe() -> u32 { | 296 | fn fifo_read_wfe() -> u32 { |
| 303 | unsafe { | 297 | let sio = pac::SIO; |
| 304 | let sio = pac::SIO; | 298 | // Wait until FIFO has data |
| 305 | // Wait until FIFO has data | 299 | while !sio.fifo().st().read().vld() { |
| 306 | while !sio.fifo().st().read().vld() { | 300 | cortex_m::asm::wfe(); |
| 307 | cortex_m::asm::wfe(); | ||
| 308 | } | ||
| 309 | sio.fifo().rd().read() | ||
| 310 | } | 301 | } |
| 302 | sio.fifo().rd().read() | ||
| 311 | } | 303 | } |
| 312 | 304 | ||
| 313 | // Drain inter-core FIFO | 305 | // Drain inter-core FIFO |
| 314 | #[inline(always)] | 306 | #[inline(always)] |
| 315 | fn fifo_drain() { | 307 | fn fifo_drain() { |
| 316 | unsafe { | 308 | let sio = pac::SIO; |
| 317 | let sio = pac::SIO; | 309 | while sio.fifo().st().read().vld() { |
| 318 | while sio.fifo().st().read().vld() { | 310 | let _ = sio.fifo().rd().read(); |
| 319 | let _ = sio.fifo().rd().read(); | ||
| 320 | } | ||
| 321 | } | 311 | } |
| 322 | } | 312 | } |
| 323 | 313 | ||
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 0fa3bd771..1b36e0a54 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs | |||
| @@ -87,7 +87,7 @@ const SMIRQ_MASK: u32 = 1 << 8; | |||
| 87 | 87 | ||
| 88 | #[cfg(feature = "rt")] | 88 | #[cfg(feature = "rt")] |
| 89 | #[interrupt] | 89 | #[interrupt] |
| 90 | unsafe fn PIO0_IRQ_0() { | 90 | fn PIO0_IRQ_0() { |
| 91 | use crate::pac; | 91 | use crate::pac; |
| 92 | let ints = pac::PIO0.irqs(0).ints().read().0; | 92 | let ints = pac::PIO0.irqs(0).ints().read().0; |
| 93 | for bit in 0..12 { | 93 | for bit in 0..12 { |
| @@ -100,7 +100,7 @@ unsafe fn PIO0_IRQ_0() { | |||
| 100 | 100 | ||
| 101 | #[cfg(feature = "rt")] | 101 | #[cfg(feature = "rt")] |
| 102 | #[interrupt] | 102 | #[interrupt] |
| 103 | unsafe fn PIO1_IRQ_0() { | 103 | fn PIO1_IRQ_0() { |
| 104 | use crate::pac; | 104 | use crate::pac; |
| 105 | let ints = pac::PIO1.irqs(0).ints().read().0; | 105 | let ints = pac::PIO1.irqs(0).ints().read().0; |
| 106 | for bit in 0..12 { | 106 | for bit in 0..12 { |
| @@ -145,11 +145,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI | |||
| 145 | Poll::Ready(()) | 145 | Poll::Ready(()) |
| 146 | } else { | 146 | } else { |
| 147 | WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); | 147 | WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); |
| 148 | unsafe { | 148 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 149 | PIO::PIO.irqs(0).inte().write_set(|m| { | 149 | m.0 = TXNFULL_MASK << SM; |
| 150 | m.0 = TXNFULL_MASK << SM; | 150 | }); |
| 151 | }); | ||
| 152 | } | ||
| 153 | // debug!("Pending"); | 151 | // debug!("Pending"); |
| 154 | Poll::Pending | 152 | Poll::Pending |
| 155 | } | 153 | } |
| @@ -158,11 +156,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI | |||
| 158 | 156 | ||
| 159 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { | 157 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { |
| 160 | fn drop(&mut self) { | 158 | fn drop(&mut self) { |
| 161 | unsafe { | 159 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 162 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 160 | m.0 = TXNFULL_MASK << SM; |
| 163 | m.0 = TXNFULL_MASK << SM; | 161 | }); |
| 164 | }); | ||
| 165 | } | ||
| 166 | } | 162 | } |
| 167 | } | 163 | } |
| 168 | 164 | ||
| @@ -186,11 +182,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO | |||
| 186 | Poll::Ready(v) | 182 | Poll::Ready(v) |
| 187 | } else { | 183 | } else { |
| 188 | WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); | 184 | WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); |
| 189 | unsafe { | 185 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 190 | PIO::PIO.irqs(0).inte().write_set(|m| { | 186 | m.0 = RXNEMPTY_MASK << SM; |
| 191 | m.0 = RXNEMPTY_MASK << SM; | 187 | }); |
| 192 | }); | ||
| 193 | } | ||
| 194 | //debug!("Pending"); | 188 | //debug!("Pending"); |
| 195 | Poll::Pending | 189 | Poll::Pending |
| 196 | } | 190 | } |
| @@ -199,11 +193,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO | |||
| 199 | 193 | ||
| 200 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { | 194 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { |
| 201 | fn drop(&mut self) { | 195 | fn drop(&mut self) { |
| 202 | unsafe { | 196 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 203 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 197 | m.0 = RXNEMPTY_MASK << SM; |
| 204 | m.0 = RXNEMPTY_MASK << SM; | 198 | }); |
| 205 | }); | ||
| 206 | } | ||
| 207 | } | 199 | } |
| 208 | } | 200 | } |
| 209 | 201 | ||
| @@ -220,30 +212,24 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> { | |||
| 220 | //debug!("Poll {},{}", PIO::PIO_NO, SM); | 212 | //debug!("Poll {},{}", PIO::PIO_NO, SM); |
| 221 | 213 | ||
| 222 | // Check if IRQ flag is already set | 214 | // Check if IRQ flag is already set |
| 223 | if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } { | 215 | if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 { |
| 224 | unsafe { | 216 | PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no); |
| 225 | PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no); | ||
| 226 | } | ||
| 227 | return Poll::Ready(()); | 217 | return Poll::Ready(()); |
| 228 | } | 218 | } |
| 229 | 219 | ||
| 230 | WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); | 220 | WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); |
| 231 | unsafe { | 221 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 232 | PIO::PIO.irqs(0).inte().write_set(|m| { | 222 | m.0 = SMIRQ_MASK << self.irq_no; |
| 233 | m.0 = SMIRQ_MASK << self.irq_no; | 223 | }); |
| 234 | }); | ||
| 235 | } | ||
| 236 | Poll::Pending | 224 | Poll::Pending |
| 237 | } | 225 | } |
| 238 | } | 226 | } |
| 239 | 227 | ||
| 240 | impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { | 228 | impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { |
| 241 | fn drop(&mut self) { | 229 | fn drop(&mut self) { |
| 242 | unsafe { | 230 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 243 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 231 | m.0 = SMIRQ_MASK << self.irq_no; |
| 244 | m.0 = SMIRQ_MASK << self.irq_no; | 232 | }); |
| 245 | }); | ||
| 246 | } | ||
| 247 | } | 233 | } |
| 248 | } | 234 | } |
| 249 | 235 | ||
| @@ -256,57 +242,47 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { | |||
| 256 | /// Set the pin's drive strength. | 242 | /// Set the pin's drive strength. |
| 257 | #[inline] | 243 | #[inline] |
| 258 | pub fn set_drive_strength(&mut self, strength: Drive) { | 244 | pub fn set_drive_strength(&mut self, strength: Drive) { |
| 259 | unsafe { | 245 | self.pin.pad_ctrl().modify(|w| { |
| 260 | self.pin.pad_ctrl().modify(|w| { | 246 | w.set_drive(match strength { |
| 261 | w.set_drive(match strength { | 247 | Drive::_2mA => pac::pads::vals::Drive::_2MA, |
| 262 | Drive::_2mA => pac::pads::vals::Drive::_2MA, | 248 | Drive::_4mA => pac::pads::vals::Drive::_4MA, |
| 263 | Drive::_4mA => pac::pads::vals::Drive::_4MA, | 249 | Drive::_8mA => pac::pads::vals::Drive::_8MA, |
| 264 | Drive::_8mA => pac::pads::vals::Drive::_8MA, | 250 | Drive::_12mA => pac::pads::vals::Drive::_12MA, |
| 265 | Drive::_12mA => pac::pads::vals::Drive::_12MA, | ||
| 266 | }); | ||
| 267 | }); | 251 | }); |
| 268 | } | 252 | }); |
| 269 | } | 253 | } |
| 270 | 254 | ||
| 271 | // Set the pin's slew rate. | 255 | // Set the pin's slew rate. |
| 272 | #[inline] | 256 | #[inline] |
| 273 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | 257 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |
| 274 | unsafe { | 258 | self.pin.pad_ctrl().modify(|w| { |
| 275 | self.pin.pad_ctrl().modify(|w| { | 259 | w.set_slewfast(slew_rate == SlewRate::Fast); |
| 276 | w.set_slewfast(slew_rate == SlewRate::Fast); | 260 | }); |
| 277 | }); | ||
| 278 | } | ||
| 279 | } | 261 | } |
| 280 | 262 | ||
| 281 | /// Set the pin's pull. | 263 | /// Set the pin's pull. |
| 282 | #[inline] | 264 | #[inline] |
| 283 | pub fn set_pull(&mut self, pull: Pull) { | 265 | pub fn set_pull(&mut self, pull: Pull) { |
| 284 | unsafe { | 266 | self.pin.pad_ctrl().modify(|w| { |
| 285 | self.pin.pad_ctrl().modify(|w| { | 267 | w.set_pue(pull == Pull::Up); |
| 286 | w.set_pue(pull == Pull::Up); | 268 | w.set_pde(pull == Pull::Down); |
| 287 | w.set_pde(pull == Pull::Down); | 269 | }); |
| 288 | }); | ||
| 289 | } | ||
| 290 | } | 270 | } |
| 291 | 271 | ||
| 292 | /// Set the pin's schmitt trigger. | 272 | /// Set the pin's schmitt trigger. |
| 293 | #[inline] | 273 | #[inline] |
| 294 | pub fn set_schmitt(&mut self, enable: bool) { | 274 | pub fn set_schmitt(&mut self, enable: bool) { |
| 295 | unsafe { | 275 | self.pin.pad_ctrl().modify(|w| { |
| 296 | self.pin.pad_ctrl().modify(|w| { | 276 | w.set_schmitt(enable); |
| 297 | w.set_schmitt(enable); | 277 | }); |
| 298 | }); | ||
| 299 | } | ||
| 300 | } | 278 | } |
| 301 | 279 | ||
| 302 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { | 280 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { |
| 303 | let mask = 1 << self.pin(); | 281 | let mask = 1 << self.pin(); |
| 304 | unsafe { | 282 | if bypass { |
| 305 | if bypass { | 283 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); |
| 306 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); | 284 | } else { |
| 307 | } else { | 285 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); |
| 308 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); | ||
| 309 | } | ||
| 310 | } | 286 | } |
| 311 | } | 287 | } |
| 312 | 288 | ||
| @@ -321,41 +297,37 @@ pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> { | |||
| 321 | 297 | ||
| 322 | impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | 298 | impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { |
| 323 | pub fn empty(&self) -> bool { | 299 | pub fn empty(&self) -> bool { |
| 324 | unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } | 300 | PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 |
| 325 | } | 301 | } |
| 326 | 302 | ||
| 327 | pub fn full(&self) -> bool { | 303 | pub fn full(&self) -> bool { |
| 328 | unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } | 304 | PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 |
| 329 | } | 305 | } |
| 330 | 306 | ||
| 331 | pub fn level(&self) -> u8 { | 307 | pub fn level(&self) -> u8 { |
| 332 | unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } | 308 | (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f |
| 333 | } | 309 | } |
| 334 | 310 | ||
| 335 | pub fn stalled(&self) -> bool { | 311 | pub fn stalled(&self) -> bool { |
| 336 | unsafe { | 312 | let fdebug = PIO::PIO.fdebug(); |
| 337 | let fdebug = PIO::PIO.fdebug(); | 313 | let ret = fdebug.read().rxstall() & (1 << SM) != 0; |
| 338 | let ret = fdebug.read().rxstall() & (1 << SM) != 0; | 314 | if ret { |
| 339 | if ret { | 315 | fdebug.write(|w| w.set_rxstall(1 << SM)); |
| 340 | fdebug.write(|w| w.set_rxstall(1 << SM)); | ||
| 341 | } | ||
| 342 | ret | ||
| 343 | } | 316 | } |
| 317 | ret | ||
| 344 | } | 318 | } |
| 345 | 319 | ||
| 346 | pub fn underflowed(&self) -> bool { | 320 | pub fn underflowed(&self) -> bool { |
| 347 | unsafe { | 321 | let fdebug = PIO::PIO.fdebug(); |
| 348 | let fdebug = PIO::PIO.fdebug(); | 322 | let ret = fdebug.read().rxunder() & (1 << SM) != 0; |
| 349 | let ret = fdebug.read().rxunder() & (1 << SM) != 0; | 323 | if ret { |
| 350 | if ret { | 324 | fdebug.write(|w| w.set_rxunder(1 << SM)); |
| 351 | fdebug.write(|w| w.set_rxunder(1 << SM)); | ||
| 352 | } | ||
| 353 | ret | ||
| 354 | } | 325 | } |
| 326 | ret | ||
| 355 | } | 327 | } |
| 356 | 328 | ||
| 357 | pub fn pull(&mut self) -> u32 { | 329 | pub fn pull(&mut self) -> u32 { |
| 358 | unsafe { PIO::PIO.rxf(SM).read() } | 330 | PIO::PIO.rxf(SM).read() |
| 359 | } | 331 | } |
| 360 | 332 | ||
| 361 | pub fn try_pull(&mut self) -> Option<u32> { | 333 | pub fn try_pull(&mut self) -> Option<u32> { |
| @@ -374,24 +346,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 374 | ch: PeripheralRef<'a, C>, | 346 | ch: PeripheralRef<'a, C>, |
| 375 | data: &'a mut [W], | 347 | data: &'a mut [W], |
| 376 | ) -> Transfer<'a, C> { | 348 | ) -> Transfer<'a, C> { |
| 377 | unsafe { | 349 | let pio_no = PIO::PIO_NO; |
| 378 | let pio_no = PIO::PIO_NO; | 350 | let p = ch.regs(); |
| 379 | let p = ch.regs(); | 351 | p.write_addr().write_value(data.as_ptr() as u32); |
| 380 | p.write_addr().write_value(data.as_ptr() as u32); | 352 | p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); |
| 381 | p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); | 353 | p.trans_count().write_value(data.len() as u32); |
| 382 | p.trans_count().write_value(data.len() as u32); | 354 | compiler_fence(Ordering::SeqCst); |
| 383 | compiler_fence(Ordering::SeqCst); | 355 | p.ctrl_trig().write(|w| { |
| 384 | p.ctrl_trig().write(|w| { | 356 | // Set RX DREQ for this statemachine |
| 385 | // Set RX DREQ for this statemachine | 357 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); |
| 386 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); | 358 | w.set_data_size(W::size()); |
| 387 | w.set_data_size(W::size()); | 359 | w.set_chain_to(ch.number()); |
| 388 | w.set_chain_to(ch.number()); | 360 | w.set_incr_read(false); |
| 389 | w.set_incr_read(false); | 361 | w.set_incr_write(true); |
| 390 | w.set_incr_write(true); | 362 | w.set_en(true); |
| 391 | w.set_en(true); | 363 | }); |
| 392 | }); | 364 | compiler_fence(Ordering::SeqCst); |
| 393 | compiler_fence(Ordering::SeqCst); | ||
| 394 | } | ||
| 395 | Transfer::new(ch) | 365 | Transfer::new(ch) |
| 396 | } | 366 | } |
| 397 | } | 367 | } |
| @@ -402,42 +372,36 @@ pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> { | |||
| 402 | 372 | ||
| 403 | impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | 373 | impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { |
| 404 | pub fn empty(&self) -> bool { | 374 | pub fn empty(&self) -> bool { |
| 405 | unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } | 375 | PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 |
| 406 | } | 376 | } |
| 407 | pub fn full(&self) -> bool { | 377 | pub fn full(&self) -> bool { |
| 408 | unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } | 378 | PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 |
| 409 | } | 379 | } |
| 410 | 380 | ||
| 411 | pub fn level(&self) -> u8 { | 381 | pub fn level(&self) -> u8 { |
| 412 | unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } | 382 | (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f |
| 413 | } | 383 | } |
| 414 | 384 | ||
| 415 | pub fn stalled(&self) -> bool { | 385 | pub fn stalled(&self) -> bool { |
| 416 | unsafe { | 386 | let fdebug = PIO::PIO.fdebug(); |
| 417 | let fdebug = PIO::PIO.fdebug(); | 387 | let ret = fdebug.read().txstall() & (1 << SM) != 0; |
| 418 | let ret = fdebug.read().txstall() & (1 << SM) != 0; | 388 | if ret { |
| 419 | if ret { | 389 | fdebug.write(|w| w.set_txstall(1 << SM)); |
| 420 | fdebug.write(|w| w.set_txstall(1 << SM)); | ||
| 421 | } | ||
| 422 | ret | ||
| 423 | } | 390 | } |
| 391 | ret | ||
| 424 | } | 392 | } |
| 425 | 393 | ||
| 426 | pub fn overflowed(&self) -> bool { | 394 | pub fn overflowed(&self) -> bool { |
| 427 | unsafe { | 395 | let fdebug = PIO::PIO.fdebug(); |
| 428 | let fdebug = PIO::PIO.fdebug(); | 396 | let ret = fdebug.read().txover() & (1 << SM) != 0; |
| 429 | let ret = fdebug.read().txover() & (1 << SM) != 0; | 397 | if ret { |
| 430 | if ret { | 398 | fdebug.write(|w| w.set_txover(1 << SM)); |
| 431 | fdebug.write(|w| w.set_txover(1 << SM)); | ||
| 432 | } | ||
| 433 | ret | ||
| 434 | } | 399 | } |
| 400 | ret | ||
| 435 | } | 401 | } |
| 436 | 402 | ||
| 437 | pub fn push(&mut self, v: u32) { | 403 | pub fn push(&mut self, v: u32) { |
| 438 | unsafe { | 404 | PIO::PIO.txf(SM).write_value(v); |
| 439 | PIO::PIO.txf(SM).write_value(v); | ||
| 440 | } | ||
| 441 | } | 405 | } |
| 442 | 406 | ||
| 443 | pub fn try_push(&mut self, v: u32) -> bool { | 407 | pub fn try_push(&mut self, v: u32) -> bool { |
| @@ -453,24 +417,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 453 | } | 417 | } |
| 454 | 418 | ||
| 455 | pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { | 419 | pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { |
| 456 | unsafe { | 420 | let pio_no = PIO::PIO_NO; |
| 457 | let pio_no = PIO::PIO_NO; | 421 | let p = ch.regs(); |
| 458 | let p = ch.regs(); | 422 | p.read_addr().write_value(data.as_ptr() as u32); |
| 459 | p.read_addr().write_value(data.as_ptr() as u32); | 423 | p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); |
| 460 | p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); | 424 | p.trans_count().write_value(data.len() as u32); |
| 461 | p.trans_count().write_value(data.len() as u32); | 425 | compiler_fence(Ordering::SeqCst); |
| 462 | compiler_fence(Ordering::SeqCst); | 426 | p.ctrl_trig().write(|w| { |
| 463 | p.ctrl_trig().write(|w| { | 427 | // Set TX DREQ for this statemachine |
| 464 | // Set TX DREQ for this statemachine | 428 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); |
| 465 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); | 429 | w.set_data_size(W::size()); |
| 466 | w.set_data_size(W::size()); | 430 | w.set_chain_to(ch.number()); |
| 467 | w.set_chain_to(ch.number()); | 431 | w.set_incr_read(true); |
| 468 | w.set_incr_read(true); | 432 | w.set_incr_write(false); |
| 469 | w.set_incr_write(false); | 433 | w.set_en(true); |
| 470 | w.set_en(true); | 434 | }); |
| 471 | }); | 435 | compiler_fence(Ordering::SeqCst); |
| 472 | compiler_fence(Ordering::SeqCst); | ||
| 473 | } | ||
| 474 | Transfer::new(ch) | 436 | Transfer::new(ch) |
| 475 | } | 437 | } |
| 476 | } | 438 | } |
| @@ -482,9 +444,7 @@ pub struct StateMachine<'d, PIO: Instance, const SM: usize> { | |||
| 482 | 444 | ||
| 483 | impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { | 445 | impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { |
| 484 | fn drop(&mut self) { | 446 | fn drop(&mut self) { |
| 485 | unsafe { | 447 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); |
| 486 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); | ||
| 487 | } | ||
| 488 | on_pio_drop::<PIO>(); | 448 | on_pio_drop::<PIO>(); |
| 489 | } | 449 | } |
| 490 | } | 450 | } |
| @@ -647,45 +607,43 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 647 | assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); | 607 | assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); |
| 648 | assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); | 608 | assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); |
| 649 | let sm = Self::this_sm(); | 609 | let sm = Self::this_sm(); |
| 650 | unsafe { | 610 | sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); |
| 651 | sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); | 611 | sm.execctrl().write(|w| { |
| 652 | sm.execctrl().write(|w| { | 612 | w.set_side_en(config.exec.side_en); |
| 653 | w.set_side_en(config.exec.side_en); | 613 | w.set_side_pindir(config.exec.side_pindir); |
| 654 | w.set_side_pindir(config.exec.side_pindir); | 614 | w.set_jmp_pin(config.exec.jmp_pin); |
| 655 | w.set_jmp_pin(config.exec.jmp_pin); | 615 | w.set_out_en_sel(config.out_en_sel); |
| 656 | w.set_out_en_sel(config.out_en_sel); | 616 | w.set_inline_out_en(config.inline_out_en); |
| 657 | w.set_inline_out_en(config.inline_out_en); | 617 | w.set_out_sticky(config.out_sticky); |
| 658 | w.set_out_sticky(config.out_sticky); | 618 | w.set_wrap_top(config.exec.wrap_top); |
| 659 | w.set_wrap_top(config.exec.wrap_top); | 619 | w.set_wrap_bottom(config.exec.wrap_bottom); |
| 660 | w.set_wrap_bottom(config.exec.wrap_bottom); | 620 | w.set_status_sel(match config.status_sel { |
| 661 | w.set_status_sel(match config.status_sel { | 621 | StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, |
| 662 | StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, | 622 | StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, |
| 663 | StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, | ||
| 664 | }); | ||
| 665 | w.set_status_n(config.status_n); | ||
| 666 | }); | ||
| 667 | sm.shiftctrl().write(|w| { | ||
| 668 | w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); | ||
| 669 | w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly); | ||
| 670 | w.set_pull_thresh(config.shift_out.threshold); | ||
| 671 | w.set_push_thresh(config.shift_in.threshold); | ||
| 672 | w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right); | ||
| 673 | w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); | ||
| 674 | w.set_autopull(config.shift_out.auto_fill); | ||
| 675 | w.set_autopush(config.shift_in.auto_fill); | ||
| 676 | }); | ||
| 677 | sm.pinctrl().write(|w| { | ||
| 678 | w.set_sideset_count(config.pins.sideset_count); | ||
| 679 | w.set_set_count(config.pins.set_count); | ||
| 680 | w.set_out_count(config.pins.out_count); | ||
| 681 | w.set_in_base(config.pins.in_base); | ||
| 682 | w.set_sideset_base(config.pins.sideset_base); | ||
| 683 | w.set_set_base(config.pins.set_base); | ||
| 684 | w.set_out_base(config.pins.out_base); | ||
| 685 | }); | 623 | }); |
| 686 | if let Some(origin) = config.origin { | 624 | w.set_status_n(config.status_n); |
| 687 | pio_instr_util::exec_jmp(self, origin); | 625 | }); |
| 688 | } | 626 | sm.shiftctrl().write(|w| { |
| 627 | w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); | ||
| 628 | w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly); | ||
| 629 | w.set_pull_thresh(config.shift_out.threshold); | ||
| 630 | w.set_push_thresh(config.shift_in.threshold); | ||
| 631 | w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right); | ||
| 632 | w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); | ||
| 633 | w.set_autopull(config.shift_out.auto_fill); | ||
| 634 | w.set_autopush(config.shift_in.auto_fill); | ||
| 635 | }); | ||
| 636 | sm.pinctrl().write(|w| { | ||
| 637 | w.set_sideset_count(config.pins.sideset_count); | ||
| 638 | w.set_set_count(config.pins.set_count); | ||
| 639 | w.set_out_count(config.pins.out_count); | ||
| 640 | w.set_in_base(config.pins.in_base); | ||
| 641 | w.set_sideset_base(config.pins.sideset_base); | ||
| 642 | w.set_set_base(config.pins.set_base); | ||
| 643 | w.set_out_base(config.pins.out_base); | ||
| 644 | }); | ||
| 645 | if let Some(origin) = config.origin { | ||
| 646 | unsafe { pio_instr_util::exec_jmp(self, origin) } | ||
| 689 | } | 647 | } |
| 690 | } | 648 | } |
| 691 | 649 | ||
| @@ -696,45 +654,35 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 696 | 654 | ||
| 697 | pub fn restart(&mut self) { | 655 | pub fn restart(&mut self) { |
| 698 | let mask = 1u8 << SM; | 656 | let mask = 1u8 << SM; |
| 699 | unsafe { | 657 | PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); |
| 700 | PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); | ||
| 701 | } | ||
| 702 | } | 658 | } |
| 703 | pub fn set_enable(&mut self, enable: bool) { | 659 | pub fn set_enable(&mut self, enable: bool) { |
| 704 | let mask = 1u8 << SM; | 660 | let mask = 1u8 << SM; |
| 705 | unsafe { | 661 | if enable { |
| 706 | if enable { | 662 | PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); |
| 707 | PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); | 663 | } else { |
| 708 | } else { | 664 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); |
| 709 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); | ||
| 710 | } | ||
| 711 | } | 665 | } |
| 712 | } | 666 | } |
| 713 | 667 | ||
| 714 | pub fn is_enabled(&self) -> bool { | 668 | pub fn is_enabled(&self) -> bool { |
| 715 | unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } | 669 | PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 |
| 716 | } | 670 | } |
| 717 | 671 | ||
| 718 | pub fn clkdiv_restart(&mut self) { | 672 | pub fn clkdiv_restart(&mut self) { |
| 719 | let mask = 1u8 << SM; | 673 | let mask = 1u8 << SM; |
| 720 | unsafe { | 674 | PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); |
| 721 | PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); | ||
| 722 | } | ||
| 723 | } | 675 | } |
| 724 | 676 | ||
| 725 | fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { | 677 | fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { |
| 726 | let enabled = self.is_enabled(); | 678 | let enabled = self.is_enabled(); |
| 727 | self.set_enable(false); | 679 | self.set_enable(false); |
| 728 | let pincfg = unsafe { Self::this_sm().pinctrl().read() }; | 680 | let pincfg = Self::this_sm().pinctrl().read(); |
| 729 | let execcfg = unsafe { Self::this_sm().execctrl().read() }; | 681 | let execcfg = Self::this_sm().execctrl().read(); |
| 730 | unsafe { | 682 | Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true)); |
| 731 | Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true)); | ||
| 732 | } | ||
| 733 | f(self); | 683 | f(self); |
| 734 | unsafe { | 684 | Self::this_sm().pinctrl().write_value(pincfg); |
| 735 | Self::this_sm().pinctrl().write_value(pincfg); | 685 | Self::this_sm().execctrl().write_value(execcfg); |
| 736 | Self::this_sm().execctrl().write_value(execcfg); | ||
| 737 | } | ||
| 738 | self.set_enable(enabled); | 686 | self.set_enable(enabled); |
| 739 | } | 687 | } |
| 740 | 688 | ||
| @@ -743,14 +691,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 743 | pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { | 691 | pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { |
| 744 | self.with_paused(|sm| { | 692 | self.with_paused(|sm| { |
| 745 | for pin in pins { | 693 | for pin in pins { |
| 746 | unsafe { | 694 | Self::this_sm().pinctrl().write(|w| { |
| 747 | Self::this_sm().pinctrl().write(|w| { | 695 | w.set_set_base(pin.pin()); |
| 748 | w.set_set_base(pin.pin()); | 696 | w.set_set_count(1); |
| 749 | w.set_set_count(1); | 697 | }); |
| 750 | }); | 698 | // SET PINDIRS, (dir) |
| 751 | // SET PINDIRS, (dir) | 699 | unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) }; |
| 752 | sm.exec_instr(0b111_00000_100_00000 | dir as u16); | ||
| 753 | } | ||
| 754 | } | 700 | } |
| 755 | }); | 701 | }); |
| 756 | } | 702 | } |
| @@ -760,29 +706,25 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 760 | pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { | 706 | pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { |
| 761 | self.with_paused(|sm| { | 707 | self.with_paused(|sm| { |
| 762 | for pin in pins { | 708 | for pin in pins { |
| 763 | unsafe { | 709 | Self::this_sm().pinctrl().write(|w| { |
| 764 | Self::this_sm().pinctrl().write(|w| { | 710 | w.set_set_base(pin.pin()); |
| 765 | w.set_set_base(pin.pin()); | 711 | w.set_set_count(1); |
| 766 | w.set_set_count(1); | 712 | }); |
| 767 | }); | 713 | // SET PINS, (dir) |
| 768 | // SET PINS, (dir) | 714 | unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) }; |
| 769 | sm.exec_instr(0b111_00000_000_00000 | level as u16); | ||
| 770 | } | ||
| 771 | } | 715 | } |
| 772 | }); | 716 | }); |
| 773 | } | 717 | } |
| 774 | 718 | ||
| 775 | pub fn clear_fifos(&mut self) { | 719 | pub fn clear_fifos(&mut self) { |
| 776 | // Toggle FJOIN_RX to flush FIFOs | 720 | // Toggle FJOIN_RX to flush FIFOs |
| 777 | unsafe { | 721 | let shiftctrl = Self::this_sm().shiftctrl(); |
| 778 | let shiftctrl = Self::this_sm().shiftctrl(); | 722 | shiftctrl.modify(|w| { |
| 779 | shiftctrl.modify(|w| { | 723 | w.set_fjoin_rx(!w.fjoin_rx()); |
| 780 | w.set_fjoin_rx(!w.fjoin_rx()); | 724 | }); |
| 781 | }); | 725 | shiftctrl.modify(|w| { |
| 782 | shiftctrl.modify(|w| { | 726 | w.set_fjoin_rx(!w.fjoin_rx()); |
| 783 | w.set_fjoin_rx(!w.fjoin_rx()); | 727 | }); |
| 784 | }); | ||
| 785 | } | ||
| 786 | } | 728 | } |
| 787 | 729 | ||
| 788 | pub unsafe fn exec_instr(&mut self, instr: u16) { | 730 | pub unsafe fn exec_instr(&mut self, instr: u16) { |
| @@ -856,11 +798,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 856 | if (self.instructions_used | used_mask) & mask != 0 { | 798 | if (self.instructions_used | used_mask) & mask != 0 { |
| 857 | return Err(addr); | 799 | return Err(addr); |
| 858 | } | 800 | } |
| 859 | unsafe { | 801 | PIO::PIO.instr_mem(addr).write(|w| { |
| 860 | PIO::PIO.instr_mem(addr).write(|w| { | 802 | w.set_instr_mem(instr); |
| 861 | w.set_instr_mem(instr); | 803 | }); |
| 862 | }); | ||
| 863 | } | ||
| 864 | used_mask |= mask; | 804 | used_mask |= mask; |
| 865 | } | 805 | } |
| 866 | self.instructions_used |= used_mask; | 806 | self.instructions_used |= used_mask; |
| @@ -877,17 +817,15 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 877 | } | 817 | } |
| 878 | 818 | ||
| 879 | pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { | 819 | pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { |
| 880 | unsafe { | 820 | // this can interfere with per-pin bypass functions. splitting the |
| 881 | // this can interfere with per-pin bypass functions. splitting the | 821 | // modification is going to be fine since nothing that relies on |
| 882 | // modification is going to be fine since nothing that relies on | 822 | // it can reasonably run before we finish. |
| 883 | // it can reasonably run before we finish. | 823 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); |
| 884 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); | 824 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); |
| 885 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); | ||
| 886 | } | ||
| 887 | } | 825 | } |
| 888 | 826 | ||
| 889 | pub fn get_input_sync_bypass(&self) -> u32 { | 827 | pub fn get_input_sync_bypass(&self) -> u32 { |
| 890 | unsafe { PIO::PIO.input_sync_bypass().read() } | 828 | PIO::PIO.input_sync_bypass().read() |
| 891 | } | 829 | } |
| 892 | 830 | ||
| 893 | /// Register a pin for PIO usage. Pins will be released from the PIO block | 831 | /// Register a pin for PIO usage. Pins will be released from the PIO block |
| @@ -896,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 896 | /// of [`Pio`] do not keep pin registrations alive.** | 834 | /// of [`Pio`] do not keep pin registrations alive.** |
| 897 | pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { | 835 | pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { |
| 898 | into_ref!(pin); | 836 | into_ref!(pin); |
| 899 | unsafe { | 837 | pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); |
| 900 | pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); | ||
| 901 | } | ||
| 902 | // we can be relaxed about this because we're &mut here and nothing is cached | 838 | // we can be relaxed about this because we're &mut here and nothing is cached |
| 903 | PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); | 839 | PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); |
| 904 | Pin { | 840 | Pin { |
| @@ -916,13 +852,11 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 916 | _pio: PhantomData, | 852 | _pio: PhantomData, |
| 917 | }; | 853 | }; |
| 918 | f(&mut batch); | 854 | f(&mut batch); |
| 919 | unsafe { | 855 | PIO::PIO.ctrl().modify(|w| { |
| 920 | PIO::PIO.ctrl().modify(|w| { | 856 | w.set_clkdiv_restart(batch.clkdiv_restart); |
| 921 | w.set_clkdiv_restart(batch.clkdiv_restart); | 857 | w.set_sm_restart(batch.sm_restart); |
| 922 | w.set_sm_restart(batch.sm_restart); | 858 | w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); |
| 923 | w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); | 859 | }); |
| 924 | }); | ||
| 925 | } | ||
| 926 | } | 860 | } |
| 927 | } | 861 | } |
| 928 | 862 | ||
| @@ -974,11 +908,11 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> { | |||
| 974 | } | 908 | } |
| 975 | 909 | ||
| 976 | pub fn check_any(&self, irqs: u8) -> bool { | 910 | pub fn check_any(&self, irqs: u8) -> bool { |
| 977 | unsafe { PIO::PIO.irq().read().irq() & irqs != 0 } | 911 | PIO::PIO.irq().read().irq() & irqs != 0 |
| 978 | } | 912 | } |
| 979 | 913 | ||
| 980 | pub fn check_all(&self, irqs: u8) -> bool { | 914 | pub fn check_all(&self, irqs: u8) -> bool { |
| 981 | unsafe { PIO::PIO.irq().read().irq() & irqs == irqs } | 915 | PIO::PIO.irq().read().irq() & irqs == irqs |
| 982 | } | 916 | } |
| 983 | 917 | ||
| 984 | pub fn clear(&self, irq_no: usize) { | 918 | pub fn clear(&self, irq_no: usize) { |
| @@ -987,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> { | |||
| 987 | } | 921 | } |
| 988 | 922 | ||
| 989 | pub fn clear_all(&self, irqs: u8) { | 923 | pub fn clear_all(&self, irqs: u8) { |
| 990 | unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } | 924 | PIO::PIO.irq().write(|w| w.set_irq(irqs)) |
| 991 | } | 925 | } |
| 992 | 926 | ||
| 993 | pub fn set(&self, irq_no: usize) { | 927 | pub fn set(&self, irq_no: usize) { |
| @@ -996,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> { | |||
| 996 | } | 930 | } |
| 997 | 931 | ||
| 998 | pub fn set_all(&self, irqs: u8) { | 932 | pub fn set_all(&self, irqs: u8) { |
| 999 | unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } | 933 | PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) |
| 1000 | } | 934 | } |
| 1001 | } | 935 | } |
| 1002 | 936 | ||
| @@ -1068,9 +1002,7 @@ fn on_pio_drop<PIO: Instance>() { | |||
| 1068 | // we only have 30 pins. don't test the other two since gpio() asserts. | 1002 | // we only have 30 pins. don't test the other two since gpio() asserts. |
| 1069 | for i in 0..30 { | 1003 | for i in 0..30 { |
| 1070 | if used_pins & (1 << i) != 0 { | 1004 | if used_pins & (1 << i) != 0 { |
| 1071 | unsafe { | 1005 | pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); |
| 1072 | pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); | ||
| 1073 | } | ||
| 1074 | } | 1006 | } |
| 1075 | } | 1007 | } |
| 1076 | } | 1008 | } |
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 0f9dcf479..20bb88446 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs | |||
| @@ -71,20 +71,18 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 71 | into_ref!(inner); | 71 | into_ref!(inner); |
| 72 | 72 | ||
| 73 | let p = inner.regs(); | 73 | let p = inner.regs(); |
| 74 | unsafe { | 74 | p.csr().modify(|w| { |
| 75 | p.csr().modify(|w| { | 75 | w.set_divmode(divmode); |
| 76 | w.set_divmode(divmode); | 76 | w.set_en(false); |
| 77 | w.set_en(false); | 77 | }); |
| 78 | }); | 78 | p.ctr().write(|w| w.0 = 0); |
| 79 | p.ctr().write(|w| w.0 = 0); | 79 | Self::configure(p, &config); |
| 80 | Self::configure(p, &config); | 80 | |
| 81 | 81 | if let Some(pin) = &a { | |
| 82 | if let Some(pin) = &a { | 82 | pin.io().ctrl().write(|w| w.set_funcsel(4)); |
| 83 | pin.io().ctrl().write(|w| w.set_funcsel(4)); | 83 | } |
| 84 | } | 84 | if let Some(pin) = &b { |
| 85 | if let Some(pin) = &b { | 85 | pin.io().ctrl().write(|w| w.set_funcsel(4)); |
| 86 | pin.io().ctrl().write(|w| w.set_funcsel(4)); | ||
| 87 | } | ||
| 88 | } | 86 | } |
| 89 | Self { | 87 | Self { |
| 90 | inner, | 88 | inner, |
| @@ -161,31 +159,29 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 161 | panic!("Requested divider is too large"); | 159 | panic!("Requested divider is too large"); |
| 162 | } | 160 | } |
| 163 | 161 | ||
| 164 | unsafe { | 162 | p.div().write_value(ChDiv(config.divider.to_bits() as u32)); |
| 165 | p.div().write_value(ChDiv(config.divider.to_bits() as u32)); | 163 | p.cc().write(|w| { |
| 166 | p.cc().write(|w| { | 164 | w.set_a(config.compare_a); |
| 167 | w.set_a(config.compare_a); | 165 | w.set_b(config.compare_b); |
| 168 | w.set_b(config.compare_b); | 166 | }); |
| 169 | }); | 167 | p.top().write(|w| w.set_top(config.top)); |
| 170 | p.top().write(|w| w.set_top(config.top)); | 168 | p.csr().modify(|w| { |
| 171 | p.csr().modify(|w| { | 169 | w.set_a_inv(config.invert_a); |
| 172 | w.set_a_inv(config.invert_a); | 170 | w.set_b_inv(config.invert_b); |
| 173 | w.set_b_inv(config.invert_b); | 171 | w.set_ph_correct(config.phase_correct); |
| 174 | w.set_ph_correct(config.phase_correct); | 172 | w.set_en(config.enable); |
| 175 | w.set_en(config.enable); | 173 | }); |
| 176 | }); | ||
| 177 | } | ||
| 178 | } | 174 | } |
| 179 | 175 | ||
| 180 | #[inline] | 176 | #[inline] |
| 181 | pub unsafe fn phase_advance(&mut self) { | 177 | pub fn phase_advance(&mut self) { |
| 182 | let p = self.inner.regs(); | 178 | let p = self.inner.regs(); |
| 183 | p.csr().write_set(|w| w.set_ph_adv(true)); | 179 | p.csr().write_set(|w| w.set_ph_adv(true)); |
| 184 | while p.csr().read().ph_adv() {} | 180 | while p.csr().read().ph_adv() {} |
| 185 | } | 181 | } |
| 186 | 182 | ||
| 187 | #[inline] | 183 | #[inline] |
| 188 | pub unsafe fn phase_retard(&mut self) { | 184 | pub fn phase_retard(&mut self) { |
| 189 | let p = self.inner.regs(); | 185 | let p = self.inner.regs(); |
| 190 | p.csr().write_set(|w| w.set_ph_ret(true)); | 186 | p.csr().write_set(|w| w.set_ph_ret(true)); |
| 191 | while p.csr().read().ph_ret() {} | 187 | while p.csr().read().ph_ret() {} |
| @@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 193 | 189 | ||
| 194 | #[inline] | 190 | #[inline] |
| 195 | pub fn counter(&self) -> u16 { | 191 | pub fn counter(&self) -> u16 { |
| 196 | unsafe { self.inner.regs().ctr().read().ctr() } | 192 | self.inner.regs().ctr().read().ctr() |
| 197 | } | 193 | } |
| 198 | 194 | ||
| 199 | #[inline] | 195 | #[inline] |
| 200 | pub fn set_counter(&self, ctr: u16) { | 196 | pub fn set_counter(&self, ctr: u16) { |
| 201 | unsafe { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) } | 197 | self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) |
| 202 | } | 198 | } |
| 203 | 199 | ||
| 204 | #[inline] | 200 | #[inline] |
| @@ -209,14 +205,12 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 209 | 205 | ||
| 210 | #[inline] | 206 | #[inline] |
| 211 | pub fn wrapped(&mut self) -> bool { | 207 | pub fn wrapped(&mut self) -> bool { |
| 212 | unsafe { pac::PWM.intr().read().0 & self.bit() != 0 } | 208 | pac::PWM.intr().read().0 & self.bit() != 0 |
| 213 | } | 209 | } |
| 214 | 210 | ||
| 215 | #[inline] | 211 | #[inline] |
| 216 | pub fn clear_wrapped(&mut self) { | 212 | pub fn clear_wrapped(&mut self) { |
| 217 | unsafe { | 213 | pac::PWM.intr().write_value(Intr(self.bit() as _)); |
| 218 | pac::PWM.intr().write_value(Intr(self.bit() as _)); | ||
| 219 | } | ||
| 220 | } | 214 | } |
| 221 | 215 | ||
| 222 | #[inline] | 216 | #[inline] |
| @@ -237,26 +231,22 @@ impl PwmBatch { | |||
| 237 | pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { | 231 | pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { |
| 238 | let mut en = PwmBatch(0); | 232 | let mut en = PwmBatch(0); |
| 239 | batch(&mut en); | 233 | batch(&mut en); |
| 240 | unsafe { | 234 | if enabled { |
| 241 | if enabled { | 235 | pac::PWM.en().write_set(|w| w.0 = en.0); |
| 242 | pac::PWM.en().write_set(|w| w.0 = en.0); | 236 | } else { |
| 243 | } else { | 237 | pac::PWM.en().write_clear(|w| w.0 = en.0); |
| 244 | pac::PWM.en().write_clear(|w| w.0 = en.0); | ||
| 245 | } | ||
| 246 | } | 238 | } |
| 247 | } | 239 | } |
| 248 | } | 240 | } |
| 249 | 241 | ||
| 250 | impl<'d, T: Channel> Drop for Pwm<'d, T> { | 242 | impl<'d, T: Channel> Drop for Pwm<'d, T> { |
| 251 | fn drop(&mut self) { | 243 | fn drop(&mut self) { |
| 252 | unsafe { | 244 | self.inner.regs().csr().write_clear(|w| w.set_en(false)); |
| 253 | self.inner.regs().csr().write_clear(|w| w.set_en(false)); | 245 | if let Some(pin) = &self.pin_a { |
| 254 | if let Some(pin) = &self.pin_a { | 246 | pin.io().ctrl().write(|w| w.set_funcsel(31)); |
| 255 | pin.io().ctrl().write(|w| w.set_funcsel(31)); | 247 | } |
| 256 | } | 248 | if let Some(pin) = &self.pin_b { |
| 257 | if let Some(pin) = &self.pin_b { | 249 | pin.io().ctrl().write(|w| w.set_funcsel(31)); |
| 258 | pin.io().ctrl().write(|w| w.set_funcsel(31)); | ||
| 259 | } | ||
| 260 | } | 250 | } |
| 261 | } | 251 | } |
| 262 | } | 252 | } |
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs index edd47c223..70512fa14 100644 --- a/embassy-rp/src/reset.rs +++ b/embassy-rp/src/reset.rs | |||
| @@ -4,11 +4,11 @@ use crate::pac; | |||
| 4 | 4 | ||
| 5 | pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); | 5 | pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); |
| 6 | 6 | ||
| 7 | pub unsafe fn reset(peris: Peripherals) { | 7 | pub(crate) fn reset(peris: Peripherals) { |
| 8 | pac::RESETS.reset().write_value(peris); | 8 | pac::RESETS.reset().write_value(peris); |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | pub unsafe fn unreset_wait(peris: Peripherals) { | 11 | pub(crate) fn unreset_wait(peris: Peripherals) { |
| 12 | // TODO use the "atomic clear" register version | 12 | // TODO use the "atomic clear" register version |
| 13 | pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); | 13 | pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); |
| 14 | while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} | 14 | while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} |
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index e1d886d4a..b18f12fc4 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs | |||
| @@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 26 | into_ref!(inner); | 26 | into_ref!(inner); |
| 27 | 27 | ||
| 28 | // Set the RTC divider | 28 | // Set the RTC divider |
| 29 | unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) }; | 29 | inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); |
| 30 | 30 | ||
| 31 | let mut result = Self { inner }; | 31 | let mut result = Self { inner }; |
| 32 | result.set_leap_year_check(true); // should be on by default, make sure this is the case. | 32 | result.set_leap_year_check(true); // should be on by default, make sure this is the case. |
| @@ -38,17 +38,14 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 38 | /// | 38 | /// |
| 39 | /// Leap year checking is enabled by default. | 39 | /// Leap year checking is enabled by default. |
| 40 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { | 40 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { |
| 41 | unsafe { | 41 | self.inner.regs().ctrl().modify(|w| { |
| 42 | self.inner | 42 | w.set_force_notleapyear(!leap_year_check_enabled); |
| 43 | .regs() | 43 | }); |
| 44 | .ctrl() | ||
| 45 | .modify(|w| w.set_force_notleapyear(!leap_year_check_enabled)) | ||
| 46 | }; | ||
| 47 | } | 44 | } |
| 48 | 45 | ||
| 49 | /// Checks to see if this RealTimeClock is running | 46 | /// Checks to see if this RealTimeClock is running |
| 50 | pub fn is_running(&self) -> bool { | 47 | pub fn is_running(&self) -> bool { |
| 51 | unsafe { self.inner.regs().ctrl().read().rtc_active() } | 48 | self.inner.regs().ctrl().read().rtc_active() |
| 52 | } | 49 | } |
| 53 | 50 | ||
| 54 | /// Set the datetime to a new value. | 51 | /// Set the datetime to a new value. |
| @@ -60,25 +57,23 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 60 | self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; | 57 | self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; |
| 61 | 58 | ||
| 62 | // disable RTC while we configure it | 59 | // disable RTC while we configure it |
| 63 | unsafe { | 60 | self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); |
| 64 | self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); | 61 | while self.inner.regs().ctrl().read().rtc_active() { |
| 65 | while self.inner.regs().ctrl().read().rtc_active() { | 62 | core::hint::spin_loop(); |
| 66 | core::hint::spin_loop(); | 63 | } |
| 67 | } | 64 | |
| 68 | 65 | self.inner.regs().setup_0().write(|w| { | |
| 69 | self.inner.regs().setup_0().write(|w| { | 66 | self::datetime::write_setup_0(&t, w); |
| 70 | self::datetime::write_setup_0(&t, w); | 67 | }); |
| 71 | }); | 68 | self.inner.regs().setup_1().write(|w| { |
| 72 | self.inner.regs().setup_1().write(|w| { | 69 | self::datetime::write_setup_1(&t, w); |
| 73 | self::datetime::write_setup_1(&t, w); | 70 | }); |
| 74 | }); | 71 | |
| 75 | 72 | // Load the new datetime and re-enable RTC | |
| 76 | // Load the new datetime and re-enable RTC | 73 | self.inner.regs().ctrl().write(|w| w.set_load(true)); |
| 77 | self.inner.regs().ctrl().write(|w| w.set_load(true)); | 74 | self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); |
| 78 | self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); | 75 | while !self.inner.regs().ctrl().read().rtc_active() { |
| 79 | while !self.inner.regs().ctrl().read().rtc_active() { | 76 | core::hint::spin_loop(); |
| 80 | core::hint::spin_loop(); | ||
| 81 | } | ||
| 82 | } | 77 | } |
| 83 | Ok(()) | 78 | Ok(()) |
| 84 | } | 79 | } |
| @@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 93 | return Err(RtcError::NotRunning); | 88 | return Err(RtcError::NotRunning); |
| 94 | } | 89 | } |
| 95 | 90 | ||
| 96 | let rtc_0 = unsafe { self.inner.regs().rtc_0().read() }; | 91 | let rtc_0 = self.inner.regs().rtc_0().read(); |
| 97 | let rtc_1 = unsafe { self.inner.regs().rtc_1().read() }; | 92 | let rtc_1 = self.inner.regs().rtc_1().read(); |
| 98 | 93 | ||
| 99 | self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) | 94 | self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) |
| 100 | } | 95 | } |
| @@ -103,12 +98,10 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 103 | /// | 98 | /// |
| 104 | /// [`schedule_alarm`]: #method.schedule_alarm | 99 | /// [`schedule_alarm`]: #method.schedule_alarm |
| 105 | pub fn disable_alarm(&mut self) { | 100 | pub fn disable_alarm(&mut self) { |
| 106 | unsafe { | 101 | self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false)); |
| 107 | self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false)); | ||
| 108 | 102 | ||
| 109 | while self.inner.regs().irq_setup_0().read().match_active() { | 103 | while self.inner.regs().irq_setup_0().read().match_active() { |
| 110 | core::hint::spin_loop(); | 104 | core::hint::spin_loop(); |
| 111 | } | ||
| 112 | } | 105 | } |
| 113 | } | 106 | } |
| 114 | 107 | ||
| @@ -132,21 +125,19 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 132 | pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { | 125 | pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { |
| 133 | self.disable_alarm(); | 126 | self.disable_alarm(); |
| 134 | 127 | ||
| 135 | unsafe { | 128 | self.inner.regs().irq_setup_0().write(|w| { |
| 136 | self.inner.regs().irq_setup_0().write(|w| { | 129 | filter.write_setup_0(w); |
| 137 | filter.write_setup_0(w); | 130 | }); |
| 138 | }); | 131 | self.inner.regs().irq_setup_1().write(|w| { |
| 139 | self.inner.regs().irq_setup_1().write(|w| { | 132 | filter.write_setup_1(w); |
| 140 | filter.write_setup_1(w); | 133 | }); |
| 141 | }); | 134 | |
| 142 | 135 | self.inner.regs().inte().modify(|w| w.set_rtc(true)); | |
| 143 | self.inner.regs().inte().modify(|w| w.set_rtc(true)); | 136 | |
| 144 | 137 | // Set the enable bit and check if it is set | |
| 145 | // Set the enable bit and check if it is set | 138 | self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); |
| 146 | self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); | 139 | while !self.inner.regs().irq_setup_0().read().match_active() { |
| 147 | while !self.inner.regs().irq_setup_0().read().match_active() { | 140 | core::hint::spin_loop(); |
| 148 | core::hint::spin_loop(); | ||
| 149 | } | ||
| 150 | } | 141 | } |
| 151 | } | 142 | } |
| 152 | 143 | ||
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 7da214743..e817d074e 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -79,39 +79,37 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 79 | ) -> Self { | 79 | ) -> Self { |
| 80 | into_ref!(inner); | 80 | into_ref!(inner); |
| 81 | 81 | ||
| 82 | unsafe { | 82 | let p = inner.regs(); |
| 83 | let p = inner.regs(); | 83 | let (presc, postdiv) = calc_prescs(config.frequency); |
| 84 | let (presc, postdiv) = calc_prescs(config.frequency); | 84 | |
| 85 | 85 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | |
| 86 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | 86 | p.cr0().write(|w| { |
| 87 | p.cr0().write(|w| { | 87 | w.set_dss(0b0111); // 8bit |
| 88 | w.set_dss(0b0111); // 8bit | 88 | w.set_spo(config.polarity == Polarity::IdleHigh); |
| 89 | w.set_spo(config.polarity == Polarity::IdleHigh); | 89 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); |
| 90 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); | 90 | w.set_scr(postdiv); |
| 91 | w.set_scr(postdiv); | 91 | }); |
| 92 | }); | 92 | |
| 93 | 93 | // Always enable DREQ signals -- harmless if DMA is not listening | |
| 94 | // Always enable DREQ signals -- harmless if DMA is not listening | 94 | p.dmacr().write(|reg| { |
| 95 | p.dmacr().write(|reg| { | 95 | reg.set_rxdmae(true); |
| 96 | reg.set_rxdmae(true); | 96 | reg.set_txdmae(true); |
| 97 | reg.set_txdmae(true); | 97 | }); |
| 98 | }); | 98 | |
| 99 | 99 | // finally, enable. | |
| 100 | // finally, enable. | 100 | p.cr1().write(|w| w.set_sse(true)); |
| 101 | p.cr1().write(|w| w.set_sse(true)); | 101 | |
| 102 | 102 | if let Some(pin) = &clk { | |
| 103 | if let Some(pin) = &clk { | 103 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 104 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 104 | } |
| 105 | } | 105 | if let Some(pin) = &mosi { |
| 106 | if let Some(pin) = &mosi { | 106 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 107 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 107 | } |
| 108 | } | 108 | if let Some(pin) = &miso { |
| 109 | if let Some(pin) = &miso { | 109 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 110 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 110 | } |
| 111 | } | 111 | if let Some(pin) = &cs { |
| 112 | if let Some(pin) = &cs { | 112 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 113 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | ||
| 114 | } | ||
| 115 | } | 113 | } |
| 116 | Self { | 114 | Self { |
| 117 | inner, | 115 | inner, |
| @@ -122,60 +120,52 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 122 | } | 120 | } |
| 123 | 121 | ||
| 124 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { | 122 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { |
| 125 | unsafe { | 123 | let p = self.inner.regs(); |
| 126 | let p = self.inner.regs(); | 124 | for &b in data { |
| 127 | for &b in data { | 125 | while !p.sr().read().tnf() {} |
| 128 | while !p.sr().read().tnf() {} | 126 | p.dr().write(|w| w.set_data(b as _)); |
| 129 | p.dr().write(|w| w.set_data(b as _)); | 127 | while !p.sr().read().rne() {} |
| 130 | while !p.sr().read().rne() {} | 128 | let _ = p.dr().read(); |
| 131 | let _ = p.dr().read(); | ||
| 132 | } | ||
| 133 | } | 129 | } |
| 134 | self.flush()?; | 130 | self.flush()?; |
| 135 | Ok(()) | 131 | Ok(()) |
| 136 | } | 132 | } |
| 137 | 133 | ||
| 138 | pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { | 134 | pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { |
| 139 | unsafe { | 135 | let p = self.inner.regs(); |
| 140 | let p = self.inner.regs(); | 136 | for b in data { |
| 141 | for b in data { | 137 | while !p.sr().read().tnf() {} |
| 142 | while !p.sr().read().tnf() {} | 138 | p.dr().write(|w| w.set_data(*b as _)); |
| 143 | p.dr().write(|w| w.set_data(*b as _)); | 139 | while !p.sr().read().rne() {} |
| 144 | while !p.sr().read().rne() {} | 140 | *b = p.dr().read().data() as u8; |
| 145 | *b = p.dr().read().data() as u8; | ||
| 146 | } | ||
| 147 | } | 141 | } |
| 148 | self.flush()?; | 142 | self.flush()?; |
| 149 | Ok(()) | 143 | Ok(()) |
| 150 | } | 144 | } |
| 151 | 145 | ||
| 152 | pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { | 146 | pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { |
| 153 | unsafe { | 147 | let p = self.inner.regs(); |
| 154 | let p = self.inner.regs(); | 148 | for b in data { |
| 155 | for b in data { | 149 | while !p.sr().read().tnf() {} |
| 156 | while !p.sr().read().tnf() {} | 150 | p.dr().write(|w| w.set_data(0)); |
| 157 | p.dr().write(|w| w.set_data(0)); | 151 | while !p.sr().read().rne() {} |
| 158 | while !p.sr().read().rne() {} | 152 | *b = p.dr().read().data() as u8; |
| 159 | *b = p.dr().read().data() as u8; | ||
| 160 | } | ||
| 161 | } | 153 | } |
| 162 | self.flush()?; | 154 | self.flush()?; |
| 163 | Ok(()) | 155 | Ok(()) |
| 164 | } | 156 | } |
| 165 | 157 | ||
| 166 | pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { | 158 | pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { |
| 167 | unsafe { | 159 | let p = self.inner.regs(); |
| 168 | let p = self.inner.regs(); | 160 | let len = read.len().max(write.len()); |
| 169 | let len = read.len().max(write.len()); | 161 | for i in 0..len { |
| 170 | for i in 0..len { | 162 | let wb = write.get(i).copied().unwrap_or(0); |
| 171 | let wb = write.get(i).copied().unwrap_or(0); | 163 | while !p.sr().read().tnf() {} |
| 172 | while !p.sr().read().tnf() {} | 164 | p.dr().write(|w| w.set_data(wb as _)); |
| 173 | p.dr().write(|w| w.set_data(wb as _)); | 165 | while !p.sr().read().rne() {} |
| 174 | while !p.sr().read().rne() {} | 166 | let rb = p.dr().read().data() as u8; |
| 175 | let rb = p.dr().read().data() as u8; | 167 | if let Some(r) = read.get_mut(i) { |
| 176 | if let Some(r) = read.get_mut(i) { | 168 | *r = rb; |
| 177 | *r = rb; | ||
| 178 | } | ||
| 179 | } | 169 | } |
| 180 | } | 170 | } |
| 181 | self.flush()?; | 171 | self.flush()?; |
| @@ -183,29 +173,25 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 183 | } | 173 | } |
| 184 | 174 | ||
| 185 | pub fn flush(&mut self) -> Result<(), Error> { | 175 | pub fn flush(&mut self) -> Result<(), Error> { |
| 186 | unsafe { | 176 | let p = self.inner.regs(); |
| 187 | let p = self.inner.regs(); | 177 | while p.sr().read().bsy() {} |
| 188 | while p.sr().read().bsy() {} | ||
| 189 | } | ||
| 190 | Ok(()) | 178 | Ok(()) |
| 191 | } | 179 | } |
| 192 | 180 | ||
| 193 | pub fn set_frequency(&mut self, freq: u32) { | 181 | pub fn set_frequency(&mut self, freq: u32) { |
| 194 | let (presc, postdiv) = calc_prescs(freq); | 182 | let (presc, postdiv) = calc_prescs(freq); |
| 195 | let p = self.inner.regs(); | 183 | let p = self.inner.regs(); |
| 196 | unsafe { | 184 | // disable |
| 197 | // disable | 185 | p.cr1().write(|w| w.set_sse(false)); |
| 198 | p.cr1().write(|w| w.set_sse(false)); | 186 | |
| 199 | 187 | // change stuff | |
| 200 | // change stuff | 188 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); |
| 201 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | 189 | p.cr0().modify(|w| { |
| 202 | p.cr0().modify(|w| { | 190 | w.set_scr(postdiv); |
| 203 | w.set_scr(postdiv); | 191 | }); |
| 204 | }); | 192 | |
| 205 | 193 | // enable | |
| 206 | // enable | 194 | p.cr1().write(|w| w.set_sse(true)); |
| 207 | p.cr1().write(|w| w.set_sse(true)); | ||
| 208 | } | ||
| 209 | } | 195 | } |
| 210 | } | 196 | } |
| 211 | 197 | ||
| @@ -337,21 +323,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 337 | let tx_transfer = unsafe { | 323 | let tx_transfer = unsafe { |
| 338 | // If we don't assign future to a variable, the data register pointer | 324 | // If we don't assign future to a variable, the data register pointer |
| 339 | // is held across an await and makes the future non-Send. | 325 | // is held across an await and makes the future non-Send. |
| 340 | crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | 326 | crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ) |
| 341 | }; | 327 | }; |
| 342 | tx_transfer.await; | 328 | tx_transfer.await; |
| 343 | 329 | ||
| 344 | let p = self.inner.regs(); | 330 | let p = self.inner.regs(); |
| 345 | unsafe { | 331 | while p.sr().read().bsy() {} |
| 346 | while p.sr().read().bsy() {} | ||
| 347 | 332 | ||
| 348 | // clear RX FIFO contents to prevent stale reads | 333 | // clear RX FIFO contents to prevent stale reads |
| 349 | while p.sr().read().rne() { | 334 | while p.sr().read().rne() { |
| 350 | let _: u16 = p.dr().read().data(); | 335 | let _: u16 = p.dr().read().data(); |
| 351 | } | ||
| 352 | // clear RX overrun interrupt | ||
| 353 | p.icr().write(|w| w.set_roric(true)); | ||
| 354 | } | 336 | } |
| 337 | // clear RX overrun interrupt | ||
| 338 | p.icr().write(|w| w.set_roric(true)); | ||
| 355 | 339 | ||
| 356 | Ok(()) | 340 | Ok(()) |
| 357 | } | 341 | } |
| @@ -363,14 +347,19 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 363 | let rx_transfer = unsafe { | 347 | let rx_transfer = unsafe { |
| 364 | // If we don't assign future to a variable, the data register pointer | 348 | // If we don't assign future to a variable, the data register pointer |
| 365 | // is held across an await and makes the future non-Send. | 349 | // is held across an await and makes the future non-Send. |
| 366 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) | 350 | crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ) |
| 367 | }; | 351 | }; |
| 368 | 352 | ||
| 369 | let tx_ch = self.tx_dma.as_mut().unwrap(); | 353 | let tx_ch = self.tx_dma.as_mut().unwrap(); |
| 370 | let tx_transfer = unsafe { | 354 | let tx_transfer = unsafe { |
| 371 | // If we don't assign future to a variable, the data register pointer | 355 | // If we don't assign future to a variable, the data register pointer |
| 372 | // is held across an await and makes the future non-Send. | 356 | // is held across an await and makes the future non-Send. |
| 373 | crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ) | 357 | crate::dma::write_repeated( |
| 358 | tx_ch, | ||
| 359 | self.inner.regs().dr().as_ptr() as *mut u8, | ||
| 360 | buffer.len(), | ||
| 361 | T::TX_DREQ, | ||
| 362 | ) | ||
| 374 | }; | 363 | }; |
| 375 | join(tx_transfer, rx_transfer).await; | 364 | join(tx_transfer, rx_transfer).await; |
| 376 | Ok(()) | 365 | Ok(()) |
| @@ -394,7 +383,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 394 | let rx_transfer = unsafe { | 383 | let rx_transfer = unsafe { |
| 395 | // If we don't assign future to a variable, the data register pointer | 384 | // If we don't assign future to a variable, the data register pointer |
| 396 | // is held across an await and makes the future non-Send. | 385 | // is held across an await and makes the future non-Send. |
| 397 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) | 386 | crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx_ptr, T::RX_DREQ) |
| 398 | }; | 387 | }; |
| 399 | 388 | ||
| 400 | let mut tx_ch = self.tx_dma.as_mut().unwrap(); | 389 | let mut tx_ch = self.tx_dma.as_mut().unwrap(); |
| @@ -403,13 +392,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 403 | let tx_transfer = async { | 392 | let tx_transfer = async { |
| 404 | let p = self.inner.regs(); | 393 | let p = self.inner.regs(); |
| 405 | unsafe { | 394 | unsafe { |
| 406 | crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await; | 395 | crate::dma::write(&mut tx_ch, tx_ptr, p.dr().as_ptr() as *mut _, T::TX_DREQ).await; |
| 407 | 396 | ||
| 408 | if rx_len > tx_len { | 397 | if rx_len > tx_len { |
| 409 | let write_bytes_len = rx_len - tx_len; | 398 | let write_bytes_len = rx_len - tx_len; |
| 410 | // write dummy data | 399 | // write dummy data |
| 411 | // this will disable incrementation of the buffers | 400 | // this will disable incrementation of the buffers |
| 412 | crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await | 401 | crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await |
| 413 | } | 402 | } |
| 414 | } | 403 | } |
| 415 | }; | 404 | }; |
| @@ -418,16 +407,14 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 418 | // if tx > rx we should clear any overflow of the FIFO SPI buffer | 407 | // if tx > rx we should clear any overflow of the FIFO SPI buffer |
| 419 | if tx_len > rx_len { | 408 | if tx_len > rx_len { |
| 420 | let p = self.inner.regs(); | 409 | let p = self.inner.regs(); |
| 421 | unsafe { | 410 | while p.sr().read().bsy() {} |
| 422 | while p.sr().read().bsy() {} | ||
| 423 | 411 | ||
| 424 | // clear RX FIFO contents to prevent stale reads | 412 | // clear RX FIFO contents to prevent stale reads |
| 425 | while p.sr().read().rne() { | 413 | while p.sr().read().rne() { |
| 426 | let _: u16 = p.dr().read().data(); | 414 | let _: u16 = p.dr().read().data(); |
| 427 | } | ||
| 428 | // clear RX overrun interrupt | ||
| 429 | p.icr().write(|w| w.set_roric(true)); | ||
| 430 | } | 415 | } |
| 416 | // clear RX overrun interrupt | ||
| 417 | p.icr().write(|w| w.set_roric(true)); | ||
| 431 | } | 418 | } |
| 432 | 419 | ||
| 433 | Ok(()) | 420 | Ok(()) |
| @@ -625,14 +612,12 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> { | |||
| 625 | fn set_config(&mut self, config: &Self::Config) { | 612 | fn set_config(&mut self, config: &Self::Config) { |
| 626 | let p = self.inner.regs(); | 613 | let p = self.inner.regs(); |
| 627 | let (presc, postdiv) = calc_prescs(config.frequency); | 614 | let (presc, postdiv) = calc_prescs(config.frequency); |
| 628 | unsafe { | 615 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); |
| 629 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | 616 | p.cr0().write(|w| { |
| 630 | p.cr0().write(|w| { | 617 | w.set_dss(0b0111); // 8bit |
| 631 | w.set_dss(0b0111); // 8bit | 618 | w.set_spo(config.polarity == Polarity::IdleHigh); |
| 632 | w.set_spo(config.polarity == Polarity::IdleHigh); | 619 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); |
| 633 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); | 620 | w.set_scr(postdiv); |
| 634 | w.set_scr(postdiv); | 621 | }); |
| 635 | }); | ||
| 636 | } | ||
| 637 | } | 622 | } |
| 638 | } | 623 | } |
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index ca8c96c0f..faa8df037 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs | |||
| @@ -34,13 +34,11 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ | |||
| 34 | impl Driver for TimerDriver { | 34 | impl Driver for TimerDriver { |
| 35 | fn now(&self) -> u64 { | 35 | fn now(&self) -> u64 { |
| 36 | loop { | 36 | loop { |
| 37 | unsafe { | 37 | let hi = pac::TIMER.timerawh().read(); |
| 38 | let hi = pac::TIMER.timerawh().read(); | 38 | let lo = pac::TIMER.timerawl().read(); |
| 39 | let lo = pac::TIMER.timerawl().read(); | 39 | let hi2 = pac::TIMER.timerawh().read(); |
| 40 | let hi2 = pac::TIMER.timerawh().read(); | 40 | if hi == hi2 { |
| 41 | if hi == hi2 { | 41 | return (hi as u64) << 32 | (lo as u64); |
| 42 | return (hi as u64) << 32 | (lo as u64); | ||
| 43 | } | ||
| 44 | } | 42 | } |
| 45 | } | 43 | } |
| 46 | } | 44 | } |
| @@ -78,13 +76,13 @@ impl Driver for TimerDriver { | |||
| 78 | // Note that we're not checking the high bits at all. This means the irq may fire early | 76 | // Note that we're not checking the high bits at all. This means the irq may fire early |
| 79 | // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire | 77 | // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire |
| 80 | // it is checked if the alarm time has passed. | 78 | // it is checked if the alarm time has passed. |
| 81 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; | 79 | pac::TIMER.alarm(n).write_value(timestamp as u32); |
| 82 | 80 | ||
| 83 | let now = self.now(); | 81 | let now = self.now(); |
| 84 | if timestamp <= now { | 82 | if timestamp <= now { |
| 85 | // If alarm timestamp has passed the alarm will not fire. | 83 | // If alarm timestamp has passed the alarm will not fire. |
| 86 | // Disarm the alarm and return `false` to indicate that. | 84 | // Disarm the alarm and return `false` to indicate that. |
| 87 | unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } | 85 | pac::TIMER.armed().write(|w| w.set_armed(1 << n)); |
| 88 | 86 | ||
| 89 | alarm.timestamp.set(u64::MAX); | 87 | alarm.timestamp.set(u64::MAX); |
| 90 | 88 | ||
| @@ -106,17 +104,17 @@ impl TimerDriver { | |||
| 106 | } else { | 104 | } else { |
| 107 | // Not elapsed, arm it again. | 105 | // Not elapsed, arm it again. |
| 108 | // This can happen if it was set more than 2^32 us in the future. | 106 | // This can happen if it was set more than 2^32 us in the future. |
| 109 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; | 107 | pac::TIMER.alarm(n).write_value(timestamp as u32); |
| 110 | } | 108 | } |
| 111 | }); | 109 | }); |
| 112 | 110 | ||
| 113 | // clear the irq | 111 | // clear the irq |
| 114 | unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) } | 112 | pac::TIMER.intr().write(|w| w.set_alarm(n, true)); |
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | fn trigger_alarm(&self, n: usize, cs: CriticalSection) { | 115 | fn trigger_alarm(&self, n: usize, cs: CriticalSection) { |
| 118 | // disarm | 116 | // disarm |
| 119 | unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } | 117 | pac::TIMER.armed().write(|w| w.set_armed(1 << n)); |
| 120 | 118 | ||
| 121 | let alarm = &self.alarms.borrow(cs)[n]; | 119 | let alarm = &self.alarms.borrow(cs)[n]; |
| 122 | alarm.timestamp.set(u64::MAX); | 120 | alarm.timestamp.set(u64::MAX); |
| @@ -153,24 +151,24 @@ pub unsafe fn init() { | |||
| 153 | 151 | ||
| 154 | #[cfg(feature = "rt")] | 152 | #[cfg(feature = "rt")] |
| 155 | #[interrupt] | 153 | #[interrupt] |
| 156 | unsafe fn TIMER_IRQ_0() { | 154 | fn TIMER_IRQ_0() { |
| 157 | DRIVER.check_alarm(0) | 155 | DRIVER.check_alarm(0) |
| 158 | } | 156 | } |
| 159 | 157 | ||
| 160 | #[cfg(feature = "rt")] | 158 | #[cfg(feature = "rt")] |
| 161 | #[interrupt] | 159 | #[interrupt] |
| 162 | unsafe fn TIMER_IRQ_1() { | 160 | fn TIMER_IRQ_1() { |
| 163 | DRIVER.check_alarm(1) | 161 | DRIVER.check_alarm(1) |
| 164 | } | 162 | } |
| 165 | 163 | ||
| 166 | #[cfg(feature = "rt")] | 164 | #[cfg(feature = "rt")] |
| 167 | #[interrupt] | 165 | #[interrupt] |
| 168 | unsafe fn TIMER_IRQ_2() { | 166 | fn TIMER_IRQ_2() { |
| 169 | DRIVER.check_alarm(2) | 167 | DRIVER.check_alarm(2) |
| 170 | } | 168 | } |
| 171 | 169 | ||
| 172 | #[cfg(feature = "rt")] | 170 | #[cfg(feature = "rt")] |
| 173 | #[interrupt] | 171 | #[interrupt] |
| 174 | unsafe fn TIMER_IRQ_3() { | 172 | fn TIMER_IRQ_3() { |
| 175 | DRIVER.check_alarm(3) | 173 | DRIVER.check_alarm(3) |
| 176 | } | 174 | } |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 6660d5dc9..30eeb5476 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -73,16 +73,14 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>( | |||
| 73 | // we clear it after it happens. The downside is that the we manually have | 73 | // we clear it after it happens. The downside is that the we manually have |
| 74 | // to pend the ISR when we want data transmission to start. | 74 | // to pend the ISR when we want data transmission to start. |
| 75 | let regs = T::regs(); | 75 | let regs = T::regs(); |
| 76 | unsafe { | 76 | regs.uartimsc().write(|w| { |
| 77 | regs.uartimsc().write(|w| { | 77 | w.set_rxim(true); |
| 78 | w.set_rxim(true); | 78 | w.set_rtim(true); |
| 79 | w.set_rtim(true); | 79 | w.set_txim(true); |
| 80 | w.set_txim(true); | 80 | }); |
| 81 | }); | 81 | |
| 82 | 82 | T::Interrupt::unpend(); | |
| 83 | T::Interrupt::unpend(); | 83 | unsafe { T::Interrupt::enable() }; |
| 84 | T::Interrupt::enable(); | ||
| 85 | }; | ||
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | impl<'d, T: Instance> BufferedUart<'d, T> { | 86 | impl<'d, T: Instance> BufferedUart<'d, T> { |
| @@ -247,12 +245,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { | |||
| 247 | // (Re-)Enable the interrupt to receive more data in case it was | 245 | // (Re-)Enable the interrupt to receive more data in case it was |
| 248 | // disabled because the buffer was full or errors were detected. | 246 | // disabled because the buffer was full or errors were detected. |
| 249 | let regs = T::regs(); | 247 | let regs = T::regs(); |
| 250 | unsafe { | 248 | regs.uartimsc().write_set(|w| { |
| 251 | regs.uartimsc().write_set(|w| { | 249 | w.set_rxim(true); |
| 252 | w.set_rxim(true); | 250 | w.set_rtim(true); |
| 253 | w.set_rtim(true); | 251 | }); |
| 254 | }); | ||
| 255 | } | ||
| 256 | 252 | ||
| 257 | Poll::Ready(result) | 253 | Poll::Ready(result) |
| 258 | } | 254 | } |
| @@ -299,12 +295,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { | |||
| 299 | // (Re-)Enable the interrupt to receive more data in case it was | 295 | // (Re-)Enable the interrupt to receive more data in case it was |
| 300 | // disabled because the buffer was full or errors were detected. | 296 | // disabled because the buffer was full or errors were detected. |
| 301 | let regs = T::regs(); | 297 | let regs = T::regs(); |
| 302 | unsafe { | 298 | regs.uartimsc().write_set(|w| { |
| 303 | regs.uartimsc().write_set(|w| { | 299 | w.set_rxim(true); |
| 304 | w.set_rxim(true); | 300 | w.set_rtim(true); |
| 305 | w.set_rtim(true); | 301 | }); |
| 306 | }); | ||
| 307 | } | ||
| 308 | } | 302 | } |
| 309 | } | 303 | } |
| 310 | 304 | ||
| @@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 414 | } | 408 | } |
| 415 | 409 | ||
| 416 | pub fn busy(&self) -> bool { | 410 | pub fn busy(&self) -> bool { |
| 417 | unsafe { T::regs().uartfr().read().busy() } | 411 | T::regs().uartfr().read().busy() |
| 418 | } | 412 | } |
| 419 | 413 | ||
| 420 | /// Assert a break condition after waiting for the transmit buffers to empty, | 414 | /// Assert a break condition after waiting for the transmit buffers to empty, |
| @@ -426,42 +420,35 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 426 | /// for the transmit fifo to empty, which may take a while on slow links. | 420 | /// for the transmit fifo to empty, which may take a while on slow links. |
| 427 | pub async fn send_break(&mut self, bits: u32) { | 421 | pub async fn send_break(&mut self, bits: u32) { |
| 428 | let regs = T::regs(); | 422 | let regs = T::regs(); |
| 429 | let bits = bits.max(unsafe { | 423 | let bits = bits.max({ |
| 430 | let lcr = regs.uartlcr_h().read(); | 424 | let lcr = regs.uartlcr_h().read(); |
| 431 | let width = lcr.wlen() as u32 + 5; | 425 | let width = lcr.wlen() as u32 + 5; |
| 432 | let parity = lcr.pen() as u32; | 426 | let parity = lcr.pen() as u32; |
| 433 | let stops = 1 + lcr.stp2() as u32; | 427 | let stops = 1 + lcr.stp2() as u32; |
| 434 | 2 * (1 + width + parity + stops) | 428 | 2 * (1 + width + parity + stops) |
| 435 | }); | 429 | }); |
| 436 | let divx64 = unsafe { | 430 | let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6) |
| 437 | ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 | 431 | + regs.uartfbrd().read().baud_divfrac() as u32) as u64; |
| 438 | } as u64; | ||
| 439 | let div_clk = clk_peri_freq() as u64 * 64; | 432 | let div_clk = clk_peri_freq() as u64 * 64; |
| 440 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; | 433 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; |
| 441 | 434 | ||
| 442 | Self::flush().await.unwrap(); | 435 | Self::flush().await.unwrap(); |
| 443 | while self.busy() {} | 436 | while self.busy() {} |
| 444 | unsafe { | 437 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); |
| 445 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); | ||
| 446 | } | ||
| 447 | Timer::after(Duration::from_micros(wait_usecs)).await; | 438 | Timer::after(Duration::from_micros(wait_usecs)).await; |
| 448 | unsafe { | 439 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); |
| 449 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); | ||
| 450 | } | ||
| 451 | } | 440 | } |
| 452 | } | 441 | } |
| 453 | 442 | ||
| 454 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | 443 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { |
| 455 | fn drop(&mut self) { | 444 | fn drop(&mut self) { |
| 456 | let state = T::buffered_state(); | 445 | let state = T::buffered_state(); |
| 457 | unsafe { | 446 | unsafe { state.rx_buf.deinit() } |
| 458 | state.rx_buf.deinit(); | ||
| 459 | 447 | ||
| 460 | // TX is inactive if the the buffer is not available. | 448 | // TX is inactive if the the buffer is not available. |
| 461 | // We can now unregister the interrupt handler | 449 | // We can now unregister the interrupt handler |
| 462 | if state.tx_buf.len() == 0 { | 450 | if state.tx_buf.len() == 0 { |
| 463 | T::Interrupt::disable(); | 451 | T::Interrupt::disable(); |
| 464 | } | ||
| 465 | } | 452 | } |
| 466 | } | 453 | } |
| 467 | } | 454 | } |
| @@ -469,14 +456,12 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | |||
| 469 | impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { | 456 | impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { |
| 470 | fn drop(&mut self) { | 457 | fn drop(&mut self) { |
| 471 | let state = T::buffered_state(); | 458 | let state = T::buffered_state(); |
| 472 | unsafe { | 459 | unsafe { state.tx_buf.deinit() } |
| 473 | state.tx_buf.deinit(); | ||
| 474 | 460 | ||
| 475 | // RX is inactive if the the buffer is not available. | 461 | // RX is inactive if the the buffer is not available. |
| 476 | // We can now unregister the interrupt handler | 462 | // We can now unregister the interrupt handler |
| 477 | if state.rx_buf.len() == 0 { | 463 | if state.rx_buf.len() == 0 { |
| 478 | T::Interrupt::disable(); | 464 | T::Interrupt::disable(); |
| 479 | } | ||
| 480 | } | 465 | } |
| 481 | } | 466 | } |
| 482 | } | 467 | } |
| @@ -494,94 +479,92 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr | |||
| 494 | 479 | ||
| 495 | let s = T::buffered_state(); | 480 | let s = T::buffered_state(); |
| 496 | 481 | ||
| 497 | unsafe { | 482 | // Clear TX and error interrupt flags |
| 498 | // Clear TX and error interrupt flags | 483 | // RX interrupt flags are cleared by reading from the FIFO. |
| 499 | // RX interrupt flags are cleared by reading from the FIFO. | 484 | let ris = r.uartris().read(); |
| 500 | let ris = r.uartris().read(); | 485 | r.uarticr().write(|w| { |
| 501 | r.uarticr().write(|w| { | 486 | w.set_txic(ris.txris()); |
| 502 | w.set_txic(ris.txris()); | 487 | w.set_feic(ris.feris()); |
| 503 | w.set_feic(ris.feris()); | 488 | w.set_peic(ris.peris()); |
| 504 | w.set_peic(ris.peris()); | 489 | w.set_beic(ris.beris()); |
| 505 | w.set_beic(ris.beris()); | 490 | w.set_oeic(ris.oeris()); |
| 506 | w.set_oeic(ris.oeris()); | 491 | }); |
| 507 | }); | ||
| 508 | 492 | ||
| 509 | trace!("on_interrupt ris={:#X}", ris.0); | 493 | trace!("on_interrupt ris={:#X}", ris.0); |
| 510 | 494 | ||
| 511 | // Errors | 495 | // Errors |
| 512 | if ris.feris() { | 496 | if ris.feris() { |
| 513 | warn!("Framing error"); | 497 | warn!("Framing error"); |
| 514 | } | 498 | } |
| 515 | if ris.peris() { | 499 | if ris.peris() { |
| 516 | warn!("Parity error"); | 500 | warn!("Parity error"); |
| 517 | } | 501 | } |
| 518 | if ris.beris() { | 502 | if ris.beris() { |
| 519 | warn!("Break error"); | 503 | warn!("Break error"); |
| 520 | } | 504 | } |
| 521 | if ris.oeris() { | 505 | if ris.oeris() { |
| 522 | warn!("Overrun error"); | 506 | warn!("Overrun error"); |
| 523 | } | 507 | } |
| 524 | 508 | ||
| 525 | // RX | 509 | // RX |
| 526 | let mut rx_writer = s.rx_buf.writer(); | 510 | let mut rx_writer = unsafe { s.rx_buf.writer() }; |
| 527 | let rx_buf = rx_writer.push_slice(); | 511 | let rx_buf = rx_writer.push_slice(); |
| 528 | let mut n_read = 0; | 512 | let mut n_read = 0; |
| 529 | let mut error = false; | 513 | let mut error = false; |
| 530 | for rx_byte in rx_buf { | 514 | for rx_byte in rx_buf { |
| 531 | if r.uartfr().read().rxfe() { | 515 | if r.uartfr().read().rxfe() { |
| 532 | break; | 516 | break; |
| 533 | } | ||
| 534 | let dr = r.uartdr().read(); | ||
| 535 | if (dr.0 >> 8) != 0 { | ||
| 536 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); | ||
| 537 | error = true; | ||
| 538 | // only fill the buffer with valid characters. the current character is fine | ||
| 539 | // if the error is an overrun, but if we add it to the buffer we'll report | ||
| 540 | // the overrun one character too late. drop it instead and pretend we were | ||
| 541 | // a bit slower at draining the rx fifo than we actually were. | ||
| 542 | // this is consistent with blocking uart error reporting. | ||
| 543 | break; | ||
| 544 | } | ||
| 545 | *rx_byte = dr.data(); | ||
| 546 | n_read += 1; | ||
| 547 | } | ||
| 548 | if n_read > 0 { | ||
| 549 | rx_writer.push_done(n_read); | ||
| 550 | s.rx_waker.wake(); | ||
| 551 | } else if error { | ||
| 552 | s.rx_waker.wake(); | ||
| 553 | } | 517 | } |
| 554 | // Disable any further RX interrupts when the buffer becomes full or | 518 | let dr = r.uartdr().read(); |
| 555 | // errors have occurred. This lets us buffer additional errors in the | 519 | if (dr.0 >> 8) != 0 { |
| 556 | // fifo without needing more error storage locations, and most applications | 520 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); |
| 557 | // will want to do a full reset of their uart state anyway once an error | 521 | error = true; |
| 558 | // has happened. | 522 | // only fill the buffer with valid characters. the current character is fine |
| 559 | if s.rx_buf.is_full() || error { | 523 | // if the error is an overrun, but if we add it to the buffer we'll report |
| 560 | r.uartimsc().write_clear(|w| { | 524 | // the overrun one character too late. drop it instead and pretend we were |
| 561 | w.set_rxim(true); | 525 | // a bit slower at draining the rx fifo than we actually were. |
| 562 | w.set_rtim(true); | 526 | // this is consistent with blocking uart error reporting. |
| 563 | }); | 527 | break; |
| 564 | } | 528 | } |
| 529 | *rx_byte = dr.data(); | ||
| 530 | n_read += 1; | ||
| 531 | } | ||
| 532 | if n_read > 0 { | ||
| 533 | rx_writer.push_done(n_read); | ||
| 534 | s.rx_waker.wake(); | ||
| 535 | } else if error { | ||
| 536 | s.rx_waker.wake(); | ||
| 537 | } | ||
| 538 | // Disable any further RX interrupts when the buffer becomes full or | ||
| 539 | // errors have occurred. This lets us buffer additional errors in the | ||
| 540 | // fifo without needing more error storage locations, and most applications | ||
| 541 | // will want to do a full reset of their uart state anyway once an error | ||
| 542 | // has happened. | ||
| 543 | if s.rx_buf.is_full() || error { | ||
| 544 | r.uartimsc().write_clear(|w| { | ||
| 545 | w.set_rxim(true); | ||
| 546 | w.set_rtim(true); | ||
| 547 | }); | ||
| 548 | } | ||
| 565 | 549 | ||
| 566 | // TX | 550 | // TX |
| 567 | let mut tx_reader = s.tx_buf.reader(); | 551 | let mut tx_reader = unsafe { s.tx_buf.reader() }; |
| 568 | let tx_buf = tx_reader.pop_slice(); | 552 | let tx_buf = tx_reader.pop_slice(); |
| 569 | let mut n_written = 0; | 553 | let mut n_written = 0; |
| 570 | for tx_byte in tx_buf.iter_mut() { | 554 | for tx_byte in tx_buf.iter_mut() { |
| 571 | if r.uartfr().read().txff() { | 555 | if r.uartfr().read().txff() { |
| 572 | break; | 556 | break; |
| 573 | } | ||
| 574 | r.uartdr().write(|w| w.set_data(*tx_byte)); | ||
| 575 | n_written += 1; | ||
| 576 | } | ||
| 577 | if n_written > 0 { | ||
| 578 | tx_reader.pop_done(n_written); | ||
| 579 | s.tx_waker.wake(); | ||
| 580 | } | 557 | } |
| 581 | // The TX interrupt only triggers once when the FIFO threshold is | 558 | r.uartdr().write(|w| w.set_data(*tx_byte)); |
| 582 | // crossed. No need to disable it when the buffer becomes empty | 559 | n_written += 1; |
| 583 | // as it does re-trigger anymore once we have cleared it. | 560 | } |
| 561 | if n_written > 0 { | ||
| 562 | tx_reader.pop_done(n_written); | ||
| 563 | s.tx_waker.wake(); | ||
| 584 | } | 564 | } |
| 565 | // The TX interrupt only triggers once when the FIFO threshold is | ||
| 566 | // crossed. No need to disable it when the buffer becomes empty | ||
| 567 | // as it does re-trigger anymore once we have cleared it. | ||
| 585 | } | 568 | } |
| 586 | } | 569 | } |
| 587 | 570 | ||
| @@ -695,24 +678,22 @@ mod eh02 { | |||
| 695 | 678 | ||
| 696 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 679 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 697 | let r = T::regs(); | 680 | let r = T::regs(); |
| 698 | unsafe { | 681 | if r.uartfr().read().rxfe() { |
| 699 | if r.uartfr().read().rxfe() { | 682 | return Err(nb::Error::WouldBlock); |
| 700 | return Err(nb::Error::WouldBlock); | 683 | } |
| 701 | } | ||
| 702 | 684 | ||
| 703 | let dr = r.uartdr().read(); | 685 | let dr = r.uartdr().read(); |
| 704 | 686 | ||
| 705 | if dr.oe() { | 687 | if dr.oe() { |
| 706 | Err(nb::Error::Other(Error::Overrun)) | 688 | Err(nb::Error::Other(Error::Overrun)) |
| 707 | } else if dr.be() { | 689 | } else if dr.be() { |
| 708 | Err(nb::Error::Other(Error::Break)) | 690 | Err(nb::Error::Other(Error::Break)) |
| 709 | } else if dr.pe() { | 691 | } else if dr.pe() { |
| 710 | Err(nb::Error::Other(Error::Parity)) | 692 | Err(nb::Error::Other(Error::Parity)) |
| 711 | } else if dr.fe() { | 693 | } else if dr.fe() { |
| 712 | Err(nb::Error::Other(Error::Framing)) | 694 | Err(nb::Error::Other(Error::Framing)) |
| 713 | } else { | 695 | } else { |
| 714 | Ok(dr.data()) | 696 | Ok(dr.data()) |
| 715 | } | ||
| 716 | } | 697 | } |
| 717 | } | 698 | } |
| 718 | } | 699 | } |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 5e3ae8a25..7b94bce5e 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||
| 146 | 146 | ||
| 147 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 147 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 148 | let r = T::regs(); | 148 | let r = T::regs(); |
| 149 | unsafe { | 149 | for &b in buffer { |
| 150 | for &b in buffer { | 150 | while r.uartfr().read().txff() {} |
| 151 | while r.uartfr().read().txff() {} | 151 | r.uartdr().write(|w| w.set_data(b)); |
| 152 | r.uartdr().write(|w| w.set_data(b)); | ||
| 153 | } | ||
| 154 | } | 152 | } |
| 155 | Ok(()) | 153 | Ok(()) |
| 156 | } | 154 | } |
| 157 | 155 | ||
| 158 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 156 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 159 | let r = T::regs(); | 157 | let r = T::regs(); |
| 160 | unsafe { while !r.uartfr().read().txfe() {} } | 158 | while !r.uartfr().read().txfe() {} |
| 161 | Ok(()) | 159 | Ok(()) |
| 162 | } | 160 | } |
| 163 | 161 | ||
| 164 | pub fn busy(&self) -> bool { | 162 | pub fn busy(&self) -> bool { |
| 165 | unsafe { T::regs().uartfr().read().busy() } | 163 | T::regs().uartfr().read().busy() |
| 166 | } | 164 | } |
| 167 | 165 | ||
| 168 | /// Assert a break condition after waiting for the transmit buffers to empty, | 166 | /// Assert a break condition after waiting for the transmit buffers to empty, |
| @@ -174,28 +172,23 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||
| 174 | /// for the transmit fifo to empty, which may take a while on slow links. | 172 | /// for the transmit fifo to empty, which may take a while on slow links. |
| 175 | pub async fn send_break(&mut self, bits: u32) { | 173 | pub async fn send_break(&mut self, bits: u32) { |
| 176 | let regs = T::regs(); | 174 | let regs = T::regs(); |
| 177 | let bits = bits.max(unsafe { | 175 | let bits = bits.max({ |
| 178 | let lcr = regs.uartlcr_h().read(); | 176 | let lcr = regs.uartlcr_h().read(); |
| 179 | let width = lcr.wlen() as u32 + 5; | 177 | let width = lcr.wlen() as u32 + 5; |
| 180 | let parity = lcr.pen() as u32; | 178 | let parity = lcr.pen() as u32; |
| 181 | let stops = 1 + lcr.stp2() as u32; | 179 | let stops = 1 + lcr.stp2() as u32; |
| 182 | 2 * (1 + width + parity + stops) | 180 | 2 * (1 + width + parity + stops) |
| 183 | }); | 181 | }); |
| 184 | let divx64 = unsafe { | 182 | let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6) |
| 185 | ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 | 183 | + regs.uartfbrd().read().baud_divfrac() as u32) as u64; |
| 186 | } as u64; | ||
| 187 | let div_clk = clk_peri_freq() as u64 * 64; | 184 | let div_clk = clk_peri_freq() as u64 * 64; |
| 188 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; | 185 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; |
| 189 | 186 | ||
| 190 | self.blocking_flush().unwrap(); | 187 | self.blocking_flush().unwrap(); |
| 191 | while self.busy() {} | 188 | while self.busy() {} |
| 192 | unsafe { | 189 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); |
| 193 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); | ||
| 194 | } | ||
| 195 | Timer::after(Duration::from_micros(wait_usecs)).await; | 190 | Timer::after(Duration::from_micros(wait_usecs)).await; |
| 196 | unsafe { | 191 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); |
| 197 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); | ||
| 198 | } | ||
| 199 | } | 192 | } |
| 200 | } | 193 | } |
| 201 | 194 | ||
| @@ -221,7 +214,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> { | |||
| 221 | }); | 214 | }); |
| 222 | // If we don't assign future to a variable, the data register pointer | 215 | // If we don't assign future to a variable, the data register pointer |
| 223 | // is held across an await and makes the future non-Send. | 216 | // is held across an await and makes the future non-Send. |
| 224 | crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) | 217 | crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ) |
| 225 | }; | 218 | }; |
| 226 | transfer.await; | 219 | transfer.await; |
| 227 | Ok(()) | 220 | Ok(()) |
| @@ -246,7 +239,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 246 | debug_assert_eq!(has_irq, rx_dma.is_some()); | 239 | debug_assert_eq!(has_irq, rx_dma.is_some()); |
| 247 | if has_irq { | 240 | if has_irq { |
| 248 | // disable all error interrupts initially | 241 | // disable all error interrupts initially |
| 249 | unsafe { T::regs().uartimsc().write(|w| w.0 = 0) } | 242 | T::regs().uartimsc().write(|w| w.0 = 0); |
| 250 | T::Interrupt::unpend(); | 243 | T::Interrupt::unpend(); |
| 251 | unsafe { T::Interrupt::enable() }; | 244 | unsafe { T::Interrupt::enable() }; |
| 252 | } | 245 | } |
| @@ -267,11 +260,11 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 267 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 260 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 268 | let r = T::regs(); | 261 | let r = T::regs(); |
| 269 | for (i, b) in buffer.iter_mut().enumerate() { | 262 | for (i, b) in buffer.iter_mut().enumerate() { |
| 270 | if unsafe { r.uartfr().read().rxfe() } { | 263 | if r.uartfr().read().rxfe() { |
| 271 | return Ok(i); | 264 | return Ok(i); |
| 272 | } | 265 | } |
| 273 | 266 | ||
| 274 | let dr = unsafe { r.uartdr().read() }; | 267 | let dr = r.uartdr().read(); |
| 275 | 268 | ||
| 276 | if dr.oe() { | 269 | if dr.oe() { |
| 277 | return Err(Error::Overrun); | 270 | return Err(Error::Overrun); |
| @@ -292,15 +285,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 292 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { | 285 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { |
| 293 | fn drop(&mut self) { | 286 | fn drop(&mut self) { |
| 294 | if let Some(_) = self.rx_dma { | 287 | if let Some(_) = self.rx_dma { |
| 295 | unsafe { | 288 | T::Interrupt::disable(); |
| 296 | T::Interrupt::disable(); | 289 | // clear dma flags. irq handlers use these to disambiguate among themselves. |
| 297 | // clear dma flags. irq handlers use these to disambiguate among themselves. | 290 | T::regs().uartdmacr().write_clear(|reg| { |
| 298 | T::regs().uartdmacr().write_clear(|reg| { | 291 | reg.set_rxdmae(true); |
| 299 | reg.set_rxdmae(true); | 292 | reg.set_txdmae(true); |
| 300 | reg.set_txdmae(true); | 293 | reg.set_dmaonerr(true); |
| 301 | reg.set_dmaonerr(true); | 294 | }); |
| 302 | }); | ||
| 303 | } | ||
| 304 | } | 295 | } |
| 305 | } | 296 | } |
| 306 | } | 297 | } |
| @@ -355,14 +346,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 355 | // clear error flags before we drain the fifo. errors that have accumulated | 346 | // clear error flags before we drain the fifo. errors that have accumulated |
| 356 | // in the flags will also be present in the fifo. | 347 | // in the flags will also be present in the fifo. |
| 357 | T::dma_state().rx_errs.store(0, Ordering::Relaxed); | 348 | T::dma_state().rx_errs.store(0, Ordering::Relaxed); |
| 358 | unsafe { | 349 | T::regs().uarticr().write(|w| { |
| 359 | T::regs().uarticr().write(|w| { | 350 | w.set_oeic(true); |
| 360 | w.set_oeic(true); | 351 | w.set_beic(true); |
| 361 | w.set_beic(true); | 352 | w.set_peic(true); |
| 362 | w.set_peic(true); | 353 | w.set_feic(true); |
| 363 | w.set_feic(true); | 354 | }); |
| 364 | }); | ||
| 365 | } | ||
| 366 | 355 | ||
| 367 | // then drain the fifo. we need to read at most 32 bytes. errors that apply | 356 | // then drain the fifo. we need to read at most 32 bytes. errors that apply |
| 368 | // to fifo bytes will be reported directly. | 357 | // to fifo bytes will be reported directly. |
| @@ -379,20 +368,20 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 379 | // interrupt flags will have been raised, and those will be picked up immediately | 368 | // interrupt flags will have been raised, and those will be picked up immediately |
| 380 | // by the interrupt handler. | 369 | // by the interrupt handler. |
| 381 | let ch = self.rx_dma.as_mut().unwrap(); | 370 | let ch = self.rx_dma.as_mut().unwrap(); |
| 371 | T::regs().uartimsc().write_set(|w| { | ||
| 372 | w.set_oeim(true); | ||
| 373 | w.set_beim(true); | ||
| 374 | w.set_peim(true); | ||
| 375 | w.set_feim(true); | ||
| 376 | }); | ||
| 377 | T::regs().uartdmacr().write_set(|reg| { | ||
| 378 | reg.set_rxdmae(true); | ||
| 379 | reg.set_dmaonerr(true); | ||
| 380 | }); | ||
| 382 | let transfer = unsafe { | 381 | let transfer = unsafe { |
| 383 | T::regs().uartimsc().write_set(|w| { | ||
| 384 | w.set_oeim(true); | ||
| 385 | w.set_beim(true); | ||
| 386 | w.set_peim(true); | ||
| 387 | w.set_feim(true); | ||
| 388 | }); | ||
| 389 | T::regs().uartdmacr().write_set(|reg| { | ||
| 390 | reg.set_rxdmae(true); | ||
| 391 | reg.set_dmaonerr(true); | ||
| 392 | }); | ||
| 393 | // If we don't assign future to a variable, the data register pointer | 382 | // If we don't assign future to a variable, the data register pointer |
| 394 | // is held across an await and makes the future non-Send. | 383 | // is held across an await and makes the future non-Send. |
| 395 | crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) | 384 | crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ) |
| 396 | }; | 385 | }; |
| 397 | 386 | ||
| 398 | // wait for either the transfer to complete or an error to happen. | 387 | // wait for either the transfer to complete or an error to happen. |
| @@ -575,81 +564,79 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | |||
| 575 | config: Config, | 564 | config: Config, |
| 576 | ) { | 565 | ) { |
| 577 | let r = T::regs(); | 566 | let r = T::regs(); |
| 578 | unsafe { | 567 | if let Some(pin) = &tx { |
| 579 | if let Some(pin) = &tx { | 568 | pin.io().ctrl().write(|w| { |
| 580 | pin.io().ctrl().write(|w| { | 569 | w.set_funcsel(2); |
| 581 | w.set_funcsel(2); | 570 | w.set_outover(if config.invert_tx { |
| 582 | w.set_outover(if config.invert_tx { | 571 | Outover::INVERT |
| 583 | Outover::INVERT | 572 | } else { |
| 584 | } else { | 573 | Outover::NORMAL |
| 585 | Outover::NORMAL | ||
| 586 | }); | ||
| 587 | }); | 574 | }); |
| 588 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 575 | }); |
| 589 | } | 576 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 590 | if let Some(pin) = &rx { | 577 | } |
| 591 | pin.io().ctrl().write(|w| { | 578 | if let Some(pin) = &rx { |
| 592 | w.set_funcsel(2); | 579 | pin.io().ctrl().write(|w| { |
| 593 | w.set_inover(if config.invert_rx { | 580 | w.set_funcsel(2); |
| 594 | Inover::INVERT | 581 | w.set_inover(if config.invert_rx { |
| 595 | } else { | 582 | Inover::INVERT |
| 596 | Inover::NORMAL | 583 | } else { |
| 597 | }); | 584 | Inover::NORMAL |
| 598 | }); | 585 | }); |
| 599 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 586 | }); |
| 600 | } | 587 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 601 | if let Some(pin) = &cts { | 588 | } |
| 602 | pin.io().ctrl().write(|w| { | 589 | if let Some(pin) = &cts { |
| 603 | w.set_funcsel(2); | 590 | pin.io().ctrl().write(|w| { |
| 604 | w.set_inover(if config.invert_cts { | 591 | w.set_funcsel(2); |
| 605 | Inover::INVERT | 592 | w.set_inover(if config.invert_cts { |
| 606 | } else { | 593 | Inover::INVERT |
| 607 | Inover::NORMAL | 594 | } else { |
| 608 | }); | 595 | Inover::NORMAL |
| 609 | }); | 596 | }); |
| 610 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 597 | }); |
| 611 | } | 598 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 612 | if let Some(pin) = &rts { | 599 | } |
| 613 | pin.io().ctrl().write(|w| { | 600 | if let Some(pin) = &rts { |
| 614 | w.set_funcsel(2); | 601 | pin.io().ctrl().write(|w| { |
| 615 | w.set_outover(if config.invert_rts { | 602 | w.set_funcsel(2); |
| 616 | Outover::INVERT | 603 | w.set_outover(if config.invert_rts { |
| 617 | } else { | 604 | Outover::INVERT |
| 618 | Outover::NORMAL | 605 | } else { |
| 619 | }); | 606 | Outover::NORMAL |
| 620 | }); | 607 | }); |
| 621 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 608 | }); |
| 622 | } | 609 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 610 | } | ||
| 623 | 611 | ||
| 624 | Self::set_baudrate_inner(config.baudrate); | 612 | Self::set_baudrate_inner(config.baudrate); |
| 625 | 613 | ||
| 626 | let (pen, eps) = match config.parity { | 614 | let (pen, eps) = match config.parity { |
| 627 | Parity::ParityNone => (false, false), | 615 | Parity::ParityNone => (false, false), |
| 628 | Parity::ParityOdd => (true, false), | 616 | Parity::ParityOdd => (true, false), |
| 629 | Parity::ParityEven => (true, true), | 617 | Parity::ParityEven => (true, true), |
| 630 | }; | 618 | }; |
| 631 | 619 | ||
| 632 | r.uartlcr_h().write(|w| { | 620 | r.uartlcr_h().write(|w| { |
| 633 | w.set_wlen(config.data_bits.bits()); | 621 | w.set_wlen(config.data_bits.bits()); |
| 634 | w.set_stp2(config.stop_bits == StopBits::STOP2); | 622 | w.set_stp2(config.stop_bits == StopBits::STOP2); |
| 635 | w.set_pen(pen); | 623 | w.set_pen(pen); |
| 636 | w.set_eps(eps); | 624 | w.set_eps(eps); |
| 637 | w.set_fen(true); | 625 | w.set_fen(true); |
| 638 | }); | 626 | }); |
| 639 | 627 | ||
| 640 | r.uartifls().write(|w| { | 628 | r.uartifls().write(|w| { |
| 641 | w.set_rxiflsel(0b000); | 629 | w.set_rxiflsel(0b000); |
| 642 | w.set_txiflsel(0b000); | 630 | w.set_txiflsel(0b000); |
| 643 | }); | 631 | }); |
| 644 | 632 | ||
| 645 | r.uartcr().write(|w| { | 633 | r.uartcr().write(|w| { |
| 646 | w.set_uarten(true); | 634 | w.set_uarten(true); |
| 647 | w.set_rxe(true); | 635 | w.set_rxe(true); |
| 648 | w.set_txe(true); | 636 | w.set_txe(true); |
| 649 | w.set_ctsen(cts.is_some()); | 637 | w.set_ctsen(cts.is_some()); |
| 650 | w.set_rtsen(rts.is_some()); | 638 | w.set_rtsen(rts.is_some()); |
| 651 | }); | 639 | }); |
| 652 | } | ||
| 653 | } | 640 | } |
| 654 | 641 | ||
| 655 | /// sets baudrate on runtime | 642 | /// sets baudrate on runtime |
| @@ -674,15 +661,13 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | |||
| 674 | baud_fbrd = 0; | 661 | baud_fbrd = 0; |
| 675 | } | 662 | } |
| 676 | 663 | ||
| 677 | unsafe { | 664 | // Load PL011's baud divisor registers |
| 678 | // Load PL011's baud divisor registers | 665 | r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); |
| 679 | r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); | 666 | r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); |
| 680 | r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); | ||
| 681 | 667 | ||
| 682 | // PL011 needs a (dummy) line control register write to latch in the | 668 | // PL011 needs a (dummy) line control register write to latch in the |
| 683 | // divisors. We don't want to actually change LCR contents here. | 669 | // divisors. We don't want to actually change LCR contents here. |
| 684 | r.uartlcr_h().modify(|_| {}); | 670 | r.uartlcr_h().modify(|_| {}); |
| 685 | } | ||
| 686 | } | 671 | } |
| 687 | } | 672 | } |
| 688 | 673 | ||
| @@ -731,24 +716,22 @@ mod eh02 { | |||
| 731 | type Error = Error; | 716 | type Error = Error; |
| 732 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 717 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 733 | let r = T::regs(); | 718 | let r = T::regs(); |
| 734 | unsafe { | 719 | if r.uartfr().read().rxfe() { |
| 735 | if r.uartfr().read().rxfe() { | 720 | return Err(nb::Error::WouldBlock); |
| 736 | return Err(nb::Error::WouldBlock); | 721 | } |
| 737 | } | ||
| 738 | 722 | ||
| 739 | let dr = r.uartdr().read(); | 723 | let dr = r.uartdr().read(); |
| 740 | 724 | ||
| 741 | if dr.oe() { | 725 | if dr.oe() { |
| 742 | Err(nb::Error::Other(Error::Overrun)) | 726 | Err(nb::Error::Other(Error::Overrun)) |
| 743 | } else if dr.be() { | 727 | } else if dr.be() { |
| 744 | Err(nb::Error::Other(Error::Break)) | 728 | Err(nb::Error::Other(Error::Break)) |
| 745 | } else if dr.pe() { | 729 | } else if dr.pe() { |
| 746 | Err(nb::Error::Other(Error::Parity)) | 730 | Err(nb::Error::Other(Error::Parity)) |
| 747 | } else if dr.fe() { | 731 | } else if dr.fe() { |
| 748 | Err(nb::Error::Other(Error::Framing)) | 732 | Err(nb::Error::Other(Error::Framing)) |
| 749 | } else { | 733 | } else { |
| 750 | Ok(dr.data()) | 734 | Ok(dr.data()) |
| 751 | } | ||
| 752 | } | 735 | } |
| 753 | } | 736 | } |
| 754 | } | 737 | } |
| @@ -758,22 +741,18 @@ mod eh02 { | |||
| 758 | 741 | ||
| 759 | fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { | 742 | fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { |
| 760 | let r = T::regs(); | 743 | let r = T::regs(); |
| 761 | unsafe { | 744 | if r.uartfr().read().txff() { |
| 762 | if r.uartfr().read().txff() { | 745 | return Err(nb::Error::WouldBlock); |
| 763 | return Err(nb::Error::WouldBlock); | ||
| 764 | } | ||
| 765 | |||
| 766 | r.uartdr().write(|w| w.set_data(word)); | ||
| 767 | } | 746 | } |
| 747 | |||
| 748 | r.uartdr().write(|w| w.set_data(word)); | ||
| 768 | Ok(()) | 749 | Ok(()) |
| 769 | } | 750 | } |
| 770 | 751 | ||
| 771 | fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { | 752 | fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { |
| 772 | let r = T::regs(); | 753 | let r = T::regs(); |
| 773 | unsafe { | 754 | if !r.uartfr().read().txfe() { |
| 774 | if !r.uartfr().read().txfe() { | 755 | return Err(nb::Error::WouldBlock); |
| 775 | return Err(nb::Error::WouldBlock); | ||
| 776 | } | ||
| 777 | } | 756 | } |
| 778 | Ok(()) | 757 | Ok(()) |
| 779 | } | 758 | } |
| @@ -854,22 +833,20 @@ mod eh1 { | |||
| 854 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { | 833 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { |
| 855 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | 834 | fn read(&mut self) -> nb::Result<u8, Self::Error> { |
| 856 | let r = T::regs(); | 835 | let r = T::regs(); |
| 857 | unsafe { | 836 | let dr = r.uartdr().read(); |
| 858 | let dr = r.uartdr().read(); | 837 | |
| 859 | 838 | if dr.oe() { | |
| 860 | if dr.oe() { | 839 | Err(nb::Error::Other(Error::Overrun)) |
| 861 | Err(nb::Error::Other(Error::Overrun)) | 840 | } else if dr.be() { |
| 862 | } else if dr.be() { | 841 | Err(nb::Error::Other(Error::Break)) |
| 863 | Err(nb::Error::Other(Error::Break)) | 842 | } else if dr.pe() { |
| 864 | } else if dr.pe() { | 843 | Err(nb::Error::Other(Error::Parity)) |
| 865 | Err(nb::Error::Other(Error::Parity)) | 844 | } else if dr.fe() { |
| 866 | } else if dr.fe() { | 845 | Err(nb::Error::Other(Error::Framing)) |
| 867 | Err(nb::Error::Other(Error::Framing)) | 846 | } else if dr.fe() { |
| 868 | } else if dr.fe() { | 847 | Ok(dr.data()) |
| 869 | Ok(dr.data()) | 848 | } else { |
| 870 | } else { | 849 | Err(nb::Error::WouldBlock) |
| 871 | Err(nb::Error::WouldBlock) | ||
| 872 | } | ||
| 873 | } | 850 | } |
| 874 | } | 851 | } |
| 875 | } | 852 | } |
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 9fb0dfb70..1900ab416 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs | |||
| @@ -39,7 +39,7 @@ impl crate::usb::Instance for peripherals::USB { | |||
| 39 | 39 | ||
| 40 | const EP_COUNT: usize = 16; | 40 | const EP_COUNT: usize = 16; |
| 41 | const EP_MEMORY_SIZE: usize = 4096; | 41 | const EP_MEMORY_SIZE: usize = 4096; |
| 42 | const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0; | 42 | const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8; |
| 43 | 43 | ||
| 44 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 44 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 45 | static BUS_WAKER: AtomicWaker = NEW_AW; | 45 | static BUS_WAKER: AtomicWaker = NEW_AW; |
| @@ -111,7 +111,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 111 | let regs = T::regs(); | 111 | let regs = T::regs(); |
| 112 | unsafe { | 112 | unsafe { |
| 113 | // zero fill regs | 113 | // zero fill regs |
| 114 | let p = regs.0 as *mut u32; | 114 | let p = regs.as_ptr() as *mut u32; |
| 115 | for i in 0..0x9c / 4 { | 115 | for i in 0..0x9c / 4 { |
| 116 | p.add(i).write_volatile(0) | 116 | p.add(i).write_volatile(0) |
| 117 | } | 117 | } |
| @@ -121,20 +121,20 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 121 | for i in 0..0x100 / 4 { | 121 | for i in 0..0x100 / 4 { |
| 122 | p.add(i).write_volatile(0) | 122 | p.add(i).write_volatile(0) |
| 123 | } | 123 | } |
| 124 | |||
| 125 | regs.usb_muxing().write(|w| { | ||
| 126 | w.set_to_phy(true); | ||
| 127 | w.set_softcon(true); | ||
| 128 | }); | ||
| 129 | regs.usb_pwr().write(|w| { | ||
| 130 | w.set_vbus_detect(true); | ||
| 131 | w.set_vbus_detect_override_en(true); | ||
| 132 | }); | ||
| 133 | regs.main_ctrl().write(|w| { | ||
| 134 | w.set_controller_en(true); | ||
| 135 | }); | ||
| 136 | } | 124 | } |
| 137 | 125 | ||
| 126 | regs.usb_muxing().write(|w| { | ||
| 127 | w.set_to_phy(true); | ||
| 128 | w.set_softcon(true); | ||
| 129 | }); | ||
| 130 | regs.usb_pwr().write(|w| { | ||
| 131 | w.set_vbus_detect(true); | ||
| 132 | w.set_vbus_detect_override_en(true); | ||
| 133 | }); | ||
| 134 | regs.main_ctrl().write(|w| { | ||
| 135 | w.set_controller_en(true); | ||
| 136 | }); | ||
| 137 | |||
| 138 | // Initialize the bus so that it signals that power is available | 138 | // Initialize the bus so that it signals that power is available |
| 139 | BUS_WAKER.wake(); | 139 | BUS_WAKER.wake(); |
| 140 | 140 | ||
| @@ -213,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 213 | }; | 213 | }; |
| 214 | 214 | ||
| 215 | match D::dir() { | 215 | match D::dir() { |
| 216 | Direction::Out => unsafe { | 216 | Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| { |
| 217 | T::dpram().ep_out_control(index - 1).write(|w| { | 217 | w.set_enable(false); |
| 218 | w.set_enable(false); | 218 | w.set_buffer_address(addr); |
| 219 | w.set_buffer_address(addr); | 219 | w.set_interrupt_per_buff(true); |
| 220 | w.set_interrupt_per_buff(true); | 220 | w.set_endpoint_type(ep_type_reg); |
| 221 | w.set_endpoint_type(ep_type_reg); | 221 | }), |
| 222 | }) | 222 | Direction::In => T::dpram().ep_in_control(index - 1).write(|w| { |
| 223 | }, | 223 | w.set_enable(false); |
| 224 | Direction::In => unsafe { | 224 | w.set_buffer_address(addr); |
| 225 | T::dpram().ep_in_control(index - 1).write(|w| { | 225 | w.set_interrupt_per_buff(true); |
| 226 | w.set_enable(false); | 226 | w.set_endpoint_type(ep_type_reg); |
| 227 | w.set_buffer_address(addr); | 227 | }), |
| 228 | w.set_interrupt_per_buff(true); | ||
| 229 | w.set_endpoint_type(ep_type_reg); | ||
| 230 | }) | ||
| 231 | }, | ||
| 232 | } | 228 | } |
| 233 | 229 | ||
| 234 | Ok(Endpoint { | 230 | Ok(Endpoint { |
| @@ -315,22 +311,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 315 | 311 | ||
| 316 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { | 312 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { |
| 317 | let regs = T::regs(); | 313 | let regs = T::regs(); |
| 318 | unsafe { | 314 | regs.inte().write(|w| { |
| 319 | regs.inte().write(|w| { | 315 | w.set_bus_reset(true); |
| 320 | w.set_bus_reset(true); | 316 | w.set_buff_status(true); |
| 321 | w.set_buff_status(true); | 317 | w.set_dev_resume_from_host(true); |
| 322 | w.set_dev_resume_from_host(true); | 318 | w.set_dev_suspend(true); |
| 323 | w.set_dev_suspend(true); | 319 | w.set_setup_req(true); |
| 324 | w.set_setup_req(true); | 320 | }); |
| 325 | }); | 321 | regs.int_ep_ctrl().write(|w| { |
| 326 | regs.int_ep_ctrl().write(|w| { | 322 | w.set_int_ep_active(0xFFFE); // all EPs |
| 327 | w.set_int_ep_active(0xFFFE); // all EPs | 323 | }); |
| 328 | }); | 324 | regs.sie_ctrl().write(|w| { |
| 329 | regs.sie_ctrl().write(|w| { | 325 | w.set_ep0_int_1buf(true); |
| 330 | w.set_ep0_int_1buf(true); | 326 | w.set_pullup_en(true); |
| 331 | w.set_pullup_en(true); | 327 | }); |
| 332 | }) | 328 | |
| 333 | } | ||
| 334 | trace!("enabled"); | 329 | trace!("enabled"); |
| 335 | 330 | ||
| 336 | ( | 331 | ( |
| @@ -355,7 +350,7 @@ pub struct Bus<'d, T: Instance> { | |||
| 355 | 350 | ||
| 356 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 351 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { |
| 357 | async fn poll(&mut self) -> Event { | 352 | async fn poll(&mut self) -> Event { |
| 358 | poll_fn(move |cx| unsafe { | 353 | poll_fn(move |cx| { |
| 359 | BUS_WAKER.register(cx.waker()); | 354 | BUS_WAKER.register(cx.waker()); |
| 360 | 355 | ||
| 361 | if !self.inited { | 356 | if !self.inited { |
| @@ -425,14 +420,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 425 | 420 | ||
| 426 | let n = ep_addr.index(); | 421 | let n = ep_addr.index(); |
| 427 | match ep_addr.direction() { | 422 | match ep_addr.direction() { |
| 428 | Direction::In => unsafe { | 423 | Direction::In => { |
| 429 | T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); | 424 | T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); |
| 430 | T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { | 425 | T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { |
| 431 | w.set_pid(0, true); // first packet is DATA0, but PID is flipped before | 426 | w.set_pid(0, true); // first packet is DATA0, but PID is flipped before |
| 432 | }); | 427 | }); |
| 433 | EP_IN_WAKERS[n].wake(); | 428 | EP_IN_WAKERS[n].wake(); |
| 434 | }, | 429 | } |
| 435 | Direction::Out => unsafe { | 430 | Direction::Out => { |
| 436 | T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); | 431 | T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); |
| 437 | 432 | ||
| 438 | T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { | 433 | T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { |
| @@ -446,7 +441,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 446 | w.set_available(0, true); | 441 | w.set_available(0, true); |
| 447 | }); | 442 | }); |
| 448 | EP_OUT_WAKERS[n].wake(); | 443 | EP_OUT_WAKERS[n].wake(); |
| 449 | }, | 444 | } |
| 450 | } | 445 | } |
| 451 | } | 446 | } |
| 452 | 447 | ||
| @@ -504,7 +499,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | |||
| 504 | let index = self.info.addr.index(); | 499 | let index = self.info.addr.index(); |
| 505 | poll_fn(|cx| { | 500 | poll_fn(|cx| { |
| 506 | EP_IN_WAKERS[index].register(cx.waker()); | 501 | EP_IN_WAKERS[index].register(cx.waker()); |
| 507 | let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() }; | 502 | let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read(); |
| 508 | if val.enable() { | 503 | if val.enable() { |
| 509 | Poll::Ready(()) | 504 | Poll::Ready(()) |
| 510 | } else { | 505 | } else { |
| @@ -526,7 +521,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { | |||
| 526 | let index = self.info.addr.index(); | 521 | let index = self.info.addr.index(); |
| 527 | poll_fn(|cx| { | 522 | poll_fn(|cx| { |
| 528 | EP_OUT_WAKERS[index].register(cx.waker()); | 523 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 529 | let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() }; | 524 | let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read(); |
| 530 | if val.enable() { | 525 | if val.enable() { |
| 531 | Poll::Ready(()) | 526 | Poll::Ready(()) |
| 532 | } else { | 527 | } else { |
| @@ -542,7 +537,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 542 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | 537 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { |
| 543 | trace!("READ WAITING, buf.len() = {}", buf.len()); | 538 | trace!("READ WAITING, buf.len() = {}", buf.len()); |
| 544 | let index = self.info.addr.index(); | 539 | let index = self.info.addr.index(); |
| 545 | let val = poll_fn(|cx| unsafe { | 540 | let val = poll_fn(|cx| { |
| 546 | EP_OUT_WAKERS[index].register(cx.waker()); | 541 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 547 | let val = T::dpram().ep_out_buffer_control(index).read(); | 542 | let val = T::dpram().ep_out_buffer_control(index).read(); |
| 548 | if val.available(0) { | 543 | if val.available(0) { |
| @@ -561,19 +556,17 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 561 | 556 | ||
| 562 | trace!("READ OK, rx_len = {}", rx_len); | 557 | trace!("READ OK, rx_len = {}", rx_len); |
| 563 | 558 | ||
| 564 | unsafe { | 559 | let pid = !val.pid(0); |
| 565 | let pid = !val.pid(0); | 560 | T::dpram().ep_out_buffer_control(index).write(|w| { |
| 566 | T::dpram().ep_out_buffer_control(index).write(|w| { | 561 | w.set_pid(0, pid); |
| 567 | w.set_pid(0, pid); | 562 | w.set_length(0, self.info.max_packet_size); |
| 568 | w.set_length(0, self.info.max_packet_size); | 563 | }); |
| 569 | }); | 564 | cortex_m::asm::delay(12); |
| 570 | cortex_m::asm::delay(12); | 565 | T::dpram().ep_out_buffer_control(index).write(|w| { |
| 571 | T::dpram().ep_out_buffer_control(index).write(|w| { | 566 | w.set_pid(0, pid); |
| 572 | w.set_pid(0, pid); | 567 | w.set_length(0, self.info.max_packet_size); |
| 573 | w.set_length(0, self.info.max_packet_size); | 568 | w.set_available(0, true); |
| 574 | w.set_available(0, true); | 569 | }); |
| 575 | }); | ||
| 576 | } | ||
| 577 | 570 | ||
| 578 | Ok(rx_len) | 571 | Ok(rx_len) |
| 579 | } | 572 | } |
| @@ -588,7 +581,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 588 | trace!("WRITE WAITING"); | 581 | trace!("WRITE WAITING"); |
| 589 | 582 | ||
| 590 | let index = self.info.addr.index(); | 583 | let index = self.info.addr.index(); |
| 591 | let val = poll_fn(|cx| unsafe { | 584 | let val = poll_fn(|cx| { |
| 592 | EP_IN_WAKERS[index].register(cx.waker()); | 585 | EP_IN_WAKERS[index].register(cx.waker()); |
| 593 | let val = T::dpram().ep_in_buffer_control(index).read(); | 586 | let val = T::dpram().ep_in_buffer_control(index).read(); |
| 594 | if val.available(0) { | 587 | if val.available(0) { |
| @@ -601,21 +594,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 601 | 594 | ||
| 602 | self.buf.write(buf); | 595 | self.buf.write(buf); |
| 603 | 596 | ||
| 604 | unsafe { | 597 | let pid = !val.pid(0); |
| 605 | let pid = !val.pid(0); | 598 | T::dpram().ep_in_buffer_control(index).write(|w| { |
| 606 | T::dpram().ep_in_buffer_control(index).write(|w| { | 599 | w.set_pid(0, pid); |
| 607 | w.set_pid(0, pid); | 600 | w.set_length(0, buf.len() as _); |
| 608 | w.set_length(0, buf.len() as _); | 601 | w.set_full(0, true); |
| 609 | w.set_full(0, true); | 602 | }); |
| 610 | }); | 603 | cortex_m::asm::delay(12); |
| 611 | cortex_m::asm::delay(12); | 604 | T::dpram().ep_in_buffer_control(index).write(|w| { |
| 612 | T::dpram().ep_in_buffer_control(index).write(|w| { | 605 | w.set_pid(0, pid); |
| 613 | w.set_pid(0, pid); | 606 | w.set_length(0, buf.len() as _); |
| 614 | w.set_length(0, buf.len() as _); | 607 | w.set_full(0, true); |
| 615 | w.set_full(0, true); | 608 | w.set_available(0, true); |
| 616 | w.set_available(0, true); | 609 | }); |
| 617 | }); | ||
| 618 | } | ||
| 619 | 610 | ||
| 620 | trace!("WRITE OK"); | 611 | trace!("WRITE OK"); |
| 621 | 612 | ||
| @@ -637,9 +628,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 637 | loop { | 628 | loop { |
| 638 | trace!("SETUP read waiting"); | 629 | trace!("SETUP read waiting"); |
| 639 | let regs = T::regs(); | 630 | let regs = T::regs(); |
| 640 | unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) }; | 631 | regs.inte().write_set(|w| w.set_setup_req(true)); |
| 641 | 632 | ||
| 642 | poll_fn(|cx| unsafe { | 633 | poll_fn(|cx| { |
| 643 | EP_OUT_WAKERS[0].register(cx.waker()); | 634 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 644 | let regs = T::regs(); | 635 | let regs = T::regs(); |
| 645 | if regs.sie_status().read().setup_rec() { | 636 | if regs.sie_status().read().setup_rec() { |
| @@ -654,13 +645,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 654 | EndpointBuffer::<T>::new(0, 8).read(&mut buf); | 645 | EndpointBuffer::<T>::new(0, 8).read(&mut buf); |
| 655 | 646 | ||
| 656 | let regs = T::regs(); | 647 | let regs = T::regs(); |
| 657 | unsafe { | 648 | regs.sie_status().write(|w| w.set_setup_rec(true)); |
| 658 | regs.sie_status().write(|w| w.set_setup_rec(true)); | ||
| 659 | 649 | ||
| 660 | // set PID to 0, so (after toggling) first DATA is PID 1 | 650 | // set PID to 0, so (after toggling) first DATA is PID 1 |
| 661 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); | 651 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); |
| 662 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); | 652 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); |
| 663 | } | ||
| 664 | 653 | ||
| 665 | trace!("SETUP read ok"); | 654 | trace!("SETUP read ok"); |
| 666 | return buf; | 655 | return buf; |
| @@ -668,23 +657,21 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 668 | } | 657 | } |
| 669 | 658 | ||
| 670 | async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { | 659 | async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { |
| 671 | unsafe { | 660 | let bufcontrol = T::dpram().ep_out_buffer_control(0); |
| 672 | let bufcontrol = T::dpram().ep_out_buffer_control(0); | 661 | let pid = !bufcontrol.read().pid(0); |
| 673 | let pid = !bufcontrol.read().pid(0); | 662 | bufcontrol.write(|w| { |
| 674 | bufcontrol.write(|w| { | 663 | w.set_length(0, self.max_packet_size); |
| 675 | w.set_length(0, self.max_packet_size); | 664 | w.set_pid(0, pid); |
| 676 | w.set_pid(0, pid); | 665 | }); |
| 677 | }); | 666 | cortex_m::asm::delay(12); |
| 678 | cortex_m::asm::delay(12); | 667 | bufcontrol.write(|w| { |
| 679 | bufcontrol.write(|w| { | 668 | w.set_length(0, self.max_packet_size); |
| 680 | w.set_length(0, self.max_packet_size); | 669 | w.set_pid(0, pid); |
| 681 | w.set_pid(0, pid); | 670 | w.set_available(0, true); |
| 682 | w.set_available(0, true); | 671 | }); |
| 683 | }); | ||
| 684 | } | ||
| 685 | 672 | ||
| 686 | trace!("control: data_out len={} first={} last={}", buf.len(), first, last); | 673 | trace!("control: data_out len={} first={} last={}", buf.len(), first, last); |
| 687 | let val = poll_fn(|cx| unsafe { | 674 | let val = poll_fn(|cx| { |
| 688 | EP_OUT_WAKERS[0].register(cx.waker()); | 675 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 689 | let val = T::dpram().ep_out_buffer_control(0).read(); | 676 | let val = T::dpram().ep_out_buffer_control(0).read(); |
| 690 | if val.available(0) { | 677 | if val.available(0) { |
| @@ -714,24 +701,22 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 714 | } | 701 | } |
| 715 | EndpointBuffer::<T>::new(0x100, 64).write(data); | 702 | EndpointBuffer::<T>::new(0x100, 64).write(data); |
| 716 | 703 | ||
| 717 | unsafe { | 704 | let bufcontrol = T::dpram().ep_in_buffer_control(0); |
| 718 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | 705 | let pid = !bufcontrol.read().pid(0); |
| 719 | let pid = !bufcontrol.read().pid(0); | 706 | bufcontrol.write(|w| { |
| 720 | bufcontrol.write(|w| { | 707 | w.set_length(0, data.len() as _); |
| 721 | w.set_length(0, data.len() as _); | 708 | w.set_pid(0, pid); |
| 722 | w.set_pid(0, pid); | 709 | w.set_full(0, true); |
| 723 | w.set_full(0, true); | 710 | }); |
| 724 | }); | 711 | cortex_m::asm::delay(12); |
| 725 | cortex_m::asm::delay(12); | 712 | bufcontrol.write(|w| { |
| 726 | bufcontrol.write(|w| { | 713 | w.set_length(0, data.len() as _); |
| 727 | w.set_length(0, data.len() as _); | 714 | w.set_pid(0, pid); |
| 728 | w.set_pid(0, pid); | 715 | w.set_full(0, true); |
| 729 | w.set_full(0, true); | 716 | w.set_available(0, true); |
| 730 | w.set_available(0, true); | 717 | }); |
| 731 | }); | ||
| 732 | } | ||
| 733 | 718 | ||
| 734 | poll_fn(|cx| unsafe { | 719 | poll_fn(|cx| { |
| 735 | EP_IN_WAKERS[0].register(cx.waker()); | 720 | EP_IN_WAKERS[0].register(cx.waker()); |
| 736 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | 721 | let bufcontrol = T::dpram().ep_in_buffer_control(0); |
| 737 | if bufcontrol.read().available(0) { | 722 | if bufcontrol.read().available(0) { |
| @@ -745,48 +730,44 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 745 | 730 | ||
| 746 | if last { | 731 | if last { |
| 747 | // prepare status phase right away. | 732 | // prepare status phase right away. |
| 748 | unsafe { | 733 | let bufcontrol = T::dpram().ep_out_buffer_control(0); |
| 749 | let bufcontrol = T::dpram().ep_out_buffer_control(0); | ||
| 750 | bufcontrol.write(|w| { | ||
| 751 | w.set_length(0, 0); | ||
| 752 | w.set_pid(0, true); | ||
| 753 | }); | ||
| 754 | cortex_m::asm::delay(12); | ||
| 755 | bufcontrol.write(|w| { | ||
| 756 | w.set_length(0, 0); | ||
| 757 | w.set_pid(0, true); | ||
| 758 | w.set_available(0, true); | ||
| 759 | }); | ||
| 760 | } | ||
| 761 | } | ||
| 762 | |||
| 763 | Ok(()) | ||
| 764 | } | ||
| 765 | |||
| 766 | async fn accept(&mut self) { | ||
| 767 | trace!("control: accept"); | ||
| 768 | |||
| 769 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | ||
| 770 | unsafe { | ||
| 771 | bufcontrol.write(|w| { | 734 | bufcontrol.write(|w| { |
| 772 | w.set_length(0, 0); | 735 | w.set_length(0, 0); |
| 773 | w.set_pid(0, true); | 736 | w.set_pid(0, true); |
| 774 | w.set_full(0, true); | ||
| 775 | }); | 737 | }); |
| 776 | cortex_m::asm::delay(12); | 738 | cortex_m::asm::delay(12); |
| 777 | bufcontrol.write(|w| { | 739 | bufcontrol.write(|w| { |
| 778 | w.set_length(0, 0); | 740 | w.set_length(0, 0); |
| 779 | w.set_pid(0, true); | 741 | w.set_pid(0, true); |
| 780 | w.set_full(0, true); | ||
| 781 | w.set_available(0, true); | 742 | w.set_available(0, true); |
| 782 | }); | 743 | }); |
| 783 | } | 744 | } |
| 784 | 745 | ||
| 746 | Ok(()) | ||
| 747 | } | ||
| 748 | |||
| 749 | async fn accept(&mut self) { | ||
| 750 | trace!("control: accept"); | ||
| 751 | |||
| 752 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | ||
| 753 | bufcontrol.write(|w| { | ||
| 754 | w.set_length(0, 0); | ||
| 755 | w.set_pid(0, true); | ||
| 756 | w.set_full(0, true); | ||
| 757 | }); | ||
| 758 | cortex_m::asm::delay(12); | ||
| 759 | bufcontrol.write(|w| { | ||
| 760 | w.set_length(0, 0); | ||
| 761 | w.set_pid(0, true); | ||
| 762 | w.set_full(0, true); | ||
| 763 | w.set_available(0, true); | ||
| 764 | }); | ||
| 765 | |||
| 785 | // wait for completion before returning, needed so | 766 | // wait for completion before returning, needed so |
| 786 | // set_address() doesn't happen early. | 767 | // set_address() doesn't happen early. |
| 787 | poll_fn(|cx| { | 768 | poll_fn(|cx| { |
| 788 | EP_IN_WAKERS[0].register(cx.waker()); | 769 | EP_IN_WAKERS[0].register(cx.waker()); |
| 789 | if unsafe { bufcontrol.read().available(0) } { | 770 | if bufcontrol.read().available(0) { |
| 790 | Poll::Pending | 771 | Poll::Pending |
| 791 | } else { | 772 | } else { |
| 792 | Poll::Ready(()) | 773 | Poll::Ready(()) |
| @@ -799,14 +780,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 799 | trace!("control: reject"); | 780 | trace!("control: reject"); |
| 800 | 781 | ||
| 801 | let regs = T::regs(); | 782 | let regs = T::regs(); |
| 802 | unsafe { | 783 | regs.ep_stall_arm().write_set(|w| { |
| 803 | regs.ep_stall_arm().write_set(|w| { | 784 | w.set_ep0_in(true); |
| 804 | w.set_ep0_in(true); | 785 | w.set_ep0_out(true); |
| 805 | w.set_ep0_out(true); | 786 | }); |
| 806 | }); | 787 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); |
| 807 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); | 788 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true)); |
| 808 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true)); | ||
| 809 | } | ||
| 810 | } | 789 | } |
| 811 | 790 | ||
| 812 | async fn accept_set_address(&mut self, addr: u8) { | 791 | async fn accept_set_address(&mut self, addr: u8) { |
| @@ -814,6 +793,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 814 | 793 | ||
| 815 | let regs = T::regs(); | 794 | let regs = T::regs(); |
| 816 | trace!("setting addr: {}", addr); | 795 | trace!("setting addr: {}", addr); |
| 817 | unsafe { regs.addr_endp().write(|w| w.set_address(addr)) } | 796 | regs.addr_endp().write(|w| w.set_address(addr)) |
| 818 | } | 797 | } |
| 819 | } | 798 | } |
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 78a295ae7..d37795cc9 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs | |||
| @@ -35,45 +35,37 @@ impl Watchdog { | |||
| 35 | /// * `cycles` - Total number of tick cycles before the next tick is generated. | 35 | /// * `cycles` - Total number of tick cycles before the next tick is generated. |
| 36 | /// It is expected to be the frequency in MHz of clk_ref. | 36 | /// It is expected to be the frequency in MHz of clk_ref. |
| 37 | pub fn enable_tick_generation(&mut self, cycles: u8) { | 37 | pub fn enable_tick_generation(&mut self, cycles: u8) { |
| 38 | unsafe { | 38 | let watchdog = pac::WATCHDOG; |
| 39 | let watchdog = pac::WATCHDOG; | 39 | watchdog.tick().write(|w| { |
| 40 | watchdog.tick().write(|w| { | 40 | w.set_enable(true); |
| 41 | w.set_enable(true); | 41 | w.set_cycles(cycles.into()) |
| 42 | w.set_cycles(cycles.into()) | 42 | }); |
| 43 | }); | ||
| 44 | } | ||
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode | 45 | /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode |
| 48 | /// or when JTAG is accessing bus fabric | 46 | /// or when JTAG is accessing bus fabric |
| 49 | pub fn pause_on_debug(&mut self, pause: bool) { | 47 | pub fn pause_on_debug(&mut self, pause: bool) { |
| 50 | unsafe { | 48 | let watchdog = pac::WATCHDOG; |
| 51 | let watchdog = pac::WATCHDOG; | 49 | watchdog.ctrl().write(|w| { |
| 52 | watchdog.ctrl().write(|w| { | 50 | w.set_pause_dbg0(pause); |
| 53 | w.set_pause_dbg0(pause); | 51 | w.set_pause_dbg1(pause); |
| 54 | w.set_pause_dbg1(pause); | 52 | w.set_pause_jtag(pause); |
| 55 | w.set_pause_jtag(pause); | 53 | }) |
| 56 | }) | ||
| 57 | } | ||
| 58 | } | 54 | } |
| 59 | 55 | ||
| 60 | fn load_counter(&self, counter: u32) { | 56 | fn load_counter(&self, counter: u32) { |
| 61 | unsafe { | 57 | let watchdog = pac::WATCHDOG; |
| 62 | let watchdog = pac::WATCHDOG; | 58 | watchdog.load().write_value(pac::watchdog::regs::Load(counter)); |
| 63 | watchdog.load().write_value(pac::watchdog::regs::Load(counter)); | ||
| 64 | } | ||
| 65 | } | 59 | } |
| 66 | 60 | ||
| 67 | fn enable(&self, bit: bool) { | 61 | fn enable(&self, bit: bool) { |
| 68 | unsafe { | 62 | let watchdog = pac::WATCHDOG; |
| 69 | let watchdog = pac::WATCHDOG; | 63 | watchdog.ctrl().write(|w| w.set_enable(bit)) |
| 70 | watchdog.ctrl().write(|w| w.set_enable(bit)) | ||
| 71 | } | ||
| 72 | } | 64 | } |
| 73 | 65 | ||
| 74 | // Configure which hardware will be reset by the watchdog | 66 | // Configure which hardware will be reset by the watchdog |
| 75 | // (everything except ROSC, XOSC) | 67 | // (everything except ROSC, XOSC) |
| 76 | unsafe fn configure_wdog_reset_triggers(&self) { | 68 | fn configure_wdog_reset_triggers(&self) { |
| 77 | let psm = pac::PSM; | 69 | let psm = pac::PSM; |
| 78 | psm.wdsel().write_value(pac::psm::regs::Wdsel( | 70 | psm.wdsel().write_value(pac::psm::regs::Wdsel( |
| 79 | 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), | 71 | 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), |
| @@ -100,23 +92,19 @@ impl Watchdog { | |||
| 100 | self.load_value = delay_us * 2; | 92 | self.load_value = delay_us * 2; |
| 101 | 93 | ||
| 102 | self.enable(false); | 94 | self.enable(false); |
| 103 | unsafe { | 95 | self.configure_wdog_reset_triggers(); |
| 104 | self.configure_wdog_reset_triggers(); | ||
| 105 | } | ||
| 106 | self.load_counter(self.load_value); | 96 | self.load_counter(self.load_value); |
| 107 | self.enable(true); | 97 | self.enable(true); |
| 108 | } | 98 | } |
| 109 | 99 | ||
| 110 | /// Trigger a system reset | 100 | /// Trigger a system reset |
| 111 | pub fn trigger_reset(&mut self) { | 101 | pub fn trigger_reset(&mut self) { |
| 112 | unsafe { | 102 | self.configure_wdog_reset_triggers(); |
| 113 | self.configure_wdog_reset_triggers(); | 103 | self.pause_on_debug(false); |
| 114 | self.pause_on_debug(false); | 104 | self.enable(true); |
| 115 | self.enable(true); | 105 | let watchdog = pac::WATCHDOG; |
| 116 | let watchdog = pac::WATCHDOG; | 106 | watchdog.ctrl().write(|w| { |
| 117 | watchdog.ctrl().write(|w| { | 107 | w.set_trigger(true); |
| 118 | w.set_trigger(true); | 108 | }) |
| 119 | }) | ||
| 120 | } | ||
| 121 | } | 109 | } |
| 122 | } | 110 | } |
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs index 6a982507a..0e0de85fa 100644 --- a/tests/rp/src/bin/float.rs +++ b/tests/rp/src/bin/float.rs | |||
| @@ -18,11 +18,9 @@ async fn main(_spawner: Spawner) { | |||
| 18 | const PI_F: f32 = 3.1415926535f32; | 18 | const PI_F: f32 = 3.1415926535f32; |
| 19 | const PI_D: f64 = 3.14159265358979323846f64; | 19 | const PI_D: f64 = 3.14159265358979323846f64; |
| 20 | 20 | ||
| 21 | unsafe { | 21 | pac::BUSCTRL |
| 22 | pac::BUSCTRL | 22 | .perfsel(0) |
| 23 | .perfsel(0) | 23 | .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM)); |
| 24 | .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM)); | ||
| 25 | } | ||
| 26 | 24 | ||
| 27 | for i in 0..=360 { | 25 | for i in 0..=360 { |
| 28 | let rad_f = (i as f32) * PI_F / 180.0; | 26 | let rad_f = (i as f32) * PI_F / 180.0; |
| @@ -46,7 +44,7 @@ async fn main(_spawner: Spawner) { | |||
| 46 | Timer::after(Duration::from_millis(10)).await; | 44 | Timer::after(Duration::from_millis(10)).await; |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | let rom_accesses = unsafe { pac::BUSCTRL.perfctr(0).read().perfctr() }; | 47 | let rom_accesses = pac::BUSCTRL.perfctr(0).read().perfctr(); |
| 50 | // every float operation used here uses at least 10 cycles | 48 | // every float operation used here uses at least 10 cycles |
| 51 | defmt::assert!(rom_accesses >= 360 * 12 * 10); | 49 | defmt::assert!(rom_accesses >= 360 * 12 * 10); |
| 52 | 50 | ||
