diff options
| author | Chuck Davis <[email protected]> | 2023-05-03 21:07:28 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-03 21:07:28 -0500 |
| commit | 91d1fff4edf41a251044ccde03af4ccf8a135f65 (patch) | |
| tree | f76426657679c7a400894f71278086ac83dfd554 | |
| parent | 629e0ea595b28d89aad3f953b7190b04d78ff9d3 (diff) | |
| parent | 374c92a4f0fda2932a0a86e5dcc3dc33651a48c7 (diff) | |
Merge branch 'embassy-rs:master' into master
| -rw-r--r-- | embassy-rp/src/gpio.rs | 143 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-rp/src/multicore.rs | 5 | ||||
| -rw-r--r-- | embassy-rp/src/pio.rs | 482 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/buffered.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 128 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_async.rs | 34 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_dma.rs | 10 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_hd44780.rs | 243 | ||||
| -rw-r--r-- | examples/rp/src/bin/ws2812-pio.rs | 15 | ||||
| -rw-r--r-- | tests/rp/src/bin/gpio_multicore.rs | 63 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart_dma.rs | 4 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | tests/stm32/build.rs | 13 | ||||
| -rw-r--r-- | tests/stm32/src/bin/spi.rs | 1 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart.rs | 77 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart_dma.rs | 3 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart_rx_ringbuffered.rs | 7 | ||||
| -rw-r--r-- | tests/stm32/src/example_common.rs | 5 |
21 files changed, 748 insertions, 503 deletions
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 98e182868..da8efba91 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs | |||
| @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 9 | 9 | ||
| 10 | use crate::pac::common::{Reg, RW}; | 10 | use crate::pac::common::{Reg, RW}; |
| 11 | use crate::pac::SIO; | 11 | use crate::pac::SIO; |
| 12 | use crate::{interrupt, pac, peripherals, Peripheral}; | 12 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; |
| 13 | 13 | ||
| 14 | const PIN_COUNT: usize = 30; | 14 | const PIN_COUNT: usize = 30; |
| 15 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 15 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| @@ -136,16 +136,11 @@ pub enum InterruptTrigger { | |||
| 136 | AnyEdge, | 136 | AnyEdge, |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | impl InterruptTrigger { | 139 | pub(crate) unsafe fn init() { |
| 140 | fn from_u32(value: u32) -> Option<InterruptTrigger> { | 140 | let irq = interrupt::IO_IRQ_BANK0::steal(); |
| 141 | match value { | 141 | irq.disable(); |
| 142 | 1 => Some(InterruptTrigger::LevelLow), | 142 | irq.set_priority(interrupt::Priority::P3); |
| 143 | 2 => Some(InterruptTrigger::LevelHigh), | 143 | irq.enable(); |
| 144 | 3 => Some(InterruptTrigger::EdgeLow), | ||
| 145 | 4 => Some(InterruptTrigger::EdgeHigh), | ||
| 146 | _ => None, | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | 144 | } |
| 150 | 145 | ||
| 151 | #[interrupt] | 146 | #[interrupt] |
| @@ -166,27 +161,15 @@ unsafe fn IO_IRQ_BANK0() { | |||
| 166 | let pin_group = (pin % 8) as usize; | 161 | let pin_group = (pin % 8) as usize; |
| 167 | let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32; | 162 | let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32; |
| 168 | 163 | ||
| 169 | if let Some(trigger) = InterruptTrigger::from_u32(event) { | 164 | // no more than one event can be awaited per pin at any given time, so |
| 170 | critical_section::with(|_| { | 165 | // we can just clear all interrupt enables for that pin without having |
| 171 | proc_intx.inte(pin / 8).modify(|w| match trigger { | 166 | // to check which event was signalled. |
| 172 | InterruptTrigger::AnyEdge => { | 167 | if event != 0 { |
| 173 | w.set_edge_high(pin_group, false); | 168 | proc_intx.inte(pin / 8).write_clear(|w| { |
| 174 | w.set_edge_low(pin_group, false); | 169 | w.set_edge_high(pin_group, true); |
| 175 | } | 170 | w.set_edge_low(pin_group, true); |
| 176 | InterruptTrigger::LevelHigh => { | 171 | w.set_level_high(pin_group, true); |
| 177 | trace!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin); | 172 | w.set_level_low(pin_group, true); |
| 178 | w.set_level_high(pin_group, false); | ||
| 179 | } | ||
| 180 | InterruptTrigger::LevelLow => { | ||
| 181 | w.set_level_low(pin_group, false); | ||
| 182 | } | ||
| 183 | InterruptTrigger::EdgeHigh => { | ||
| 184 | w.set_edge_high(pin_group, false); | ||
| 185 | } | ||
| 186 | InterruptTrigger::EdgeLow => { | ||
| 187 | w.set_edge_low(pin_group, false); | ||
| 188 | } | ||
| 189 | }); | ||
| 190 | }); | 173 | }); |
| 191 | INTERRUPT_WAKERS[pin as usize].wake(); | 174 | INTERRUPT_WAKERS[pin as usize].wake(); |
| 192 | } | 175 | } |
| @@ -203,16 +186,26 @@ impl<'d, T: Pin> InputFuture<'d, T> { | |||
| 203 | 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 { |
| 204 | into_ref!(pin); | 187 | into_ref!(pin); |
| 205 | unsafe { | 188 | unsafe { |
| 206 | let irq = interrupt::IO_IRQ_BANK0::steal(); | 189 | let pin_group = (pin.pin() % 8) as usize; |
| 207 | irq.disable(); | 190 | // first, clear the INTR register bits. without this INTR will still |
| 208 | irq.set_priority(interrupt::Priority::P3); | 191 | // contain reports of previous edges, causing the IRQ to fire early |
| 192 | // on stale state. clearing these means that we can only detect edges | ||
| 193 | // that occur *after* the clear happened, but since both this and the | ||
| 194 | // alternative are fundamentally racy it's probably fine. | ||
| 195 | // (the alternative being checking the current level and waiting for | ||
| 196 | // its inverse, but that requires reading the current level and thus | ||
| 197 | // missing anything that happened before the level was read.) | ||
| 198 | pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { | ||
| 199 | w.set_edge_high(pin_group, true); | ||
| 200 | w.set_edge_low(pin_group, true); | ||
| 201 | }); | ||
| 209 | 202 | ||
| 210 | // Each INTR register is divided into 8 groups, one group for each | 203 | // Each INTR register is divided into 8 groups, one group for each |
| 211 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, | 204 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, |
| 212 | // and EGDE_HIGH. | 205 | // and EGDE_HIGH. |
| 213 | let pin_group = (pin.pin() % 8) as usize; | 206 | pin.int_proc() |
| 214 | critical_section::with(|_| { | 207 | .inte((pin.pin() / 8) as usize) |
| 215 | pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level { | 208 | .write_set(|w| match level { |
| 216 | InterruptTrigger::LevelHigh => { | 209 | InterruptTrigger::LevelHigh => { |
| 217 | trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); | 210 | trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); |
| 218 | w.set_level_high(pin_group, true); | 211 | w.set_level_high(pin_group, true); |
| @@ -227,12 +220,10 @@ impl<'d, T: Pin> InputFuture<'d, T> { | |||
| 227 | w.set_edge_low(pin_group, true); | 220 | w.set_edge_low(pin_group, true); |
| 228 | } | 221 | } |
| 229 | InterruptTrigger::AnyEdge => { | 222 | InterruptTrigger::AnyEdge => { |
| 230 | // noop | 223 | w.set_edge_high(pin_group, true); |
| 224 | w.set_edge_low(pin_group, true); | ||
| 231 | } | 225 | } |
| 232 | }); | 226 | }); |
| 233 | }); | ||
| 234 | |||
| 235 | irq.enable(); | ||
| 236 | } | 227 | } |
| 237 | 228 | ||
| 238 | Self { pin, level } | 229 | Self { pin, level } |
| @@ -257,47 +248,21 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { | |||
| 257 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. | 248 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. |
| 258 | let pin_group = (self.pin.pin() % 8) as usize; | 249 | let pin_group = (self.pin.pin() % 8) as usize; |
| 259 | 250 | ||
| 260 | // This should check the the level of the interrupt trigger level of | 251 | // since the interrupt handler clears all INTE flags we'll check that |
| 261 | // the pin and if it has been disabled that means it was done by the | 252 | // all have been cleared and unconditionally return Ready(()) if so. |
| 262 | // interrupt service routine, so we then know that the event/trigger | 253 | // we don't need further handshaking since only a single event wait |
| 263 | // happened and Poll::Ready will be returned. | 254 | // is possible for any given pin at any given time. |
| 264 | trace!("{:?} for pin {}", self.level, self.pin.pin()); | 255 | if !inte.edge_high(pin_group) |
| 265 | match self.level { | 256 | && !inte.edge_low(pin_group) |
| 266 | InterruptTrigger::AnyEdge => { | 257 | && !inte.level_high(pin_group) |
| 267 | if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) { | 258 | && !inte.level_low(pin_group) |
| 268 | #[rustfmt::skip] | 259 | { |
| 269 | trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); | 260 | trace!( |
| 270 | return Poll::Ready(()); | 261 | "{:?} for pin {} was cleared, return Poll::Ready", |
| 271 | } | 262 | self.level, |
| 272 | } | 263 | self.pin.pin() |
| 273 | InterruptTrigger::LevelHigh => { | 264 | ); |
| 274 | if !inte.level_high(pin_group) { | 265 | return Poll::Ready(()); |
| 275 | #[rustfmt::skip] | ||
| 276 | trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); | ||
| 277 | return Poll::Ready(()); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | InterruptTrigger::LevelLow => { | ||
| 281 | if !inte.level_low(pin_group) { | ||
| 282 | #[rustfmt::skip] | ||
| 283 | trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); | ||
| 284 | return Poll::Ready(()); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | InterruptTrigger::EdgeHigh => { | ||
| 288 | if !inte.edge_high(pin_group) { | ||
| 289 | #[rustfmt::skip] | ||
| 290 | trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); | ||
| 291 | return Poll::Ready(()); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | InterruptTrigger::EdgeLow => { | ||
| 295 | if !inte.edge_low(pin_group) { | ||
| 296 | #[rustfmt::skip] | ||
| 297 | trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); | ||
| 298 | return Poll::Ready(()); | ||
| 299 | } | ||
| 300 | } | ||
| 301 | } | 266 | } |
| 302 | trace!("InputFuture::poll return Poll::Pending"); | 267 | trace!("InputFuture::poll return Poll::Pending"); |
| 303 | Poll::Pending | 268 | Poll::Pending |
| @@ -644,23 +609,17 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 644 | 609 | ||
| 645 | #[inline] | 610 | #[inline] |
| 646 | pub async fn wait_for_rising_edge(&mut self) { | 611 | pub async fn wait_for_rising_edge(&mut self) { |
| 647 | self.wait_for_low().await; | 612 | InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; |
| 648 | self.wait_for_high().await; | ||
| 649 | } | 613 | } |
| 650 | 614 | ||
| 651 | #[inline] | 615 | #[inline] |
| 652 | pub async fn wait_for_falling_edge(&mut self) { | 616 | pub async fn wait_for_falling_edge(&mut self) { |
| 653 | self.wait_for_high().await; | 617 | InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; |
| 654 | self.wait_for_low().await; | ||
| 655 | } | 618 | } |
| 656 | 619 | ||
| 657 | #[inline] | 620 | #[inline] |
| 658 | pub async fn wait_for_any_edge(&mut self) { | 621 | pub async fn wait_for_any_edge(&mut self) { |
| 659 | if self.is_high() { | 622 | InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; |
| 660 | self.wait_for_low().await; | ||
| 661 | } else { | ||
| 662 | self.wait_for_high().await; | ||
| 663 | } | ||
| 664 | } | 623 | } |
| 665 | } | 624 | } |
| 666 | 625 | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index d69d12a30..cba7559df 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -157,6 +157,7 @@ pub fn init(_config: config::Config) -> Peripherals { | |||
| 157 | timer::init(); | 157 | timer::init(); |
| 158 | dma::init(); | 158 | dma::init(); |
| 159 | pio::init(); | 159 | pio::init(); |
| 160 | gpio::init(); | ||
| 160 | } | 161 | } |
| 161 | 162 | ||
| 162 | peripherals | 163 | peripherals |
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index e51fc218a..c84fea5c8 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs | |||
| @@ -33,7 +33,7 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; | |||
| 33 | 33 | ||
| 34 | use crate::interrupt::{Interrupt, InterruptExt}; | 34 | use crate::interrupt::{Interrupt, InterruptExt}; |
| 35 | use crate::peripherals::CORE1; | 35 | use crate::peripherals::CORE1; |
| 36 | use crate::{interrupt, pac}; | 36 | use crate::{gpio, interrupt, pac}; |
| 37 | 37 | ||
| 38 | const PAUSE_TOKEN: u32 = 0xDEADBEEF; | 38 | const PAUSE_TOKEN: u32 = 0xDEADBEEF; |
| 39 | const RESUME_TOKEN: u32 = !0xDEADBEEF; | 39 | const RESUME_TOKEN: u32 = !0xDEADBEEF; |
| @@ -68,6 +68,9 @@ fn install_stack_guard(stack_bottom: *mut usize) { | |||
| 68 | #[inline(always)] | 68 | #[inline(always)] |
| 69 | fn core1_setup(stack_bottom: *mut usize) { | 69 | fn core1_setup(stack_bottom: *mut usize) { |
| 70 | install_stack_guard(stack_bottom); | 70 | install_stack_guard(stack_bottom); |
| 71 | unsafe { | ||
| 72 | gpio::init(); | ||
| 73 | } | ||
| 71 | } | 74 | } |
| 72 | 75 | ||
| 73 | /// Data type for a properly aligned stack of N bytes | 76 | /// Data type for a properly aligned stack of N bytes |
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 7faec10b5..5433d3f21 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs | |||
| @@ -5,14 +5,14 @@ use core::sync::atomic::{compiler_fence, Ordering}; | |||
| 5 | use core::task::{Context, Poll}; | 5 | use core::task::{Context, Poll}; |
| 6 | 6 | ||
| 7 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | 7 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; |
| 8 | use embassy_hal_common::PeripheralRef; | 8 | use embassy_hal_common::{Peripheral, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 10 | ||
| 11 | use crate::dma::{Channel, Transfer}; | 11 | use crate::dma::{Channel, Transfer, Word}; |
| 12 | use crate::gpio::sealed::Pin as SealedPin; | 12 | use crate::gpio::sealed::Pin as SealedPin; |
| 13 | use crate::gpio::{Drive, Pin, Pull, SlewRate}; | 13 | use crate::gpio::{Drive, Pin, Pull, SlewRate}; |
| 14 | use crate::pac::dma::vals::{DataSize, TreqSel}; | 14 | use crate::pac::dma::vals::TreqSel; |
| 15 | use crate::pio::sealed::{PioInstance as _, SmInstance as _}; | 15 | use crate::pio::sealed::PioInstance as _; |
| 16 | use crate::{interrupt, pac, peripherals, RegExt}; | 16 | use crate::{interrupt, pac, peripherals, RegExt}; |
| 17 | 17 | ||
| 18 | struct Wakers([AtomicWaker; 12]); | 18 | struct Wakers([AtomicWaker; 12]); |
| @@ -119,10 +119,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture | |||
| 119 | if self.get_mut().sm.try_push_tx(value) { | 119 | if self.get_mut().sm.try_push_tx(value) { |
| 120 | Poll::Ready(()) | 120 | Poll::Ready(()) |
| 121 | } else { | 121 | } else { |
| 122 | WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); | 122 | WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::SM as usize].register(cx.waker()); |
| 123 | unsafe { | 123 | unsafe { |
| 124 | PIO::PIO.irqs(0).inte().write_set(|m| { | 124 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 125 | m.0 = TXNFULL_MASK << SM::Sm::SM_NO; | 125 | m.0 = TXNFULL_MASK << SM::SM; |
| 126 | }); | 126 | }); |
| 127 | } | 127 | } |
| 128 | // debug!("Pending"); | 128 | // debug!("Pending"); |
| @@ -135,7 +135,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<' | |||
| 135 | fn drop(&mut self) { | 135 | fn drop(&mut self) { |
| 136 | unsafe { | 136 | unsafe { |
| 137 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 137 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 138 | m.0 = TXNFULL_MASK << SM::Sm::SM_NO; | 138 | m.0 = TXNFULL_MASK << SM::SM; |
| 139 | }); | 139 | }); |
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| @@ -164,10 +164,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, | |||
| 164 | if let Some(v) = self.sm.try_pull_rx() { | 164 | if let Some(v) = self.sm.try_pull_rx() { |
| 165 | Poll::Ready(v) | 165 | Poll::Ready(v) |
| 166 | } else { | 166 | } else { |
| 167 | WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); | 167 | WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::SM].register(cx.waker()); |
| 168 | unsafe { | 168 | unsafe { |
| 169 | PIO::PIO.irqs(0).inte().write_set(|m| { | 169 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 170 | m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; | 170 | m.0 = RXNEMPTY_MASK << SM::SM; |
| 171 | }); | 171 | }); |
| 172 | } | 172 | } |
| 173 | //debug!("Pending"); | 173 | //debug!("Pending"); |
| @@ -180,7 +180,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S | |||
| 180 | fn drop(&mut self) { | 180 | fn drop(&mut self) { |
| 181 | unsafe { | 181 | unsafe { |
| 182 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 182 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 183 | m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; | 183 | m.0 = RXNEMPTY_MASK << SM::SM; |
| 184 | }); | 184 | }); |
| 185 | } | 185 | } |
| 186 | } | 186 | } |
| @@ -277,15 +277,14 @@ impl<PIO: PioInstance> PioPin<PIO> { | |||
| 277 | #[inline] | 277 | #[inline] |
| 278 | pub fn set_pull(&mut self, pull: Pull) { | 278 | pub fn set_pull(&mut self, pull: Pull) { |
| 279 | unsafe { | 279 | unsafe { |
| 280 | self.pad_ctrl().modify(|w| match pull { | 280 | self.pad_ctrl().modify(|w| { |
| 281 | Pull::Up => w.set_pue(true), | 281 | w.set_pue(pull == Pull::Up); |
| 282 | Pull::Down => w.set_pde(true), | 282 | w.set_pde(pull == Pull::Down); |
| 283 | Pull::None => {} | ||
| 284 | }); | 283 | }); |
| 285 | } | 284 | } |
| 286 | } | 285 | } |
| 287 | 286 | ||
| 288 | /// Set the pin's pull. | 287 | /// Set the pin's schmitt trigger. |
| 289 | #[inline] | 288 | #[inline] |
| 290 | pub fn set_schmitt(&mut self, enable: bool) { | 289 | pub fn set_schmitt(&mut self, enable: bool) { |
| 291 | unsafe { | 290 | unsafe { |
| @@ -298,9 +297,11 @@ impl<PIO: PioInstance> PioPin<PIO> { | |||
| 298 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { | 297 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { |
| 299 | let mask = 1 << self.pin(); | 298 | let mask = 1 << self.pin(); |
| 300 | unsafe { | 299 | unsafe { |
| 301 | PIO::PIO | 300 | if bypass { |
| 302 | .input_sync_bypass() | 301 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); |
| 303 | .modify(|w| *w = if bypass { *w & !mask } else { *w | mask }); | 302 | } else { |
| 303 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); | ||
| 304 | } | ||
| 304 | } | 305 | } |
| 305 | } | 306 | } |
| 306 | 307 | ||
| @@ -315,16 +316,15 @@ impl<PIO: PioInstance> SealedPin for PioPin<PIO> { | |||
| 315 | } | 316 | } |
| 316 | } | 317 | } |
| 317 | 318 | ||
| 318 | pub struct PioStateMachineInstance<PIO: PioInstance, SM: SmInstance> { | 319 | pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> { |
| 319 | pio: PhantomData<PIO>, | 320 | pio: PhantomData<&'d PIO>, |
| 320 | sm: PhantomData<SM>, | ||
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | impl<PIO: PioInstance, SM: SmInstance> sealed::PioStateMachine for PioStateMachineInstance<PIO, SM> { | 323 | impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { |
| 324 | type Pio = PIO; | 324 | type Pio = PIO; |
| 325 | type Sm = SM; | 325 | const SM: usize = SM; |
| 326 | } | 326 | } |
| 327 | impl<PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<PIO, SM> {} | 327 | impl<'d, PIO: PioInstance, const SM: usize> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {} |
| 328 | 328 | ||
| 329 | pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | 329 | pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { |
| 330 | fn pio_no(&self) -> u8 { | 330 | fn pio_no(&self) -> u8 { |
| @@ -332,60 +332,61 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | fn sm_no(&self) -> u8 { | 334 | fn sm_no(&self) -> u8 { |
| 335 | Self::Sm::SM_NO | 335 | Self::SM as u8 |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | fn restart(&mut self) { | 338 | fn restart(&mut self) { |
| 339 | let mask = 1u8 << Self::SM; | ||
| 339 | unsafe { | 340 | unsafe { |
| 340 | Self::Pio::PIO | 341 | Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); |
| 341 | .ctrl() | ||
| 342 | .modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO)); | ||
| 343 | } | 342 | } |
| 344 | } | 343 | } |
| 345 | fn set_enable(&mut self, enable: bool) { | 344 | fn set_enable(&mut self, enable: bool) { |
| 346 | let mask = 1u8 << Self::Sm::SM_NO; | 345 | let mask = 1u8 << Self::SM; |
| 347 | unsafe { | 346 | unsafe { |
| 348 | Self::Pio::PIO | 347 | if enable { |
| 349 | .ctrl() | 348 | Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); |
| 350 | .modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); | 349 | } else { |
| 350 | Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); | ||
| 351 | } | ||
| 351 | } | 352 | } |
| 352 | } | 353 | } |
| 353 | 354 | ||
| 354 | fn is_enabled(&self) -> bool { | 355 | fn is_enabled(&self) -> bool { |
| 355 | unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } | 356 | unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::SM) != 0 } |
| 356 | } | 357 | } |
| 357 | 358 | ||
| 358 | fn is_tx_empty(&self) -> bool { | 359 | fn is_tx_empty(&self) -> bool { |
| 359 | unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } | 360 | unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::SM) != 0 } |
| 360 | } | 361 | } |
| 361 | fn is_tx_full(&self) -> bool { | 362 | fn is_tx_full(&self) -> bool { |
| 362 | unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 } | 363 | unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::SM) != 0 } |
| 363 | } | 364 | } |
| 364 | 365 | ||
| 365 | fn is_rx_empty(&self) -> bool { | 366 | fn is_rx_empty(&self) -> bool { |
| 366 | unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 } | 367 | unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::SM) != 0 } |
| 367 | } | 368 | } |
| 368 | fn is_rx_full(&self) -> bool { | 369 | fn is_rx_full(&self) -> bool { |
| 369 | unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 } | 370 | unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::SM) != 0 } |
| 370 | } | 371 | } |
| 371 | 372 | ||
| 372 | fn tx_level(&self) -> u8 { | 373 | fn tx_level(&self) -> u8 { |
| 373 | unsafe { | 374 | unsafe { |
| 374 | let flevel = Self::Pio::PIO.flevel().read().0; | 375 | let flevel = Self::Pio::PIO.flevel().read().0; |
| 375 | (flevel >> (Self::Sm::SM_NO * 8)) as u8 & 0x0f | 376 | (flevel >> (Self::SM * 8)) as u8 & 0x0f |
| 376 | } | 377 | } |
| 377 | } | 378 | } |
| 378 | 379 | ||
| 379 | fn rx_level(&self) -> u8 { | 380 | fn rx_level(&self) -> u8 { |
| 380 | unsafe { | 381 | unsafe { |
| 381 | let flevel = Self::Pio::PIO.flevel().read().0; | 382 | let flevel = Self::Pio::PIO.flevel().read().0; |
| 382 | (flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f | 383 | (flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f |
| 383 | } | 384 | } |
| 384 | } | 385 | } |
| 385 | 386 | ||
| 386 | fn push_tx(&mut self, v: u32) { | 387 | fn push_tx(&mut self, v: u32) { |
| 387 | unsafe { | 388 | unsafe { |
| 388 | Self::Pio::PIO.txf(Self::Sm::SM_NO as usize).write_value(v); | 389 | Self::Pio::PIO.txf(Self::SM).write_value(v); |
| 389 | } | 390 | } |
| 390 | } | 391 | } |
| 391 | 392 | ||
| @@ -398,7 +399,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 398 | } | 399 | } |
| 399 | 400 | ||
| 400 | fn pull_rx(&mut self) -> u32 { | 401 | fn pull_rx(&mut self) -> u32 { |
| 401 | unsafe { Self::Pio::PIO.rxf(Self::Sm::SM_NO as usize).read() } | 402 | unsafe { Self::Pio::PIO.rxf(Self::SM).read() } |
| 402 | } | 403 | } |
| 403 | 404 | ||
| 404 | fn try_pull_rx(&mut self) -> Option<u32> { | 405 | fn try_pull_rx(&mut self) -> Option<u32> { |
| @@ -410,73 +411,54 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 410 | 411 | ||
| 411 | fn set_clkdiv(&mut self, div_x_256: u32) { | 412 | fn set_clkdiv(&mut self, div_x_256: u32) { |
| 412 | unsafe { | 413 | unsafe { |
| 413 | Self::Pio::PIO | 414 | Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); |
| 414 | .sm(Self::Sm::SM_NO as usize) | ||
| 415 | .clkdiv() | ||
| 416 | .write(|w| w.0 = div_x_256 << 8); | ||
| 417 | } | 415 | } |
| 418 | } | 416 | } |
| 419 | 417 | ||
| 420 | fn get_clkdiv(&self) -> u32 { | 418 | fn get_clkdiv(&self) -> u32 { |
| 421 | unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).clkdiv().read().0 >> 8 } | 419 | unsafe { Self::this_sm().clkdiv().read().0 >> 8 } |
| 422 | } | 420 | } |
| 423 | 421 | ||
| 424 | fn clkdiv_restart(&mut self) { | 422 | fn clkdiv_restart(&mut self) { |
| 423 | let mask = 1u8 << Self::SM; | ||
| 425 | unsafe { | 424 | unsafe { |
| 426 | Self::Pio::PIO | 425 | Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); |
| 427 | .ctrl() | ||
| 428 | .modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO)); | ||
| 429 | } | 426 | } |
| 430 | } | 427 | } |
| 431 | 428 | ||
| 432 | fn set_side_enable(&self, enable: bool) { | 429 | fn set_side_enable(&self, enable: bool) { |
| 433 | unsafe { | 430 | unsafe { |
| 434 | Self::Pio::PIO | 431 | Self::this_sm().execctrl().modify(|w| w.set_side_en(enable)); |
| 435 | .sm(Self::Sm::SM_NO as usize) | ||
| 436 | .execctrl() | ||
| 437 | .modify(|w| w.set_side_en(enable)); | ||
| 438 | } | 432 | } |
| 439 | } | 433 | } |
| 440 | 434 | ||
| 441 | fn is_side_enabled(&self) -> bool { | 435 | fn is_side_enabled(&self) -> bool { |
| 442 | unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().side_en() } | 436 | unsafe { Self::this_sm().execctrl().read().side_en() } |
| 443 | } | 437 | } |
| 444 | 438 | ||
| 445 | fn set_side_pindir(&mut self, pindir: bool) { | 439 | fn set_side_pindir(&mut self, pindir: bool) { |
| 446 | unsafe { | 440 | unsafe { |
| 447 | Self::Pio::PIO | 441 | Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir)); |
| 448 | .sm(Self::Sm::SM_NO as usize) | ||
| 449 | .execctrl() | ||
| 450 | .modify(|w| w.set_side_pindir(pindir)); | ||
| 451 | } | 442 | } |
| 452 | } | 443 | } |
| 453 | 444 | ||
| 454 | fn is_side_pindir(&self) -> bool { | 445 | fn is_side_pindir(&self) -> bool { |
| 455 | unsafe { | 446 | unsafe { Self::this_sm().execctrl().read().side_pindir() } |
| 456 | Self::Pio::PIO | ||
| 457 | .sm(Self::Sm::SM_NO as usize) | ||
| 458 | .execctrl() | ||
| 459 | .read() | ||
| 460 | .side_pindir() | ||
| 461 | } | ||
| 462 | } | 447 | } |
| 463 | 448 | ||
| 464 | fn set_jmp_pin(&mut self, pin: u8) { | 449 | fn set_jmp_pin(&mut self, pin: u8) { |
| 465 | unsafe { | 450 | unsafe { |
| 466 | Self::Pio::PIO | 451 | Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); |
| 467 | .sm(Self::Sm::SM_NO as usize) | ||
| 468 | .execctrl() | ||
| 469 | .modify(|w| w.set_jmp_pin(pin)); | ||
| 470 | } | 452 | } |
| 471 | } | 453 | } |
| 472 | 454 | ||
| 473 | fn get_jmp_pin(&mut self) -> u8 { | 455 | fn get_jmp_pin(&mut self) -> u8 { |
| 474 | unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().jmp_pin() } | 456 | unsafe { Self::this_sm().execctrl().read().jmp_pin() } |
| 475 | } | 457 | } |
| 476 | 458 | ||
| 477 | fn set_wrap(&self, source: u8, target: u8) { | 459 | fn set_wrap(&self, source: u8, target: u8) { |
| 478 | unsafe { | 460 | unsafe { |
| 479 | Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().modify(|w| { | 461 | Self::this_sm().execctrl().modify(|w| { |
| 480 | w.set_wrap_top(source); | 462 | w.set_wrap_top(source); |
| 481 | w.set_wrap_bottom(target) | 463 | w.set_wrap_bottom(target) |
| 482 | }); | 464 | }); |
| @@ -486,7 +468,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 486 | /// Get wrapping addresses. Returns (source, target). | 468 | /// Get wrapping addresses. Returns (source, target). |
| 487 | fn get_wrap(&self) -> (u8, u8) { | 469 | fn get_wrap(&self) -> (u8, u8) { |
| 488 | unsafe { | 470 | unsafe { |
| 489 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read(); | 471 | let r = Self::this_sm().execctrl().read(); |
| 490 | (r.wrap_top(), r.wrap_bottom()) | 472 | (r.wrap_top(), r.wrap_bottom()) |
| 491 | } | 473 | } |
| 492 | } | 474 | } |
| @@ -498,7 +480,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 498 | FifoJoin::TxOnly => (false, true), | 480 | FifoJoin::TxOnly => (false, true), |
| 499 | }; | 481 | }; |
| 500 | unsafe { | 482 | unsafe { |
| 501 | Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().modify(|w| { | 483 | Self::this_sm().shiftctrl().modify(|w| { |
| 502 | w.set_fjoin_rx(rx); | 484 | w.set_fjoin_rx(rx); |
| 503 | w.set_fjoin_tx(tx) | 485 | w.set_fjoin_tx(tx) |
| 504 | }); | 486 | }); |
| @@ -506,7 +488,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 506 | } | 488 | } |
| 507 | fn get_fifo_join(&self) -> FifoJoin { | 489 | fn get_fifo_join(&self) -> FifoJoin { |
| 508 | unsafe { | 490 | unsafe { |
| 509 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); | 491 | let r = Self::this_sm().shiftctrl().read(); |
| 510 | // Ignores the invalid state when both bits are set | 492 | // Ignores the invalid state when both bits are set |
| 511 | if r.fjoin_rx() { | 493 | if r.fjoin_rx() { |
| 512 | FifoJoin::RxOnly | 494 | FifoJoin::RxOnly |
| @@ -521,7 +503,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 521 | fn clear_fifos(&mut self) { | 503 | fn clear_fifos(&mut self) { |
| 522 | // Toggle FJOIN_RX to flush FIFOs | 504 | // Toggle FJOIN_RX to flush FIFOs |
| 523 | unsafe { | 505 | unsafe { |
| 524 | let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl(); | 506 | let shiftctrl = Self::this_sm().shiftctrl(); |
| 525 | shiftctrl.modify(|w| { | 507 | shiftctrl.modify(|w| { |
| 526 | w.set_fjoin_rx(!w.fjoin_rx()); | 508 | w.set_fjoin_rx(!w.fjoin_rx()); |
| 527 | }); | 509 | }); |
| @@ -533,51 +515,33 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 533 | 515 | ||
| 534 | fn set_pull_threshold(&mut self, threshold: u8) { | 516 | fn set_pull_threshold(&mut self, threshold: u8) { |
| 535 | unsafe { | 517 | unsafe { |
| 536 | Self::Pio::PIO | 518 | Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold)); |
| 537 | .sm(Self::Sm::SM_NO as usize) | ||
| 538 | .shiftctrl() | ||
| 539 | .modify(|w| w.set_pull_thresh(threshold)); | ||
| 540 | } | 519 | } |
| 541 | } | 520 | } |
| 542 | 521 | ||
| 543 | fn get_pull_threshold(&self) -> u8 { | 522 | fn get_pull_threshold(&self) -> u8 { |
| 544 | unsafe { | 523 | unsafe { Self::this_sm().shiftctrl().read().pull_thresh() } |
| 545 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); | ||
| 546 | r.pull_thresh() | ||
| 547 | } | ||
| 548 | } | 524 | } |
| 549 | fn set_push_threshold(&mut self, threshold: u8) { | 525 | fn set_push_threshold(&mut self, threshold: u8) { |
| 550 | unsafe { | 526 | unsafe { |
| 551 | Self::Pio::PIO | 527 | Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold)); |
| 552 | .sm(Self::Sm::SM_NO as usize) | ||
| 553 | .shiftctrl() | ||
| 554 | .modify(|w| w.set_push_thresh(threshold)); | ||
| 555 | } | 528 | } |
| 556 | } | 529 | } |
| 557 | 530 | ||
| 558 | fn get_push_threshold(&self) -> u8 { | 531 | fn get_push_threshold(&self) -> u8 { |
| 559 | unsafe { | 532 | unsafe { Self::this_sm().shiftctrl().read().push_thresh() } |
| 560 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); | ||
| 561 | r.push_thresh() | ||
| 562 | } | ||
| 563 | } | 533 | } |
| 564 | 534 | ||
| 565 | fn set_out_shift_dir(&mut self, dir: ShiftDirection) { | 535 | fn set_out_shift_dir(&mut self, dir: ShiftDirection) { |
| 566 | unsafe { | 536 | unsafe { |
| 567 | Self::Pio::PIO | 537 | Self::this_sm() |
| 568 | .sm(Self::Sm::SM_NO as usize) | ||
| 569 | .shiftctrl() | 538 | .shiftctrl() |
| 570 | .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); | 539 | .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); |
| 571 | } | 540 | } |
| 572 | } | 541 | } |
| 573 | fn get_out_shiftdir(&self) -> ShiftDirection { | 542 | fn get_out_shiftdir(&self) -> ShiftDirection { |
| 574 | unsafe { | 543 | unsafe { |
| 575 | if Self::Pio::PIO | 544 | if Self::this_sm().shiftctrl().read().out_shiftdir() { |
| 576 | .sm(Self::Sm::SM_NO as usize) | ||
| 577 | .shiftctrl() | ||
| 578 | .read() | ||
| 579 | .out_shiftdir() | ||
| 580 | { | ||
| 581 | ShiftDirection::Right | 545 | ShiftDirection::Right |
| 582 | } else { | 546 | } else { |
| 583 | ShiftDirection::Left | 547 | ShiftDirection::Left |
| @@ -587,20 +551,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 587 | 551 | ||
| 588 | fn set_in_shift_dir(&mut self, dir: ShiftDirection) { | 552 | fn set_in_shift_dir(&mut self, dir: ShiftDirection) { |
| 589 | unsafe { | 553 | unsafe { |
| 590 | Self::Pio::PIO | 554 | Self::this_sm() |
| 591 | .sm(Self::Sm::SM_NO as usize) | ||
| 592 | .shiftctrl() | 555 | .shiftctrl() |
| 593 | .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); | 556 | .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); |
| 594 | } | 557 | } |
| 595 | } | 558 | } |
| 596 | fn get_in_shiftdir(&self) -> ShiftDirection { | 559 | fn get_in_shiftdir(&self) -> ShiftDirection { |
| 597 | unsafe { | 560 | unsafe { |
| 598 | if Self::Pio::PIO | 561 | if Self::this_sm().shiftctrl().read().in_shiftdir() { |
| 599 | .sm(Self::Sm::SM_NO as usize) | ||
| 600 | .shiftctrl() | ||
| 601 | .read() | ||
| 602 | .in_shiftdir() | ||
| 603 | { | ||
| 604 | ShiftDirection::Right | 562 | ShiftDirection::Right |
| 605 | } else { | 563 | } else { |
| 606 | ShiftDirection::Left | 564 | ShiftDirection::Left |
| @@ -610,76 +568,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 610 | 568 | ||
| 611 | fn set_autopull(&mut self, auto: bool) { | 569 | fn set_autopull(&mut self, auto: bool) { |
| 612 | unsafe { | 570 | unsafe { |
| 613 | Self::Pio::PIO | 571 | Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto)); |
| 614 | .sm(Self::Sm::SM_NO as usize) | ||
| 615 | .shiftctrl() | ||
| 616 | .modify(|w| w.set_autopull(auto)); | ||
| 617 | } | 572 | } |
| 618 | } | 573 | } |
| 619 | 574 | ||
| 620 | fn is_autopull(&self) -> bool { | 575 | fn is_autopull(&self) -> bool { |
| 621 | unsafe { | 576 | unsafe { Self::this_sm().shiftctrl().read().autopull() } |
| 622 | Self::Pio::PIO | ||
| 623 | .sm(Self::Sm::SM_NO as usize) | ||
| 624 | .shiftctrl() | ||
| 625 | .read() | ||
| 626 | .autopull() | ||
| 627 | } | ||
| 628 | } | 577 | } |
| 629 | 578 | ||
| 630 | fn set_autopush(&mut self, auto: bool) { | 579 | fn set_autopush(&mut self, auto: bool) { |
| 631 | unsafe { | 580 | unsafe { |
| 632 | Self::Pio::PIO | 581 | Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto)); |
| 633 | .sm(Self::Sm::SM_NO as usize) | ||
| 634 | .shiftctrl() | ||
| 635 | .modify(|w| w.set_autopush(auto)); | ||
| 636 | } | 582 | } |
| 637 | } | 583 | } |
| 638 | 584 | ||
| 639 | fn is_autopush(&self) -> bool { | 585 | fn is_autopush(&self) -> bool { |
| 640 | unsafe { | 586 | unsafe { Self::this_sm().shiftctrl().read().autopush() } |
| 641 | Self::Pio::PIO | ||
| 642 | .sm(Self::Sm::SM_NO as usize) | ||
| 643 | .shiftctrl() | ||
| 644 | .read() | ||
| 645 | .autopush() | ||
| 646 | } | ||
| 647 | } | 587 | } |
| 648 | 588 | ||
| 649 | fn get_addr(&self) -> u8 { | 589 | fn get_addr(&self) -> u8 { |
| 650 | unsafe { | 590 | unsafe { Self::this_sm().addr().read().addr() } |
| 651 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read(); | ||
| 652 | r.addr() | ||
| 653 | } | ||
| 654 | } | 591 | } |
| 655 | fn set_sideset_count(&mut self, count: u8) { | 592 | fn set_sideset_count(&mut self, count: u8) { |
| 656 | unsafe { | 593 | unsafe { |
| 657 | Self::Pio::PIO | 594 | Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count)); |
| 658 | .sm(Self::Sm::SM_NO as usize) | ||
| 659 | .pinctrl() | ||
| 660 | .modify(|w| w.set_sideset_count(count)); | ||
| 661 | } | 595 | } |
| 662 | } | 596 | } |
| 663 | 597 | ||
| 664 | fn get_sideset_count(&self) -> u8 { | 598 | fn get_sideset_count(&self) -> u8 { |
| 665 | unsafe { | 599 | unsafe { Self::this_sm().pinctrl().read().sideset_count() } |
| 666 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); | ||
| 667 | r.sideset_count() | ||
| 668 | } | ||
| 669 | } | 600 | } |
| 670 | 601 | ||
| 671 | fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) { | 602 | fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) { |
| 672 | unsafe { | 603 | unsafe { |
| 673 | Self::Pio::PIO | 604 | Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin())); |
| 674 | .sm(Self::Sm::SM_NO as usize) | ||
| 675 | .pinctrl() | ||
| 676 | .modify(|w| w.set_sideset_base(base_pin.pin())); | ||
| 677 | } | 605 | } |
| 678 | } | 606 | } |
| 679 | 607 | ||
| 680 | fn get_sideset_base(&self) -> u8 { | 608 | fn get_sideset_base(&self) -> u8 { |
| 681 | unsafe { | 609 | unsafe { |
| 682 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); | 610 | let r = Self::this_sm().pinctrl().read(); |
| 683 | r.sideset_base() | 611 | r.sideset_base() |
| 684 | } | 612 | } |
| 685 | } | 613 | } |
| @@ -688,7 +616,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 688 | fn set_set_range(&mut self, base: u8, count: u8) { | 616 | fn set_set_range(&mut self, base: u8, count: u8) { |
| 689 | assert!(base + count < 32); | 617 | assert!(base + count < 32); |
| 690 | unsafe { | 618 | unsafe { |
| 691 | Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { | 619 | Self::this_sm().pinctrl().modify(|w| { |
| 692 | w.set_set_base(base); | 620 | w.set_set_base(base); |
| 693 | w.set_set_count(count) | 621 | w.set_set_count(count) |
| 694 | }); | 622 | }); |
| @@ -698,23 +626,20 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 698 | /// Get the range of out pins affected by a set instruction. Returns (base, count). | 626 | /// Get the range of out pins affected by a set instruction. Returns (base, count). |
| 699 | fn get_set_range(&self) -> (u8, u8) { | 627 | fn get_set_range(&self) -> (u8, u8) { |
| 700 | unsafe { | 628 | unsafe { |
| 701 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); | 629 | let r = Self::this_sm().pinctrl().read(); |
| 702 | (r.set_base(), r.set_count()) | 630 | (r.set_base(), r.set_count()) |
| 703 | } | 631 | } |
| 704 | } | 632 | } |
| 705 | 633 | ||
| 706 | fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) { | 634 | fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) { |
| 707 | unsafe { | 635 | unsafe { |
| 708 | Self::Pio::PIO | 636 | Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin())); |
| 709 | .sm(Self::Sm::SM_NO as usize) | ||
| 710 | .pinctrl() | ||
| 711 | .modify(|w| w.set_in_base(base.pin())); | ||
| 712 | } | 637 | } |
| 713 | } | 638 | } |
| 714 | 639 | ||
| 715 | fn get_in_base(&self) -> u8 { | 640 | fn get_in_base(&self) -> u8 { |
| 716 | unsafe { | 641 | unsafe { |
| 717 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); | 642 | let r = Self::this_sm().pinctrl().read(); |
| 718 | r.in_base() | 643 | r.in_base() |
| 719 | } | 644 | } |
| 720 | } | 645 | } |
| @@ -722,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 722 | fn set_out_range(&mut self, base: u8, count: u8) { | 647 | fn set_out_range(&mut self, base: u8, count: u8) { |
| 723 | assert!(base + count < 32); | 648 | assert!(base + count < 32); |
| 724 | unsafe { | 649 | unsafe { |
| 725 | Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { | 650 | Self::this_sm().pinctrl().modify(|w| { |
| 726 | w.set_out_base(base); | 651 | w.set_out_base(base); |
| 727 | w.set_out_count(count) | 652 | w.set_out_count(count) |
| 728 | }); | 653 | }); |
| @@ -732,7 +657,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 732 | /// Get the range of out pins affected by a set instruction. Returns (base, count). | 657 | /// Get the range of out pins affected by a set instruction. Returns (base, count). |
| 733 | fn get_out_range(&self) -> (u8, u8) { | 658 | fn get_out_range(&self) -> (u8, u8) { |
| 734 | unsafe { | 659 | unsafe { |
| 735 | let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); | 660 | let r = Self::this_sm().pinctrl().read(); |
| 736 | (r.out_base(), r.out_count()) | 661 | (r.out_base(), r.out_count()) |
| 737 | } | 662 | } |
| 738 | } | 663 | } |
| @@ -760,15 +685,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 760 | } | 685 | } |
| 761 | 686 | ||
| 762 | fn get_current_instr() -> u32 { | 687 | fn get_current_instr() -> u32 { |
| 763 | unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).instr().read().0 } | 688 | unsafe { Self::this_sm().instr().read().0 } |
| 764 | } | 689 | } |
| 765 | 690 | ||
| 766 | fn exec_instr(&mut self, instr: u16) { | 691 | fn exec_instr(&mut self, instr: u16) { |
| 767 | unsafe { | 692 | unsafe { |
| 768 | Self::Pio::PIO | 693 | Self::this_sm().instr().write(|w| w.set_instr(instr)); |
| 769 | .sm(Self::Sm::SM_NO as usize) | ||
| 770 | .instr() | ||
| 771 | .write(|w| w.set_instr(instr)); | ||
| 772 | } | 694 | } |
| 773 | } | 695 | } |
| 774 | 696 | ||
| @@ -787,8 +709,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 787 | fn has_tx_stalled(&self) -> bool { | 709 | fn has_tx_stalled(&self) -> bool { |
| 788 | unsafe { | 710 | unsafe { |
| 789 | let fdebug = Self::Pio::PIO.fdebug(); | 711 | let fdebug = Self::Pio::PIO.fdebug(); |
| 790 | let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0; | 712 | let ret = fdebug.read().txstall() & (1 << Self::SM) != 0; |
| 791 | fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO)); | 713 | fdebug.write(|w| w.set_txstall(1 << Self::SM)); |
| 792 | ret | 714 | ret |
| 793 | } | 715 | } |
| 794 | } | 716 | } |
| @@ -796,8 +718,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 796 | fn has_tx_overflowed(&self) -> bool { | 718 | fn has_tx_overflowed(&self) -> bool { |
| 797 | unsafe { | 719 | unsafe { |
| 798 | let fdebug = Self::Pio::PIO.fdebug(); | 720 | let fdebug = Self::Pio::PIO.fdebug(); |
| 799 | let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0; | 721 | let ret = fdebug.read().txover() & (1 << Self::SM) != 0; |
| 800 | fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO)); | 722 | fdebug.write(|w| w.set_txover(1 << Self::SM)); |
| 801 | ret | 723 | ret |
| 802 | } | 724 | } |
| 803 | } | 725 | } |
| @@ -805,8 +727,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 805 | fn has_rx_stalled(&self) -> bool { | 727 | fn has_rx_stalled(&self) -> bool { |
| 806 | unsafe { | 728 | unsafe { |
| 807 | let fdebug = Self::Pio::PIO.fdebug(); | 729 | let fdebug = Self::Pio::PIO.fdebug(); |
| 808 | let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0; | 730 | let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0; |
| 809 | fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO)); | 731 | fdebug.write(|w| w.set_rxstall(1 << Self::SM)); |
| 810 | ret | 732 | ret |
| 811 | } | 733 | } |
| 812 | } | 734 | } |
| @@ -814,25 +736,25 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 814 | fn has_rx_underflowed(&self) -> bool { | 736 | fn has_rx_underflowed(&self) -> bool { |
| 815 | unsafe { | 737 | unsafe { |
| 816 | let fdebug = Self::Pio::PIO.fdebug(); | 738 | let fdebug = Self::Pio::PIO.fdebug(); |
| 817 | let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0; | 739 | let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0; |
| 818 | fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO)); | 740 | fdebug.write(|w| w.set_rxunder(1 << Self::SM)); |
| 819 | ret | 741 | ret |
| 820 | } | 742 | } |
| 821 | } | 743 | } |
| 822 | 744 | ||
| 823 | fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> { | 745 | fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { |
| 824 | unsafe { | 746 | unsafe { |
| 825 | let pio_no = Self::Pio::PIO_NO; | 747 | let pio_no = Self::Pio::PIO_NO; |
| 826 | let sm_no = Self::Sm::SM_NO; | 748 | let sm_no = Self::SM; |
| 827 | let p = ch.regs(); | 749 | let p = ch.regs(); |
| 828 | p.read_addr().write_value(data.as_ptr() as u32); | 750 | p.read_addr().write_value(data.as_ptr() as u32); |
| 829 | p.write_addr() | 751 | p.write_addr().write_value(Self::Pio::PIO.txf(sm_no).ptr() as u32); |
| 830 | .write_value(Self::Pio::PIO.txf(sm_no as usize).ptr() as u32); | ||
| 831 | p.trans_count().write_value(data.len() as u32); | 752 | p.trans_count().write_value(data.len() as u32); |
| 753 | compiler_fence(Ordering::SeqCst); | ||
| 832 | p.ctrl_trig().write(|w| { | 754 | p.ctrl_trig().write(|w| { |
| 833 | // Set TX DREQ for this statemachine | 755 | // Set TX DREQ for this statemachine |
| 834 | w.set_treq_sel(TreqSel(pio_no * 8 + sm_no)); | 756 | w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8)); |
| 835 | w.set_data_size(DataSize::SIZE_WORD); | 757 | w.set_data_size(W::size()); |
| 836 | w.set_chain_to(ch.number()); | 758 | w.set_chain_to(ch.number()); |
| 837 | w.set_incr_read(true); | 759 | w.set_incr_read(true); |
| 838 | w.set_incr_write(false); | 760 | w.set_incr_write(false); |
| @@ -843,19 +765,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 843 | Transfer::new(ch) | 765 | Transfer::new(ch) |
| 844 | } | 766 | } |
| 845 | 767 | ||
| 846 | fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> { | 768 | fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> { |
| 847 | unsafe { | 769 | unsafe { |
| 848 | let pio_no = Self::Pio::PIO_NO; | 770 | let pio_no = Self::Pio::PIO_NO; |
| 849 | let sm_no = Self::Sm::SM_NO; | 771 | let sm_no = Self::SM; |
| 850 | let p = ch.regs(); | 772 | let p = ch.regs(); |
| 851 | p.write_addr().write_value(data.as_ptr() as u32); | 773 | p.write_addr().write_value(data.as_ptr() as u32); |
| 852 | p.read_addr() | 774 | p.read_addr().write_value(Self::Pio::PIO.rxf(sm_no).ptr() as u32); |
| 853 | .write_value(Self::Pio::PIO.rxf(sm_no as usize).ptr() as u32); | ||
| 854 | p.trans_count().write_value(data.len() as u32); | 775 | p.trans_count().write_value(data.len() as u32); |
| 776 | compiler_fence(Ordering::SeqCst); | ||
| 855 | p.ctrl_trig().write(|w| { | 777 | p.ctrl_trig().write(|w| { |
| 856 | // Set TX DREQ for this statemachine | 778 | // Set RX DREQ for this statemachine |
| 857 | w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4)); | 779 | w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8 + 4)); |
| 858 | w.set_data_size(DataSize::SIZE_WORD); | 780 | w.set_data_size(W::size()); |
| 859 | w.set_chain_to(ch.number()); | 781 | w.set_chain_to(ch.number()); |
| 860 | w.set_incr_read(false); | 782 | w.set_incr_read(false); |
| 861 | w.set_incr_write(true); | 783 | w.set_incr_write(true); |
| @@ -867,21 +789,18 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { | |||
| 867 | } | 789 | } |
| 868 | } | 790 | } |
| 869 | 791 | ||
| 870 | pub struct PioCommonInstance<PIO: PioInstance> { | 792 | pub struct PioCommon<'d, PIO: PioInstance> { |
| 871 | instructions_used: u32, | 793 | instructions_used: u32, |
| 872 | pio: PhantomData<PIO>, | 794 | pio: PhantomData<&'d PIO>, |
| 873 | } | 795 | } |
| 874 | 796 | ||
| 875 | pub struct PioInstanceMemory<PIO: PioInstance> { | 797 | pub struct PioInstanceMemory<'d, PIO: PioInstance> { |
| 876 | used_mask: u32, | 798 | used_mask: u32, |
| 877 | pio: PhantomData<PIO>, | 799 | pio: PhantomData<&'d PIO>, |
| 878 | } | 800 | } |
| 879 | 801 | ||
| 880 | impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> { | 802 | impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { |
| 881 | type Pio = PIO; | 803 | pub fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO> |
| 882 | } | ||
| 883 | impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> { | ||
| 884 | fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio> | ||
| 885 | where | 804 | where |
| 886 | I: Iterator<Item = u16>, | 805 | I: Iterator<Item = u16>, |
| 887 | { | 806 | { |
| @@ -908,66 +827,50 @@ impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> { | |||
| 908 | } | 827 | } |
| 909 | } | 828 | } |
| 910 | 829 | ||
| 911 | fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>) { | 830 | // TODO make instruction memory that is currently in use unfreeable |
| 831 | pub fn free_instr(&mut self, instrs: PioInstanceMemory<PIO>) { | ||
| 912 | self.instructions_used &= !instrs.used_mask; | 832 | self.instructions_used &= !instrs.used_mask; |
| 913 | } | 833 | } |
| 914 | } | ||
| 915 | |||
| 916 | pub trait PioCommon: sealed::PioCommon + Sized { | ||
| 917 | fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio> | ||
| 918 | where | ||
| 919 | I: Iterator<Item = u16>; | ||
| 920 | 834 | ||
| 921 | // TODO make instruction memory that is currently in use unfreeable | 835 | pub fn is_irq_set(&self, irq_no: u8) -> bool { |
| 922 | fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>); | ||
| 923 | |||
| 924 | fn is_irq_set(&self, irq_no: u8) -> bool { | ||
| 925 | assert!(irq_no < 8); | 836 | assert!(irq_no < 8); |
| 926 | unsafe { | 837 | unsafe { |
| 927 | let irq_flags = Self::Pio::PIO.irq(); | 838 | let irq_flags = PIO::PIO.irq(); |
| 928 | irq_flags.read().0 & (1 << irq_no) != 0 | 839 | irq_flags.read().0 & (1 << irq_no) != 0 |
| 929 | } | 840 | } |
| 930 | } | 841 | } |
| 931 | 842 | ||
| 932 | fn clear_irq(&mut self, irq_no: usize) { | 843 | pub fn clear_irq(&mut self, irq_no: usize) { |
| 933 | assert!(irq_no < 8); | 844 | assert!(irq_no < 8); |
| 934 | unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } | 845 | unsafe { PIO::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } |
| 935 | } | 846 | } |
| 936 | 847 | ||
| 937 | fn clear_irqs(&mut self, mask: u8) { | 848 | pub fn clear_irqs(&mut self, mask: u8) { |
| 938 | unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) } | 849 | unsafe { PIO::PIO.irq().write(|w| w.set_irq(mask)) } |
| 939 | } | 850 | } |
| 940 | 851 | ||
| 941 | fn force_irq(&mut self, irq_no: usize) { | 852 | pub fn force_irq(&mut self, irq_no: usize) { |
| 942 | assert!(irq_no < 8); | 853 | assert!(irq_no < 8); |
| 943 | unsafe { Self::Pio::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } | 854 | unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } |
| 944 | } | 855 | } |
| 945 | 856 | ||
| 946 | fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { | 857 | pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { |
| 947 | unsafe { | 858 | unsafe { |
| 948 | Self::Pio::PIO | 859 | // this can interfere with per-pin bypass functions. splitting the |
| 949 | .input_sync_bypass() | 860 | // modification is going to be fine since nothing that relies on |
| 950 | .modify(|w| *w = (*w & !mask) | (bypass & mask)); | 861 | // it can reasonably run before we finish. |
| 862 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); | ||
| 863 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); | ||
| 951 | } | 864 | } |
| 952 | } | 865 | } |
| 953 | 866 | ||
| 954 | fn get_input_sync_bypass(&self) -> u32 { | 867 | pub fn get_input_sync_bypass(&self) -> u32 { |
| 955 | unsafe { Self::Pio::PIO.input_sync_bypass().read() } | 868 | unsafe { PIO::PIO.input_sync_bypass().read() } |
| 956 | } | 869 | } |
| 957 | 870 | ||
| 958 | fn make_pio_pin(&self, pin: impl Pin) -> PioPin<Self::Pio> { | 871 | pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin<PIO> { |
| 959 | unsafe { | 872 | unsafe { |
| 960 | pin.io().ctrl().write(|w| { | 873 | pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); |
| 961 | w.set_funcsel( | ||
| 962 | if Self::Pio::PIO_NO == 1 { | ||
| 963 | pac::io::vals::Gpio0ctrlFuncsel::PIO1_0 | ||
| 964 | } else { | ||
| 965 | // PIO == 0 | ||
| 966 | pac::io::vals::Gpio0ctrlFuncsel::PIO0_0 | ||
| 967 | } | ||
| 968 | .0, | ||
| 969 | ); | ||
| 970 | }); | ||
| 971 | } | 874 | } |
| 972 | PioPin { | 875 | PioPin { |
| 973 | pin_bank: pin.pin_bank(), | 876 | pin_bank: pin.pin_bank(), |
| @@ -976,112 +879,63 @@ pub trait PioCommon: sealed::PioCommon + Sized { | |||
| 976 | } | 879 | } |
| 977 | } | 880 | } |
| 978 | 881 | ||
| 979 | // Identifies a specific state machine inside a PIO device | 882 | pub struct Pio<'d, PIO: PioInstance> { |
| 980 | pub struct SmInstanceBase<const SM_NO: u8> {} | 883 | pub common: PioCommon<'d, PIO>, |
| 981 | 884 | pub sm0: PioStateMachineInstance<'d, PIO, 0>, | |
| 982 | pub trait SmInstance: sealed::SmInstance + Unpin {} | 885 | pub sm1: PioStateMachineInstance<'d, PIO, 1>, |
| 983 | 886 | pub sm2: PioStateMachineInstance<'d, PIO, 2>, | |
| 984 | impl<const SM_NO: u8> sealed::SmInstance for SmInstanceBase<SM_NO> { | 887 | pub sm3: PioStateMachineInstance<'d, PIO, 3>, |
| 985 | const SM_NO: u8 = SM_NO; | ||
| 986 | } | 888 | } |
| 987 | impl<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {} | ||
| 988 | |||
| 989 | pub trait PioPeripheral: sealed::PioPeripheral + Sized { | ||
| 990 | fn pio(&self) -> u8 { | ||
| 991 | Self::Pio::PIO_NO | ||
| 992 | } | ||
| 993 | 889 | ||
| 994 | fn split( | 890 | impl<'d, PIO: PioInstance> Pio<'d, PIO> { |
| 995 | self, | 891 | pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self { |
| 996 | ) -> ( | 892 | Self { |
| 997 | PioCommonInstance<Self::Pio>, | 893 | common: PioCommon { |
| 998 | PioStateMachineInstance<Self::Pio, SmInstanceBase<0>>, | ||
| 999 | PioStateMachineInstance<Self::Pio, SmInstanceBase<1>>, | ||
| 1000 | PioStateMachineInstance<Self::Pio, SmInstanceBase<2>>, | ||
| 1001 | PioStateMachineInstance<Self::Pio, SmInstanceBase<3>>, | ||
| 1002 | ) { | ||
| 1003 | ( | ||
| 1004 | PioCommonInstance { | ||
| 1005 | instructions_used: 0, | 894 | instructions_used: 0, |
| 1006 | pio: PhantomData::default(), | 895 | pio: PhantomData, |
| 1007 | }, | 896 | }, |
| 1008 | PioStateMachineInstance { | 897 | sm0: PioStateMachineInstance { pio: PhantomData }, |
| 1009 | sm: PhantomData::default(), | 898 | sm1: PioStateMachineInstance { pio: PhantomData }, |
| 1010 | pio: PhantomData::default(), | 899 | sm2: PioStateMachineInstance { pio: PhantomData }, |
| 1011 | }, | 900 | sm3: PioStateMachineInstance { pio: PhantomData }, |
| 1012 | PioStateMachineInstance { | 901 | } |
| 1013 | sm: PhantomData::default(), | ||
| 1014 | pio: PhantomData::default(), | ||
| 1015 | }, | ||
| 1016 | PioStateMachineInstance { | ||
| 1017 | sm: PhantomData::default(), | ||
| 1018 | pio: PhantomData::default(), | ||
| 1019 | }, | ||
| 1020 | PioStateMachineInstance { | ||
| 1021 | sm: PhantomData::default(), | ||
| 1022 | pio: PhantomData::default(), | ||
| 1023 | }, | ||
| 1024 | ) | ||
| 1025 | } | 902 | } |
| 1026 | } | 903 | } |
| 1027 | 904 | ||
| 1028 | mod sealed { | 905 | pub trait PioInstance: sealed::PioInstance + Sized + Unpin { |
| 1029 | pub trait PioInstance { | 906 | fn pio(&self) -> u8 { |
| 1030 | const PIO_NO: u8; | 907 | Self::PIO_NO |
| 1031 | const PIO: &'static crate::pac::pio::Pio; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | pub trait PioCommon { | ||
| 1035 | type Pio: super::PioInstance; | ||
| 1036 | } | 908 | } |
| 909 | } | ||
| 1037 | 910 | ||
| 911 | mod sealed { | ||
| 1038 | pub trait PioStateMachine { | 912 | pub trait PioStateMachine { |
| 1039 | type Pio: super::PioInstance; | 913 | type Pio: super::PioInstance; |
| 1040 | type Sm: super::SmInstance; | 914 | const SM: usize; |
| 1041 | } | ||
| 1042 | 915 | ||
| 1043 | pub trait SmInstance { | 916 | #[inline(always)] |
| 1044 | const SM_NO: u8; | 917 | fn this_sm() -> crate::pac::pio::StateMachine { |
| 918 | Self::Pio::PIO.sm(Self::SM as usize) | ||
| 919 | } | ||
| 1045 | } | 920 | } |
| 1046 | 921 | ||
| 1047 | pub trait PioPeripheral { | 922 | pub trait PioInstance { |
| 1048 | type Pio: super::PioInstance; | 923 | const PIO_NO: u8; |
| 924 | const PIO: &'static crate::pac::pio::Pio; | ||
| 925 | const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; | ||
| 1049 | } | 926 | } |
| 1050 | } | 927 | } |
| 1051 | 928 | ||
| 1052 | // Identifies a specific PIO device | 929 | macro_rules! impl_pio { |
| 1053 | pub struct PioInstanceBase<const PIO_NO: u8> {} | 930 | ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { |
| 1054 | 931 | impl sealed::PioInstance for peripherals::$name { | |
| 1055 | pub trait PioInstance: sealed::PioInstance + Unpin {} | 932 | const PIO_NO: u8 = $pio; |
| 1056 | 933 | const PIO: &'static pac::pio::Pio = &pac::$pac; | |
| 1057 | impl sealed::PioInstance for PioInstanceBase<0> { | 934 | const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel; |
| 1058 | const PIO_NO: u8 = 0; | ||
| 1059 | const PIO: &'static pac::pio::Pio = &pac::PIO0; | ||
| 1060 | } | ||
| 1061 | impl PioInstance for PioInstanceBase<0> {} | ||
| 1062 | |||
| 1063 | impl sealed::PioInstance for PioInstanceBase<1> { | ||
| 1064 | const PIO_NO: u8 = 1; | ||
| 1065 | const PIO: &'static pac::pio::Pio = &pac::PIO1; | ||
| 1066 | } | ||
| 1067 | impl PioInstance for PioInstanceBase<1> {} | ||
| 1068 | |||
| 1069 | pub type Pio0 = PioInstanceBase<0>; | ||
| 1070 | pub type Pio1 = PioInstanceBase<1>; | ||
| 1071 | |||
| 1072 | pub type Sm0 = SmInstanceBase<0>; | ||
| 1073 | pub type Sm1 = SmInstanceBase<1>; | ||
| 1074 | pub type Sm2 = SmInstanceBase<2>; | ||
| 1075 | pub type Sm3 = SmInstanceBase<3>; | ||
| 1076 | |||
| 1077 | macro_rules! impl_pio_sm { | ||
| 1078 | ($name:ident, $pio:expr) => { | ||
| 1079 | impl sealed::PioPeripheral for peripherals::$name { | ||
| 1080 | type Pio = PioInstanceBase<$pio>; | ||
| 1081 | } | 935 | } |
| 1082 | impl PioPeripheral for peripherals::$name {} | 936 | impl PioInstance for peripherals::$name {} |
| 1083 | }; | 937 | }; |
| 1084 | } | 938 | } |
| 1085 | 939 | ||
| 1086 | impl_pio_sm!(PIO0, 0); | 940 | impl_pio!(PIO0, 0, PIO0, PIO0_0); |
| 1087 | impl_pio_sm!(PIO1, 1); | 941 | impl_pio!(PIO1, 1, PIO1, PIO1_0); |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index ebe32cc66..4084c158a 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -874,7 +874,6 @@ mod sealed { | |||
| 874 | pub trait Instance { | 874 | pub trait Instance { |
| 875 | const TX_DREQ: u8; | 875 | const TX_DREQ: u8; |
| 876 | const RX_DREQ: u8; | 876 | const RX_DREQ: u8; |
| 877 | const ID: usize; | ||
| 878 | 877 | ||
| 879 | type Interrupt: crate::interrupt::Interrupt; | 878 | type Interrupt: crate::interrupt::Interrupt; |
| 880 | 879 | ||
| @@ -909,11 +908,10 @@ impl_mode!(Async); | |||
| 909 | pub trait Instance: sealed::Instance {} | 908 | pub trait Instance: sealed::Instance {} |
| 910 | 909 | ||
| 911 | macro_rules! impl_instance { | 910 | macro_rules! impl_instance { |
| 912 | ($inst:ident, $irq:ident, $id:expr, $tx_dreq:expr, $rx_dreq:expr) => { | 911 | ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { |
| 913 | impl sealed::Instance for peripherals::$inst { | 912 | impl sealed::Instance for peripherals::$inst { |
| 914 | const TX_DREQ: u8 = $tx_dreq; | 913 | const TX_DREQ: u8 = $tx_dreq; |
| 915 | const RX_DREQ: u8 = $rx_dreq; | 914 | const RX_DREQ: u8 = $rx_dreq; |
| 916 | const ID: usize = $id; | ||
| 917 | 915 | ||
| 918 | type Interrupt = crate::interrupt::$irq; | 916 | type Interrupt = crate::interrupt::$irq; |
| 919 | 917 | ||
| @@ -939,8 +937,8 @@ macro_rules! impl_instance { | |||
| 939 | }; | 937 | }; |
| 940 | } | 938 | } |
| 941 | 939 | ||
| 942 | impl_instance!(UART0, UART0_IRQ, 0, 20, 21); | 940 | impl_instance!(UART0, UART0_IRQ, 20, 21); |
| 943 | impl_instance!(UART1, UART1_IRQ, 1, 22, 23); | 941 | impl_instance!(UART1, UART1_IRQ, 22, 23); |
| 944 | 942 | ||
| 945 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | 943 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} |
| 946 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | 944 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 9686b10ce..b9887f9b3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -58,7 +58,7 @@ sdio-host = "0.5.0" | |||
| 58 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 58 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 59 | critical-section = "1.1" | 59 | critical-section = "1.1" |
| 60 | atomic-polyfill = "1.0.1" | 60 | atomic-polyfill = "1.0.1" |
| 61 | stm32-metapac = "6" | 61 | stm32-metapac = "7" |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 74 | [build-dependencies] | 74 | [build-dependencies] |
| 75 | proc-macro2 = "1.0.36" | 75 | proc-macro2 = "1.0.36" |
| 76 | quote = "1.0.15" | 76 | quote = "1.0.15" |
| 77 | stm32-metapac = { version = "6", default-features = false, features = ["metadata"]} | 77 | stm32-metapac = { version = "7", default-features = false, features = ["metadata"]} |
| 78 | 78 | ||
| 79 | [features] | 79 | [features] |
| 80 | default = ["stm32-metapac/rt"] | 80 | default = ["stm32-metapac/rt"] |
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 3e23e7ca1..12cf8b0fc 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -84,7 +84,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 84 | Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) | 84 | Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | #[cfg(not(usart_v1))] | 87 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 88 | pub fn new_with_de( | 88 | pub fn new_with_de( |
| 89 | peri: impl Peripheral<P = T> + 'd, | 89 | peri: impl Peripheral<P = T> + 'd, |
| 90 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 90 | irq: impl Peripheral<P = T::Interrupt> + 'd, |
| @@ -133,7 +133,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 133 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 133 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | configure(r, &config, T::frequency(), T::MULTIPLIER, true, true); | 136 | configure(r, &config, T::frequency(), T::KIND, true, true); |
| 137 | 137 | ||
| 138 | unsafe { | 138 | unsafe { |
| 139 | r.cr1().modify(|w| { | 139 | r.cr1().modify(|w| { |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ad450f2b3..dbce668c2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -12,10 +12,11 @@ use futures::future::{select, Either}; | |||
| 12 | 12 | ||
| 13 | use crate::dma::{NoDma, Transfer}; | 13 | use crate::dma::{NoDma, Transfer}; |
| 14 | use crate::gpio::sealed::AFType; | 14 | use crate::gpio::sealed::AFType; |
| 15 | #[cfg(any(lpuart_v1, lpuart_v2))] | 15 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 16 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; | 16 | use crate::pac::usart::Lpuart as Regs; |
| 17 | #[cfg(not(any(lpuart_v1, lpuart_v2)))] | 17 | #[cfg(any(usart_v1, usart_v2))] |
| 18 | use crate::pac::usart::{regs, vals, Usart as Regs}; | 18 | use crate::pac::usart::Usart as Regs; |
| 19 | use crate::pac::usart::{regs, vals}; | ||
| 19 | use crate::time::Hertz; | 20 | use crate::time::Hertz; |
| 20 | use crate::{peripherals, Peripheral}; | 21 | use crate::{peripherals, Peripheral}; |
| 21 | 22 | ||
| @@ -159,7 +160,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 159 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 160 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 160 | } | 161 | } |
| 161 | 162 | ||
| 162 | configure(r, &config, T::frequency(), T::MULTIPLIER, false, true); | 163 | configure(r, &config, T::frequency(), T::KIND, false, true); |
| 163 | 164 | ||
| 164 | // create state once! | 165 | // create state once! |
| 165 | let _s = T::state(); | 166 | let _s = T::state(); |
| @@ -261,7 +262,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 261 | rx.set_as_af(rx.af_num(), AFType::Input); | 262 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 262 | } | 263 | } |
| 263 | 264 | ||
| 264 | configure(r, &config, T::frequency(), T::MULTIPLIER, true, false); | 265 | configure(r, &config, T::frequency(), T::KIND, true, false); |
| 265 | 266 | ||
| 266 | irq.set_handler(Self::on_interrupt); | 267 | irq.set_handler(Self::on_interrupt); |
| 267 | irq.unpend(); | 268 | irq.unpend(); |
| @@ -653,7 +654,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 653 | Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) | 654 | Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) |
| 654 | } | 655 | } |
| 655 | 656 | ||
| 656 | #[cfg(not(usart_v1))] | 657 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 657 | pub fn new_with_de( | 658 | pub fn new_with_de( |
| 658 | peri: impl Peripheral<P = T> + 'd, | 659 | peri: impl Peripheral<P = T> + 'd, |
| 659 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 660 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| @@ -696,7 +697,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 696 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 697 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 697 | } | 698 | } |
| 698 | 699 | ||
| 699 | configure(r, &config, T::frequency(), T::MULTIPLIER, true, true); | 700 | configure(r, &config, T::frequency(), T::KIND, true, true); |
| 700 | 701 | ||
| 701 | irq.set_handler(UartRx::<T, RxDma>::on_interrupt); | 702 | irq.set_handler(UartRx::<T, RxDma>::on_interrupt); |
| 702 | irq.unpend(); | 703 | irq.unpend(); |
| @@ -763,16 +764,74 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 763 | } | 764 | } |
| 764 | } | 765 | } |
| 765 | 766 | ||
| 766 | fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) { | 767 | fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { |
| 767 | if !enable_rx && !enable_tx { | 768 | if !enable_rx && !enable_tx { |
| 768 | panic!("USART: At least one of RX or TX should be enabled"); | 769 | panic!("USART: At least one of RX or TX should be enabled"); |
| 769 | } | 770 | } |
| 770 | 771 | ||
| 771 | // TODO: better calculation, including error checking and OVER8 if possible. | 772 | #[cfg(not(usart_v4))] |
| 772 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; | 773 | static DIVS: [(u16, ()); 1] = [(1, ())]; |
| 774 | |||
| 775 | #[cfg(usart_v4)] | ||
| 776 | static DIVS: [(u16, vals::Presc); 12] = [ | ||
| 777 | (1, vals::Presc::DIV1), | ||
| 778 | (2, vals::Presc::DIV2), | ||
| 779 | (4, vals::Presc::DIV4), | ||
| 780 | (6, vals::Presc::DIV6), | ||
| 781 | (8, vals::Presc::DIV8), | ||
| 782 | (10, vals::Presc::DIV10), | ||
| 783 | (12, vals::Presc::DIV12), | ||
| 784 | (16, vals::Presc::DIV16), | ||
| 785 | (32, vals::Presc::DIV32), | ||
| 786 | (64, vals::Presc::DIV64), | ||
| 787 | (128, vals::Presc::DIV128), | ||
| 788 | (256, vals::Presc::DIV256), | ||
| 789 | ]; | ||
| 790 | |||
| 791 | let (mul, brr_min, brr_max) = match kind { | ||
| 792 | #[cfg(any(usart_v3, usart_v4))] | ||
| 793 | Kind::Lpuart => (256, 0x300, 0x10_0000), | ||
| 794 | Kind::Uart => (1, 0x10, 0x1_0000), | ||
| 795 | }; | ||
| 796 | |||
| 797 | #[cfg(not(usart_v1))] | ||
| 798 | let mut over8 = false; | ||
| 799 | let mut found = false; | ||
| 800 | for &(presc, _presc_val) in &DIVS { | ||
| 801 | let denom = (config.baudrate * presc as u32) as u64; | ||
| 802 | let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom; | ||
| 803 | trace!("USART: presc={} div={:08x}", presc, div); | ||
| 804 | |||
| 805 | if div < brr_min { | ||
| 806 | #[cfg(not(usart_v1))] | ||
| 807 | if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { | ||
| 808 | over8 = true; | ||
| 809 | let div = div as u32; | ||
| 810 | unsafe { | ||
| 811 | r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); | ||
| 812 | #[cfg(usart_v4)] | ||
| 813 | r.presc().write(|w| w.set_prescaler(_presc_val)); | ||
| 814 | } | ||
| 815 | found = true; | ||
| 816 | break; | ||
| 817 | } | ||
| 818 | panic!("USART: baudrate too high"); | ||
| 819 | } | ||
| 820 | |||
| 821 | if div < brr_max { | ||
| 822 | unsafe { | ||
| 823 | r.brr().write_value(regs::Brr(div as u32)); | ||
| 824 | #[cfg(usart_v4)] | ||
| 825 | r.presc().write(|w| w.set_prescaler(_presc_val)); | ||
| 826 | } | ||
| 827 | found = true; | ||
| 828 | break; | ||
| 829 | } | ||
| 830 | } | ||
| 831 | |||
| 832 | assert!(found, "USART: baudrate too low"); | ||
| 773 | 833 | ||
| 774 | unsafe { | 834 | unsafe { |
| 775 | r.brr().write_value(regs::Brr(div)); | ||
| 776 | r.cr2().write(|w| { | 835 | r.cr2().write(|w| { |
| 777 | w.set_stop(match config.stop_bits { | 836 | w.set_stop(match config.stop_bits { |
| 778 | StopBits::STOP0P5 => vals::Stop::STOP0P5, | 837 | StopBits::STOP0P5 => vals::Stop::STOP0P5, |
| @@ -801,6 +860,8 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable | |||
| 801 | Parity::ParityEven => vals::Ps::EVEN, | 860 | Parity::ParityEven => vals::Ps::EVEN, |
| 802 | _ => vals::Ps::EVEN, | 861 | _ => vals::Ps::EVEN, |
| 803 | }); | 862 | }); |
| 863 | #[cfg(not(usart_v1))] | ||
| 864 | w.set_over8(vals::Over8(over8 as _)); | ||
| 804 | }); | 865 | }); |
| 805 | } | 866 | } |
| 806 | } | 867 | } |
| @@ -986,43 +1047,45 @@ mod rx_ringbuffered; | |||
| 986 | #[cfg(not(gpdma))] | 1047 | #[cfg(not(gpdma))] |
| 987 | pub use rx_ringbuffered::RingBufferedUartRx; | 1048 | pub use rx_ringbuffered::RingBufferedUartRx; |
| 988 | 1049 | ||
| 989 | #[cfg(usart_v1)] | 1050 | use self::sealed::Kind; |
| 1051 | |||
| 1052 | #[cfg(any(usart_v1, usart_v2))] | ||
| 990 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { | 1053 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { |
| 991 | r.dr().ptr() as _ | 1054 | r.dr().ptr() as _ |
| 992 | } | 1055 | } |
| 993 | 1056 | ||
| 994 | #[cfg(usart_v1)] | 1057 | #[cfg(any(usart_v1, usart_v2))] |
| 995 | fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { | 1058 | fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { |
| 996 | r.dr().ptr() as _ | 1059 | r.dr().ptr() as _ |
| 997 | } | 1060 | } |
| 998 | 1061 | ||
| 999 | #[cfg(usart_v1)] | 1062 | #[cfg(any(usart_v1, usart_v2))] |
| 1000 | fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { | 1063 | fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { |
| 1001 | r.sr() | 1064 | r.sr() |
| 1002 | } | 1065 | } |
| 1003 | 1066 | ||
| 1004 | #[cfg(usart_v1)] | 1067 | #[cfg(any(usart_v1, usart_v2))] |
| 1005 | #[allow(unused)] | 1068 | #[allow(unused)] |
| 1006 | unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { | 1069 | unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { |
| 1007 | // On v1 the flags are cleared implicitly by reads and writes to DR. | 1070 | // On v1 the flags are cleared implicitly by reads and writes to DR. |
| 1008 | } | 1071 | } |
| 1009 | 1072 | ||
| 1010 | #[cfg(usart_v2)] | 1073 | #[cfg(any(usart_v3, usart_v4))] |
| 1011 | fn tdr(r: Regs) -> *mut u8 { | 1074 | fn tdr(r: Regs) -> *mut u8 { |
| 1012 | r.tdr().ptr() as _ | 1075 | r.tdr().ptr() as _ |
| 1013 | } | 1076 | } |
| 1014 | 1077 | ||
| 1015 | #[cfg(usart_v2)] | 1078 | #[cfg(any(usart_v3, usart_v4))] |
| 1016 | fn rdr(r: Regs) -> *mut u8 { | 1079 | fn rdr(r: Regs) -> *mut u8 { |
| 1017 | r.rdr().ptr() as _ | 1080 | r.rdr().ptr() as _ |
| 1018 | } | 1081 | } |
| 1019 | 1082 | ||
| 1020 | #[cfg(usart_v2)] | 1083 | #[cfg(any(usart_v3, usart_v4))] |
| 1021 | fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> { | 1084 | fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> { |
| 1022 | r.isr() | 1085 | r.isr() |
| 1023 | } | 1086 | } |
| 1024 | 1087 | ||
| 1025 | #[cfg(usart_v2)] | 1088 | #[cfg(any(usart_v3, usart_v4))] |
| 1026 | #[allow(unused)] | 1089 | #[allow(unused)] |
| 1027 | unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | 1090 | unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { |
| 1028 | r.icr().write(|w| *w = regs::Icr(sr.0)); | 1091 | r.icr().write(|w| *w = regs::Icr(sr.0)); |
| @@ -1033,6 +1096,13 @@ pub(crate) mod sealed { | |||
| 1033 | 1096 | ||
| 1034 | use super::*; | 1097 | use super::*; |
| 1035 | 1098 | ||
| 1099 | #[derive(Clone, Copy, PartialEq, Eq)] | ||
| 1100 | pub enum Kind { | ||
| 1101 | Uart, | ||
| 1102 | #[cfg(any(usart_v3, usart_v4))] | ||
| 1103 | Lpuart, | ||
| 1104 | } | ||
| 1105 | |||
| 1036 | pub struct State { | 1106 | pub struct State { |
| 1037 | pub rx_waker: AtomicWaker, | 1107 | pub rx_waker: AtomicWaker, |
| 1038 | pub tx_waker: AtomicWaker, | 1108 | pub tx_waker: AtomicWaker, |
| @@ -1048,7 +1118,7 @@ pub(crate) mod sealed { | |||
| 1048 | } | 1118 | } |
| 1049 | 1119 | ||
| 1050 | pub trait BasicInstance: crate::rcc::RccPeripheral { | 1120 | pub trait BasicInstance: crate::rcc::RccPeripheral { |
| 1051 | const MULTIPLIER: u32; | 1121 | const KIND: Kind; |
| 1052 | type Interrupt: crate::interrupt::Interrupt; | 1122 | type Interrupt: crate::interrupt::Interrupt; |
| 1053 | 1123 | ||
| 1054 | fn regs() -> Regs; | 1124 | fn regs() -> Regs; |
| @@ -1077,10 +1147,10 @@ pin_trait!(DePin, BasicInstance); | |||
| 1077 | dma_trait!(TxDma, BasicInstance); | 1147 | dma_trait!(TxDma, BasicInstance); |
| 1078 | dma_trait!(RxDma, BasicInstance); | 1148 | dma_trait!(RxDma, BasicInstance); |
| 1079 | 1149 | ||
| 1080 | macro_rules! impl_lpuart { | 1150 | macro_rules! impl_usart { |
| 1081 | ($inst:ident, $irq:ident, $mul:expr) => { | 1151 | ($inst:ident, $irq:ident, $kind:expr) => { |
| 1082 | impl sealed::BasicInstance for crate::peripherals::$inst { | 1152 | impl sealed::BasicInstance for crate::peripherals::$inst { |
| 1083 | const MULTIPLIER: u32 = $mul; | 1153 | const KIND: Kind = $kind; |
| 1084 | type Interrupt = crate::interrupt::$irq; | 1154 | type Interrupt = crate::interrupt::$irq; |
| 1085 | 1155 | ||
| 1086 | fn regs() -> Regs { | 1156 | fn regs() -> Regs { |
| @@ -1104,21 +1174,19 @@ macro_rules! impl_lpuart { | |||
| 1104 | } | 1174 | } |
| 1105 | 1175 | ||
| 1106 | foreach_interrupt!( | 1176 | foreach_interrupt!( |
| 1107 | ($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => { | 1177 | ($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => { |
| 1108 | impl_lpuart!($inst, $irq, 256); | 1178 | impl_usart!($inst, $irq, Kind::Lpuart); |
| 1109 | }; | 1179 | }; |
| 1110 | 1180 | ||
| 1111 | ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { | 1181 | ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { |
| 1112 | impl_lpuart!($inst, $irq, 1); | 1182 | impl_usart!($inst, $irq, Kind::Uart); |
| 1113 | 1183 | ||
| 1114 | impl sealed::FullInstance for peripherals::$inst { | 1184 | impl sealed::FullInstance for peripherals::$inst { |
| 1115 | |||
| 1116 | fn regs_uart() -> crate::pac::usart::Usart { | 1185 | fn regs_uart() -> crate::pac::usart::Usart { |
| 1117 | crate::pac::$inst | 1186 | crate::pac::$inst |
| 1118 | } | 1187 | } |
| 1119 | } | 1188 | } |
| 1120 | 1189 | ||
| 1121 | impl FullInstance for peripherals::$inst { | 1190 | impl FullInstance for peripherals::$inst {} |
| 1122 | } | ||
| 1123 | }; | 1191 | }; |
| 1124 | ); | 1192 | ); |
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 1b075b8fd..5fea7034b 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs | |||
| @@ -4,15 +4,13 @@ | |||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_rp::gpio::{AnyPin, Pin}; | 6 | use embassy_rp::gpio::{AnyPin, Pin}; |
| 7 | use embassy_rp::pio::{ | 7 | use embassy_rp::peripherals::PIO0; |
| 8 | Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, | 8 | use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection}; |
| 9 | Sm1, Sm2, | ||
| 10 | }; | ||
| 11 | use embassy_rp::pio_instr_util; | 9 | use embassy_rp::pio_instr_util; |
| 12 | use embassy_rp::relocate::RelocatedProgram; | 10 | use embassy_rp::relocate::RelocatedProgram; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 12 | ||
| 15 | fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) { | 13 | fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 0>, pin: AnyPin) { |
| 16 | // Setup sm0 | 14 | // Setup sm0 |
| 17 | 15 | ||
| 18 | // Send data serially to pin | 16 | // Send data serially to pin |
| @@ -40,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin | |||
| 40 | } | 38 | } |
| 41 | 39 | ||
| 42 | #[embassy_executor::task] | 40 | #[embassy_executor::task] |
| 43 | async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) { | 41 | async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) { |
| 44 | sm.set_enable(true); | 42 | sm.set_enable(true); |
| 45 | 43 | ||
| 46 | let mut v = 0x0f0caffa; | 44 | let mut v = 0x0f0caffa; |
| @@ -51,7 +49,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) { | |||
| 51 | } | 49 | } |
| 52 | } | 50 | } |
| 53 | 51 | ||
| 54 | fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm1>) { | 52 | fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 1>) { |
| 55 | // Setupm sm1 | 53 | // Setupm sm1 |
| 56 | 54 | ||
| 57 | // Read 0b10101 repeatedly until ISR is full | 55 | // Read 0b10101 repeatedly until ISR is full |
| @@ -70,7 +68,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin | |||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | #[embassy_executor::task] | 70 | #[embassy_executor::task] |
| 73 | async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) { | 71 | async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) { |
| 74 | sm.set_enable(true); | 72 | sm.set_enable(true); |
| 75 | loop { | 73 | loop { |
| 76 | let rx = sm.wait_pull().await; | 74 | let rx = sm.wait_pull().await; |
| @@ -78,7 +76,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) { | |||
| 78 | } | 76 | } |
| 79 | } | 77 | } |
| 80 | 78 | ||
| 81 | fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm2>) { | 79 | fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 2>) { |
| 82 | // Setup sm2 | 80 | // Setup sm2 |
| 83 | 81 | ||
| 84 | // Repeatedly trigger IRQ 3 | 82 | // Repeatedly trigger IRQ 3 |
| @@ -102,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin | |||
| 102 | } | 100 | } |
| 103 | 101 | ||
| 104 | #[embassy_executor::task] | 102 | #[embassy_executor::task] |
| 105 | async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) { | 103 | async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) { |
| 106 | sm.set_enable(true); | 104 | sm.set_enable(true); |
| 107 | loop { | 105 | loop { |
| 108 | sm.wait_irq(3).await; | 106 | sm.wait_irq(3).await; |
| @@ -115,11 +113,17 @@ async fn main(spawner: Spawner) { | |||
| 115 | let p = embassy_rp::init(Default::default()); | 113 | let p = embassy_rp::init(Default::default()); |
| 116 | let pio = p.PIO0; | 114 | let pio = p.PIO0; |
| 117 | 115 | ||
| 118 | let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split(); | 116 | let Pio { |
| 119 | 117 | mut common, | |
| 120 | setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); | 118 | mut sm0, |
| 121 | setup_pio_task_sm1(&mut pio0, &mut sm1); | 119 | mut sm1, |
| 122 | setup_pio_task_sm2(&mut pio0, &mut sm2); | 120 | mut sm2, |
| 121 | .. | ||
| 122 | } = Pio::new(pio); | ||
| 123 | |||
| 124 | setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade()); | ||
| 125 | setup_pio_task_sm1(&mut common, &mut sm1); | ||
| 126 | setup_pio_task_sm2(&mut common, &mut sm2); | ||
| 123 | spawner.spawn(pio_task_sm0(sm0)).unwrap(); | 127 | spawner.spawn(pio_task_sm0(sm0)).unwrap(); |
| 124 | spawner.spawn(pio_task_sm1(sm1)).unwrap(); | 128 | spawner.spawn(pio_task_sm1(sm1)).unwrap(); |
| 125 | spawner.spawn(pio_task_sm2(sm2)).unwrap(); | 129 | spawner.spawn(pio_task_sm2(sm2)).unwrap(); |
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 7d4919f75..0f1f6df12 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_rp::pio::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection}; | 7 | use embassy_rp::pio::{Pio, PioStateMachine, ShiftDirection}; |
| 8 | use embassy_rp::relocate::RelocatedProgram; | 8 | use embassy_rp::relocate::RelocatedProgram; |
| 9 | use embassy_rp::{pio_instr_util, Peripheral}; | 9 | use embassy_rp::{pio_instr_util, Peripheral}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -19,7 +19,11 @@ fn swap_nibbles(v: u32) -> u32 { | |||
| 19 | async fn main(_spawner: Spawner) { | 19 | async fn main(_spawner: Spawner) { |
| 20 | let p = embassy_rp::init(Default::default()); | 20 | let p = embassy_rp::init(Default::default()); |
| 21 | let pio = p.PIO0; | 21 | let pio = p.PIO0; |
| 22 | let (mut pio0, mut sm, ..) = pio.split(); | 22 | let Pio { |
| 23 | mut common, | ||
| 24 | sm0: mut sm, | ||
| 25 | .. | ||
| 26 | } = Pio::new(pio); | ||
| 23 | 27 | ||
| 24 | let prg = pio_proc::pio_asm!( | 28 | let prg = pio_proc::pio_asm!( |
| 25 | ".origin 0", | 29 | ".origin 0", |
| @@ -34,7 +38,7 @@ async fn main(_spawner: Spawner) { | |||
| 34 | ); | 38 | ); |
| 35 | 39 | ||
| 36 | let relocated = RelocatedProgram::new(&prg.program); | 40 | let relocated = RelocatedProgram::new(&prg.program); |
| 37 | pio0.write_instr(relocated.origin() as usize, relocated.code()); | 41 | common.write_instr(relocated.origin() as usize, relocated.code()); |
| 38 | pio_instr_util::exec_jmp(&mut sm, relocated.origin()); | 42 | pio_instr_util::exec_jmp(&mut sm, relocated.origin()); |
| 39 | sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); | 43 | sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); |
| 40 | let pio::Wrap { source, target } = relocated.wrap(); | 44 | let pio::Wrap { source, target } = relocated.wrap(); |
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs new file mode 100644 index 000000000..59b4c1f52 --- /dev/null +++ b/examples/rp/src/bin/pio_hd44780.rs | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use core::fmt::Write; | ||
| 6 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::dma::{AnyChannel, Channel}; | ||
| 9 | use embassy_rp::gpio::Pin; | ||
| 10 | use embassy_rp::peripherals::PIO0; | ||
| 11 | use embassy_rp::pio::{FifoJoin, Pio, PioStateMachine, PioStateMachineInstance, ShiftDirection}; | ||
| 12 | use embassy_rp::pwm::{Config, Pwm}; | ||
| 13 | use embassy_rp::relocate::RelocatedProgram; | ||
| 14 | use embassy_rp::{into_ref, Peripheral, PeripheralRef}; | ||
| 15 | use embassy_time::{Duration, Instant, Timer}; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async fn main(_spawner: Spawner) { | ||
| 20 | // this test assumes a 2x16 HD44780 display attached as follow: | ||
| 21 | // rs = PIN0 | ||
| 22 | // rw = PIN1 | ||
| 23 | // e = PIN2 | ||
| 24 | // db4 = PIN3 | ||
| 25 | // db5 = PIN4 | ||
| 26 | // db6 = PIN5 | ||
| 27 | // db7 = PIN6 | ||
| 28 | // additionally a pwm signal for a bias voltage charge pump is provided on pin 15, | ||
| 29 | // allowing direct connection of the display to the RP2040 without level shifters. | ||
| 30 | let p = embassy_rp::init(Default::default()); | ||
| 31 | |||
| 32 | let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { | ||
| 33 | let mut c = Config::default(); | ||
| 34 | c.divider = 125.into(); | ||
| 35 | c.top = 100; | ||
| 36 | c.compare_b = 50; | ||
| 37 | c | ||
| 38 | }); | ||
| 39 | |||
| 40 | let mut hd = HD44780::new( | ||
| 41 | p.PIO0, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, | ||
| 42 | ) | ||
| 43 | .await; | ||
| 44 | |||
| 45 | loop { | ||
| 46 | struct Buf<const N: usize>([u8; N], usize); | ||
| 47 | impl<const N: usize> Write for Buf<N> { | ||
| 48 | fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { | ||
| 49 | for b in s.as_bytes() { | ||
| 50 | if self.1 >= N { | ||
| 51 | return Err(core::fmt::Error); | ||
| 52 | } | ||
| 53 | self.0[self.1] = *b; | ||
| 54 | self.1 += 1; | ||
| 55 | } | ||
| 56 | Ok(()) | ||
| 57 | } | ||
| 58 | } | ||
| 59 | let mut buf = Buf([0; 16], 0); | ||
| 60 | write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap(); | ||
| 61 | hd.add_line(&buf.0[0..buf.1]).await; | ||
| 62 | Timer::after(Duration::from_secs(1)).await; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | pub struct HD44780<'l> { | ||
| 67 | dma: PeripheralRef<'l, AnyChannel>, | ||
| 68 | sm: PioStateMachineInstance<'l, PIO0, 0>, | ||
| 69 | |||
| 70 | buf: [u8; 40], | ||
| 71 | } | ||
| 72 | |||
| 73 | impl<'l> HD44780<'l> { | ||
| 74 | pub async fn new( | ||
| 75 | pio: impl Peripheral<P = PIO0> + 'l, | ||
| 76 | dma: impl Peripheral<P = impl Channel> + 'l, | ||
| 77 | rs: impl Pin, | ||
| 78 | rw: impl Pin, | ||
| 79 | e: impl Pin, | ||
| 80 | db4: impl Pin, | ||
| 81 | db5: impl Pin, | ||
| 82 | db6: impl Pin, | ||
| 83 | db7: impl Pin, | ||
| 84 | ) -> HD44780<'l> { | ||
| 85 | into_ref!(dma); | ||
| 86 | |||
| 87 | let db7pin = db7.pin(); | ||
| 88 | let Pio { | ||
| 89 | mut common, mut sm0, .. | ||
| 90 | } = Pio::new(pio); | ||
| 91 | |||
| 92 | // takes command words (<wait:24> <command:4> <0:4>) | ||
| 93 | let prg = pio_proc::pio_asm!( | ||
| 94 | r#" | ||
| 95 | .side_set 1 opt | ||
| 96 | |||
| 97 | loop: | ||
| 98 | out x, 24 | ||
| 99 | delay: | ||
| 100 | jmp x--, delay | ||
| 101 | out pins, 4 side 1 | ||
| 102 | out null, 4 side 0 | ||
| 103 | jmp !osre, loop | ||
| 104 | irq 0 | ||
| 105 | "#, | ||
| 106 | ); | ||
| 107 | |||
| 108 | let rs = common.make_pio_pin(rs); | ||
| 109 | let rw = common.make_pio_pin(rw); | ||
| 110 | let e = common.make_pio_pin(e); | ||
| 111 | let db4 = common.make_pio_pin(db4); | ||
| 112 | let db5 = common.make_pio_pin(db5); | ||
| 113 | let db6 = common.make_pio_pin(db6); | ||
| 114 | let db7 = common.make_pio_pin(db7); | ||
| 115 | |||
| 116 | sm0.set_set_pins(&[&rs, &rw]); | ||
| 117 | embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11); | ||
| 118 | sm0.set_set_pins(&[&e]); | ||
| 119 | embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1); | ||
| 120 | sm0.set_set_pins(&[&db4, &db5, &db6, &db7]); | ||
| 121 | embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111); | ||
| 122 | |||
| 123 | let relocated = RelocatedProgram::new(&prg.program); | ||
| 124 | common.write_instr(relocated.origin() as usize, relocated.code()); | ||
| 125 | embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); | ||
| 126 | sm0.set_clkdiv(125 * 256); | ||
| 127 | let pio::Wrap { source, target } = relocated.wrap(); | ||
| 128 | sm0.set_wrap(source, target); | ||
| 129 | sm0.set_side_enable(true); | ||
| 130 | sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); | ||
| 131 | sm0.set_sideset_base_pin(&e); | ||
| 132 | sm0.set_sideset_count(2); | ||
| 133 | sm0.set_out_shift_dir(ShiftDirection::Left); | ||
| 134 | sm0.set_fifo_join(FifoJoin::TxOnly); | ||
| 135 | sm0.set_autopull(true); | ||
| 136 | sm0.set_pull_threshold(32); | ||
| 137 | |||
| 138 | sm0.set_enable(true); | ||
| 139 | // init to 8 bit thrice | ||
| 140 | sm0.push_tx((50000 << 8) | 0x30); | ||
| 141 | sm0.push_tx((5000 << 8) | 0x30); | ||
| 142 | sm0.push_tx((200 << 8) | 0x30); | ||
| 143 | // init 4 bit | ||
| 144 | sm0.push_tx((200 << 8) | 0x20); | ||
| 145 | // set font and lines | ||
| 146 | sm0.push_tx((50 << 8) | 0x20); | ||
| 147 | sm0.push_tx(0b1100_0000); | ||
| 148 | |||
| 149 | sm0.wait_irq(0).await; | ||
| 150 | sm0.set_enable(false); | ||
| 151 | |||
| 152 | // takes command sequences (<rs:1> <count:7>, data...) | ||
| 153 | // many side sets are only there to free up a delay bit! | ||
| 154 | let prg = pio_proc::pio_asm!( | ||
| 155 | r#" | ||
| 156 | .origin 7 | ||
| 157 | .side_set 1 | ||
| 158 | |||
| 159 | .wrap_target | ||
| 160 | pull side 0 | ||
| 161 | out x 1 side 0 ; !rs | ||
| 162 | out y 7 side 0 ; #data - 1 | ||
| 163 | |||
| 164 | ; rs/rw to e: >= 60ns | ||
| 165 | ; e high time: >= 500ns | ||
| 166 | ; e low time: >= 500ns | ||
| 167 | ; read data valid after e falling: ~5ns | ||
| 168 | ; write data hold after e falling: ~10ns | ||
| 169 | |||
| 170 | loop: | ||
| 171 | pull side 0 | ||
| 172 | jmp !x data side 0 | ||
| 173 | command: | ||
| 174 | set pins 0b00 side 0 | ||
| 175 | jmp shift side 0 | ||
| 176 | data: | ||
| 177 | set pins 0b01 side 0 | ||
| 178 | shift: | ||
| 179 | out pins 4 side 1 [9] | ||
| 180 | nop side 0 [9] | ||
| 181 | out pins 4 side 1 [9] | ||
| 182 | mov osr null side 0 [7] | ||
| 183 | out pindirs 4 side 0 | ||
| 184 | set pins 0b10 side 0 | ||
| 185 | busy: | ||
| 186 | nop side 1 [9] | ||
| 187 | jmp pin more side 0 [9] | ||
| 188 | mov osr ~osr side 1 [9] | ||
| 189 | nop side 0 [4] | ||
| 190 | out pindirs 4 side 0 | ||
| 191 | jmp y-- loop side 0 | ||
| 192 | .wrap | ||
| 193 | more: | ||
| 194 | nop side 1 [9] | ||
| 195 | jmp busy side 0 [9] | ||
| 196 | "# | ||
| 197 | ); | ||
| 198 | |||
| 199 | let relocated = RelocatedProgram::new(&prg.program); | ||
| 200 | common.write_instr(relocated.origin() as usize, relocated.code()); | ||
| 201 | embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); | ||
| 202 | let pio::Wrap { source, target } = relocated.wrap(); | ||
| 203 | sm0.set_clkdiv(8 * 256); // ~64ns/insn | ||
| 204 | sm0.set_side_enable(false); | ||
| 205 | sm0.set_jmp_pin(db7pin); | ||
| 206 | sm0.set_wrap(source, target); | ||
| 207 | sm0.set_set_pins(&[&rs, &rw]); | ||
| 208 | sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); | ||
| 209 | sm0.set_sideset_base_pin(&e); | ||
| 210 | sm0.set_sideset_count(1); | ||
| 211 | sm0.set_out_shift_dir(ShiftDirection::Left); | ||
| 212 | sm0.set_fifo_join(FifoJoin::TxOnly); | ||
| 213 | |||
| 214 | sm0.set_enable(true); | ||
| 215 | |||
| 216 | // display on and cursor on and blinking, reset display | ||
| 217 | sm0.dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; | ||
| 218 | |||
| 219 | Self { | ||
| 220 | dma: dma.map_into(), | ||
| 221 | sm: sm0, | ||
| 222 | buf: [0x20; 40], | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | pub async fn add_line(&mut self, s: &[u8]) { | ||
| 227 | // move cursor to 0:0, prepare 16 characters | ||
| 228 | self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); | ||
| 229 | // move line 2 up | ||
| 230 | self.buf.copy_within(22..38, 3); | ||
| 231 | // move cursor to 1:0, prepare 16 characters | ||
| 232 | self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); | ||
| 233 | // file line 2 with spaces | ||
| 234 | self.buf[22..38].fill(0x20); | ||
| 235 | // copy input line | ||
| 236 | let len = s.len().min(16); | ||
| 237 | self.buf[22..22 + len].copy_from_slice(&s[0..len]); | ||
| 238 | // set cursor to 1:15 | ||
| 239 | self.buf[38..].copy_from_slice(&[0x80, 0xcf]); | ||
| 240 | |||
| 241 | self.sm.dma_push(self.dma.reborrow(), &self.buf).await; | ||
| 242 | } | ||
| 243 | } | ||
diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 041e8ae11..0975559d7 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs | |||
| @@ -6,20 +6,19 @@ use defmt::*; | |||
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_rp::gpio::{self, Pin}; | 7 | use embassy_rp::gpio::{self, Pin}; |
| 8 | use embassy_rp::pio::{ | 8 | use embassy_rp::pio::{ |
| 9 | FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, | 9 | FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, |
| 10 | ShiftDirection, SmInstance, | ||
| 11 | }; | 10 | }; |
| 12 | use embassy_rp::pio_instr_util; | 11 | use embassy_rp::pio_instr_util; |
| 13 | use embassy_rp::relocate::RelocatedProgram; | 12 | use embassy_rp::relocate::RelocatedProgram; |
| 14 | use embassy_time::{Duration, Timer}; | 13 | use embassy_time::{Duration, Timer}; |
| 15 | use smart_leds::RGB8; | 14 | use smart_leds::RGB8; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | pub struct Ws2812<P: PioInstance, S: SmInstance> { | 16 | pub struct Ws2812<'d, P: PioInstance, const S: usize> { |
| 18 | sm: PioStateMachineInstance<P, S>, | 17 | sm: PioStateMachineInstance<'d, P, S>, |
| 19 | } | 18 | } |
| 20 | 19 | ||
| 21 | impl<P: PioInstance, S: SmInstance> Ws2812<P, S> { | 20 | impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> { |
| 22 | pub fn new(mut pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self { | 21 | pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self { |
| 23 | // Setup sm0 | 22 | // Setup sm0 |
| 24 | 23 | ||
| 25 | // prepare the PIO program | 24 | // prepare the PIO program |
| @@ -116,7 +115,7 @@ async fn main(_spawner: Spawner) { | |||
| 116 | info!("Start"); | 115 | info!("Start"); |
| 117 | let p = embassy_rp::init(Default::default()); | 116 | let p = embassy_rp::init(Default::default()); |
| 118 | 117 | ||
| 119 | let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); | 118 | let Pio { common, sm0, .. } = Pio::new(p.PIO0); |
| 120 | 119 | ||
| 121 | // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit | 120 | // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit |
| 122 | // feather boards for the 2040 both have one built in. | 121 | // feather boards for the 2040 both have one built in. |
| @@ -125,7 +124,7 @@ async fn main(_spawner: Spawner) { | |||
| 125 | 124 | ||
| 126 | // For the thing plus, use pin 8 | 125 | // For the thing plus, use pin 8 |
| 127 | // For the feather, use pin 16 | 126 | // For the feather, use pin 16 |
| 128 | let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade()); | 127 | let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade()); |
| 129 | 128 | ||
| 130 | // Loop forever making RGB values and pushing them out to the WS2812. | 129 | // Loop forever making RGB values and pushing them out to the WS2812. |
| 131 | loop { | 130 | loop { |
diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs new file mode 100644 index 000000000..6c13ccaae --- /dev/null +++ b/tests/rp/src/bin/gpio_multicore.rs | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{info, unwrap}; | ||
| 6 | use embassy_executor::Executor; | ||
| 7 | use embassy_executor::_export::StaticCell; | ||
| 8 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | ||
| 9 | use embassy_rp::multicore::{spawn_core1, Stack}; | ||
| 10 | use embassy_rp::peripherals::{PIN_0, PIN_1}; | ||
| 11 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 12 | use embassy_sync::channel::Channel; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | static mut CORE1_STACK: Stack<1024> = Stack::new(); | ||
| 16 | static EXECUTOR0: StaticCell<Executor> = StaticCell::new(); | ||
| 17 | static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); | ||
| 18 | static CHANNEL0: Channel<CriticalSectionRawMutex, (), 1> = Channel::new(); | ||
| 19 | static CHANNEL1: Channel<CriticalSectionRawMutex, (), 1> = Channel::new(); | ||
| 20 | |||
| 21 | #[cortex_m_rt::entry] | ||
| 22 | fn main() -> ! { | ||
| 23 | let p = embassy_rp::init(Default::default()); | ||
| 24 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | ||
| 25 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 26 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1)))); | ||
| 27 | }); | ||
| 28 | let executor0 = EXECUTOR0.init(Executor::new()); | ||
| 29 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0)))); | ||
| 30 | } | ||
| 31 | |||
| 32 | #[embassy_executor::task] | ||
| 33 | async fn core0_task(p: PIN_0) { | ||
| 34 | info!("CORE0 is running"); | ||
| 35 | |||
| 36 | let mut pin = Output::new(p, Level::Low); | ||
| 37 | |||
| 38 | CHANNEL0.send(()).await; | ||
| 39 | CHANNEL1.recv().await; | ||
| 40 | |||
| 41 | pin.set_high(); | ||
| 42 | |||
| 43 | CHANNEL1.recv().await; | ||
| 44 | |||
| 45 | info!("Test OK"); | ||
| 46 | cortex_m::asm::bkpt(); | ||
| 47 | } | ||
| 48 | |||
| 49 | #[embassy_executor::task] | ||
| 50 | async fn core1_task(p: PIN_1) { | ||
| 51 | info!("CORE1 is running"); | ||
| 52 | |||
| 53 | CHANNEL0.recv().await; | ||
| 54 | |||
| 55 | let mut pin = Input::new(p, Pull::Down); | ||
| 56 | let wait = pin.wait_for_rising_edge(); | ||
| 57 | |||
| 58 | CHANNEL1.send(()).await; | ||
| 59 | |||
| 60 | wait.await; | ||
| 61 | |||
| 62 | CHANNEL1.send(()).await; | ||
| 63 | } | ||
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs index 92aa205c9..52f42e582 100644 --- a/tests/rp/src/bin/uart_dma.rs +++ b/tests/rp/src/bin/uart_dma.rs | |||
| @@ -53,10 +53,6 @@ async fn main(_spawner: Spawner) { | |||
| 53 | let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0); | 53 | let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0); |
| 54 | let mut irq = interrupt::take!(UART0_IRQ); | 54 | let mut irq = interrupt::take!(UART0_IRQ); |
| 55 | 55 | ||
| 56 | // TODO | ||
| 57 | // nuclear error reporting. just abort the entire transfer and invalidate the | ||
| 58 | // dma buffer, buffered buffer, fifo etc. | ||
| 59 | |||
| 60 | // We can't send too many bytes, they have to fit in the FIFO. | 56 | // We can't send too many bytes, they have to fit in the FIFO. |
| 61 | // This is because we aren't sending+receiving at the same time. | 57 | // This is because we aren't sending+receiving at the same time. |
| 62 | { | 58 | { |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 5cd949661..83bf1e9c9 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -3,6 +3,7 @@ edition = "2021" | |||
| 3 | name = "embassy-stm32-tests" | 3 | name = "embassy-stm32-tests" |
| 4 | version = "0.1.0" | 4 | version = "0.1.0" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | autobins = false | ||
| 6 | 7 | ||
| 7 | [features] | 8 | [features] |
| 8 | stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill | 9 | stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill |
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index 3e67a7392..7ae311778 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs | |||
| @@ -6,15 +6,16 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
| 6 | let out = PathBuf::from(env::var("OUT_DIR").unwrap()); | 6 | let out = PathBuf::from(env::var("OUT_DIR").unwrap()); |
| 7 | fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); | 7 | fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); |
| 8 | println!("cargo:rustc-link-search={}", out.display()); | 8 | println!("cargo:rustc-link-search={}", out.display()); |
| 9 | println!("cargo:rerun-if-changed=link_ram.x"); | ||
| 10 | |||
| 11 | println!("cargo:rustc-link-arg-bins=--nmagic"); | 9 | println!("cargo:rustc-link-arg-bins=--nmagic"); |
| 12 | 10 | ||
| 13 | // too little RAM to run from RAM. | 11 | // too little RAM to run from RAM. |
| 14 | #[cfg(any(feature = "stm32c031c6"))] | 12 | if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) { |
| 15 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | 13 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); |
| 16 | #[cfg(not(any(feature = "stm32c031c6")))] | 14 | println!("cargo:rerun-if-changed=link.x"); |
| 17 | println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); | 15 | } else { |
| 16 | println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); | ||
| 17 | println!("cargo:rerun-if-changed=link_ram.x"); | ||
| 18 | } | ||
| 18 | 19 | ||
| 19 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | 20 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); |
| 20 | 21 | ||
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 0f5e563b1..a87ac3237 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs | |||
| @@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) { | |||
| 35 | #[cfg(feature = "stm32c031c6")] | 35 | #[cfg(feature = "stm32c031c6")] |
| 36 | let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); | 36 | let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); |
| 37 | 37 | ||
| 38 | info!("asdfa;"); | ||
| 39 | let mut spi = Spi::new( | 38 | let mut spi = Spi::new( |
| 40 | spi, | 39 | spi, |
| 41 | sck, // Arduino D13 | 40 | sck, // Arduino D13 |
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index cca8c42ee..bda2ce9c2 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs | |||
| @@ -9,6 +9,7 @@ use embassy_executor::Spawner; | |||
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | 10 | use embassy_stm32::interrupt; |
| 11 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 12 | use embassy_time::{Duration, Instant}; | ||
| 12 | use example_common::*; | 13 | use example_common::*; |
| 13 | 14 | ||
| 14 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| @@ -19,36 +20,76 @@ async fn main(_spawner: Spawner) { | |||
| 19 | // Arduino pins D0 and D1 | 20 | // Arduino pins D0 and D1 |
| 20 | // They're connected together with a 1K resistor. | 21 | // They're connected together with a 1K resistor. |
| 21 | #[cfg(feature = "stm32f103c8")] | 22 | #[cfg(feature = "stm32f103c8")] |
| 22 | let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); | 23 | let (mut tx, mut rx, mut usart, mut irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); |
| 23 | #[cfg(feature = "stm32g491re")] | 24 | #[cfg(feature = "stm32g491re")] |
| 24 | let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); | 25 | let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); |
| 25 | #[cfg(feature = "stm32g071rb")] | 26 | #[cfg(feature = "stm32g071rb")] |
| 26 | let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); | 27 | let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); |
| 27 | #[cfg(feature = "stm32f429zi")] | 28 | #[cfg(feature = "stm32f429zi")] |
| 28 | let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); | 29 | let (mut tx, mut rx, mut usart, mut irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); |
| 29 | #[cfg(feature = "stm32wb55rg")] | 30 | #[cfg(feature = "stm32wb55rg")] |
| 30 | let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); | 31 | let (mut tx, mut rx, mut usart, mut irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); |
| 31 | #[cfg(feature = "stm32h755zi")] | 32 | #[cfg(feature = "stm32h755zi")] |
| 32 | let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); | 33 | let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); |
| 33 | #[cfg(feature = "stm32u585ai")] | 34 | #[cfg(feature = "stm32u585ai")] |
| 34 | let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); | 35 | let (mut tx, mut rx, mut usart, mut irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); |
| 35 | #[cfg(feature = "stm32h563zi")] | 36 | #[cfg(feature = "stm32h563zi")] |
| 36 | let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1)); | 37 | let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1)); |
| 37 | #[cfg(feature = "stm32c031c6")] | 38 | #[cfg(feature = "stm32c031c6")] |
| 38 | let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); | 39 | let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); |
| 39 | 40 | ||
| 40 | let config = Config::default(); | 41 | { |
| 41 | let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); | 42 | let config = Config::default(); |
| 43 | let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config); | ||
| 42 | 44 | ||
| 43 | // We can't send too many bytes, they have to fit in the FIFO. | 45 | // We can't send too many bytes, they have to fit in the FIFO. |
| 44 | // This is because we aren't sending+receiving at the same time. | 46 | // This is because we aren't sending+receiving at the same time. |
| 45 | 47 | ||
| 46 | let data = [0xC0, 0xDE]; | 48 | let data = [0xC0, 0xDE]; |
| 47 | usart.blocking_write(&data).unwrap(); | 49 | usart.blocking_write(&data).unwrap(); |
| 48 | 50 | ||
| 49 | let mut buf = [0; 2]; | 51 | let mut buf = [0; 2]; |
| 50 | usart.blocking_read(&mut buf).unwrap(); | 52 | usart.blocking_read(&mut buf).unwrap(); |
| 51 | assert_eq!(buf, data); | 53 | assert_eq!(buf, data); |
| 54 | } | ||
| 55 | |||
| 56 | // Test that baudrate divider is calculated correctly. | ||
| 57 | // Do it by comparing the time it takes to send a known number of bytes. | ||
| 58 | for baudrate in [ | ||
| 59 | 300, | ||
| 60 | 9600, | ||
| 61 | 115200, | ||
| 62 | 250_000, | ||
| 63 | 337_934, | ||
| 64 | #[cfg(not(feature = "stm32f103c8"))] | ||
| 65 | 1_000_000, | ||
| 66 | #[cfg(not(feature = "stm32f103c8"))] | ||
| 67 | 2_000_000, | ||
| 68 | ] { | ||
| 69 | info!("testing baudrate {}", baudrate); | ||
| 70 | |||
| 71 | let mut config = Config::default(); | ||
| 72 | config.baudrate = baudrate; | ||
| 73 | let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config); | ||
| 74 | |||
| 75 | let n = (baudrate as usize / 100).max(64); | ||
| 76 | |||
| 77 | let start = Instant::now(); | ||
| 78 | for _ in 0..n { | ||
| 79 | usart.blocking_write(&[0x00]).unwrap(); | ||
| 80 | } | ||
| 81 | let dur = Instant::now() - start; | ||
| 82 | let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64)); | ||
| 83 | let fuzz = want_dur / 5; | ||
| 84 | if dur < want_dur - fuzz || dur > want_dur + fuzz { | ||
| 85 | defmt::panic!( | ||
| 86 | "bad duration for baudrate {}: got {:?} want {:?}", | ||
| 87 | baudrate, | ||
| 88 | dur, | ||
| 89 | want_dur | ||
| 90 | ); | ||
| 91 | } | ||
| 92 | } | ||
| 52 | 93 | ||
| 53 | info!("Test OK"); | 94 | info!("Test OK"); |
| 54 | cortex_m::asm::bkpt(); | 95 | cortex_m::asm::bkpt(); |
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index de6cd41d1..62444f0a8 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs | |||
| @@ -94,6 +94,9 @@ async fn main(_spawner: Spawner) { | |||
| 94 | let rx_fut = async { | 94 | let rx_fut = async { |
| 95 | rx.read(&mut rx_buf).await.unwrap(); | 95 | rx.read(&mut rx_buf).await.unwrap(); |
| 96 | }; | 96 | }; |
| 97 | |||
| 98 | // note: rx needs to be polled first, to workaround this bug: | ||
| 99 | // https://github.com/embassy-rs/embassy/issues/1426 | ||
| 97 | join(rx_fut, tx_fut).await; | 100 | join(rx_fut, tx_fut).await; |
| 98 | 101 | ||
| 99 | assert_eq!(tx_buf, rx_buf); | 102 | assert_eq!(tx_buf, rx_buf); |
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index 2c4a8fdf4..9d75dbe55 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs | |||
| @@ -145,13 +145,16 @@ async fn main(spawner: Spawner) { | |||
| 145 | 145 | ||
| 146 | #[embassy_executor::task] | 146 | #[embassy_executor::task] |
| 147 | async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { | 147 | async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { |
| 148 | // workaround https://github.com/embassy-rs/embassy/issues/1426 | ||
| 149 | Timer::after(Duration::from_millis(100) as _).await; | ||
| 150 | |||
| 148 | let mut rng = ChaCha8Rng::seed_from_u64(1337); | 151 | let mut rng = ChaCha8Rng::seed_from_u64(1337); |
| 149 | 152 | ||
| 150 | info!("Starting random transmissions into void..."); | 153 | info!("Starting random transmissions into void..."); |
| 151 | 154 | ||
| 152 | let mut i: u8 = 0; | 155 | let mut i: u8 = 0; |
| 153 | loop { | 156 | loop { |
| 154 | let mut buf = [0; 32]; | 157 | let mut buf = [0; 256]; |
| 155 | let len = 1 + (rng.next_u32() as usize % buf.len()); | 158 | let len = 1 + (rng.next_u32() as usize % buf.len()); |
| 156 | for b in &mut buf[..len] { | 159 | for b in &mut buf[..len] { |
| 157 | *b = i; | 160 | *b = i; |
| @@ -172,7 +175,7 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx | |||
| 172 | let mut i = 0; | 175 | let mut i = 0; |
| 173 | let mut expected = 0; | 176 | let mut expected = 0; |
| 174 | loop { | 177 | loop { |
| 175 | let mut buf = [0; 100]; | 178 | let mut buf = [0; 256]; |
| 176 | let max_len = 1 + (rng.next_u32() as usize % buf.len()); | 179 | let max_len = 1 + (rng.next_u32() as usize % buf.len()); |
| 177 | let received = match rx.read(&mut buf[..max_len]).await { | 180 | let received = match rx.read(&mut buf[..max_len]).await { |
| 178 | Ok(r) => r, | 181 | Ok(r) => r, |
diff --git a/tests/stm32/src/example_common.rs b/tests/stm32/src/example_common.rs index a4f8668c7..3d150da60 100644 --- a/tests/stm32/src/example_common.rs +++ b/tests/stm32/src/example_common.rs | |||
| @@ -16,5 +16,10 @@ pub fn config() -> Config { | |||
| 16 | config.rcc.pll1.q_ck = Some(Hertz(100_000_000)); | 16 | config.rcc.pll1.q_ck = Some(Hertz(100_000_000)); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | #[cfg(feature = "stm32u585ai")] | ||
| 20 | { | ||
| 21 | config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz); | ||
| 22 | } | ||
| 23 | |||
| 19 | config | 24 | config |
| 20 | } | 25 | } |
