diff options
| -rw-r--r-- | embassy-rp/src/dma.rs | 31 | ||||
| -rw-r--r-- | embassy-rp/src/uart.rs | 71 | ||||
| -rw-r--r-- | tests/rp/src/bin/dma_copy_async.rs | 41 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart.rs | 32 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart_dma.rs | 32 |
5 files changed, 184 insertions, 23 deletions
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 694823742..75d7492e0 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -41,18 +41,38 @@ pub unsafe fn read<'a, C: Channel, W: Word>( | |||
| 41 | ch: impl Peripheral<P = C> + 'a, | 41 | ch: impl Peripheral<P = C> + 'a, |
| 42 | from: *const W, | 42 | from: *const W, |
| 43 | to: &mut [W], | 43 | to: &mut [W], |
| 44 | dreq: u8, | ||
| 44 | ) -> Transfer<'a, C> { | 45 | ) -> Transfer<'a, C> { |
| 45 | let (ptr, len) = crate::dma::slice_ptr_parts_mut(to); | 46 | let (to_ptr, len) = crate::dma::slice_ptr_parts_mut(to); |
| 46 | copy_inner(ch, from as *const u32, ptr as *mut u32, len, W::size(), false, true) | 47 | copy_inner( |
| 48 | ch, | ||
| 49 | from as *const u32, | ||
| 50 | to_ptr as *mut u32, | ||
| 51 | len, | ||
| 52 | W::size(), | ||
| 53 | false, | ||
| 54 | true, | ||
| 55 | dreq, | ||
| 56 | ) | ||
| 47 | } | 57 | } |
| 48 | 58 | ||
| 49 | pub unsafe fn write<'a, C: Channel, W: Word>( | 59 | pub unsafe fn write<'a, C: Channel, W: Word>( |
| 50 | ch: impl Peripheral<P = C> + 'a, | 60 | ch: impl Peripheral<P = C> + 'a, |
| 51 | from: &[W], | 61 | from: &[W], |
| 52 | to: *mut W, | 62 | to: *mut W, |
| 63 | dreq: u8, | ||
| 53 | ) -> Transfer<'a, C> { | 64 | ) -> Transfer<'a, C> { |
| 54 | let (from_ptr, len) = crate::dma::slice_ptr_parts(from); | 65 | let (from_ptr, len) = crate::dma::slice_ptr_parts(from); |
| 55 | copy_inner(ch, from_ptr as *const u32, to as *mut u32, len, W::size(), true, false) | 66 | copy_inner( |
| 67 | ch, | ||
| 68 | from_ptr as *const u32, | ||
| 69 | to as *mut u32, | ||
| 70 | len, | ||
| 71 | W::size(), | ||
| 72 | true, | ||
| 73 | false, | ||
| 74 | dreq, | ||
| 75 | ) | ||
| 56 | } | 76 | } |
| 57 | 77 | ||
| 58 | pub unsafe fn copy<'a, C: Channel, W: Word>( | 78 | pub unsafe fn copy<'a, C: Channel, W: Word>( |
| @@ -71,6 +91,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>( | |||
| 71 | W::size(), | 91 | W::size(), |
| 72 | true, | 92 | true, |
| 73 | true, | 93 | true, |
| 94 | vals::TreqSel::PERMANENT.0, | ||
| 74 | ) | 95 | ) |
| 75 | } | 96 | } |
| 76 | 97 | ||
| @@ -82,6 +103,7 @@ fn copy_inner<'a, C: Channel>( | |||
| 82 | data_size: DataSize, | 103 | data_size: DataSize, |
| 83 | incr_read: bool, | 104 | incr_read: bool, |
| 84 | incr_write: bool, | 105 | incr_write: bool, |
| 106 | dreq: u8, | ||
| 85 | ) -> Transfer<'a, C> { | 107 | ) -> Transfer<'a, C> { |
| 86 | into_ref!(ch); | 108 | into_ref!(ch); |
| 87 | 109 | ||
| @@ -95,6 +117,9 @@ fn copy_inner<'a, C: Channel>( | |||
| 95 | compiler_fence(Ordering::SeqCst); | 117 | compiler_fence(Ordering::SeqCst); |
| 96 | 118 | ||
| 97 | p.ctrl_trig().write(|w| { | 119 | p.ctrl_trig().write(|w| { |
| 120 | // TODO: Add all DREQ options to pac vals::TreqSel, and use | ||
| 121 | // `set_treq:sel` | ||
| 122 | w.0 = ((dreq as u32) & 0x3f) << 15usize; | ||
| 98 | w.set_data_size(data_size); | 123 | w.set_data_size(data_size); |
| 99 | w.set_incr_read(incr_read); | 124 | w.set_incr_read(incr_read); |
| 100 | w.set_incr_write(incr_write); | 125 | w.set_incr_write(incr_write); |
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart.rs index 9d94dcf21..4a3c7a0ce 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart.rs | |||
| @@ -113,7 +113,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||
| 113 | 113 | ||
| 114 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 114 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 115 | let r = T::regs(); | 115 | let r = T::regs(); |
| 116 | unsafe { while r.uartfr().read().txff() {} } | 116 | unsafe { while !r.uartfr().read().txfe() {} } |
| 117 | Ok(()) | 117 | Ok(()) |
| 118 | } | 118 | } |
| 119 | } | 119 | } |
| @@ -127,7 +127,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> { | |||
| 127 | }); | 127 | }); |
| 128 | // If we don't assign future to a variable, the data register pointer | 128 | // If we don't assign future to a variable, the data register pointer |
| 129 | // is held across an await and makes the future non-Send. | 129 | // is held across an await and makes the future non-Send. |
| 130 | crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _) | 130 | crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) |
| 131 | }; | 131 | }; |
| 132 | transfer.await; | 132 | transfer.await; |
| 133 | Ok(()) | 133 | Ok(()) |
| @@ -147,6 +147,10 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 147 | unsafe { | 147 | unsafe { |
| 148 | for b in buffer { | 148 | for b in buffer { |
| 149 | *b = loop { | 149 | *b = loop { |
| 150 | if r.uartfr().read().rxfe() { | ||
| 151 | continue; | ||
| 152 | } | ||
| 153 | |||
| 150 | let dr = r.uartdr().read(); | 154 | let dr = r.uartdr().read(); |
| 151 | 155 | ||
| 152 | if dr.oe() { | 156 | if dr.oe() { |
| @@ -157,7 +161,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 157 | return Err(Error::Parity); | 161 | return Err(Error::Parity); |
| 158 | } else if dr.fe() { | 162 | } else if dr.fe() { |
| 159 | return Err(Error::Framing); | 163 | return Err(Error::Framing); |
| 160 | } else if dr.fe() { | 164 | } else { |
| 161 | break dr.data(); | 165 | break dr.data(); |
| 162 | } | 166 | } |
| 163 | }; | 167 | }; |
| @@ -176,7 +180,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 176 | }); | 180 | }); |
| 177 | // If we don't assign future to a variable, the data register pointer | 181 | // If we don't assign future to a variable, the data register pointer |
| 178 | // is held across an await and makes the future non-Send. | 182 | // is held across an await and makes the future non-Send. |
| 179 | crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer) | 183 | crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) |
| 180 | }; | 184 | }; |
| 181 | transfer.await; | 185 | transfer.await; |
| 182 | Ok(()) | 186 | Ok(()) |
| @@ -282,6 +286,30 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||
| 282 | unsafe { | 286 | unsafe { |
| 283 | let r = T::regs(); | 287 | let r = T::regs(); |
| 284 | 288 | ||
| 289 | tx.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 290 | rx.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 291 | |||
| 292 | tx.pad_ctrl().write(|w| { | ||
| 293 | w.set_ie(true); | ||
| 294 | }); | ||
| 295 | |||
| 296 | rx.pad_ctrl().write(|w| { | ||
| 297 | w.set_ie(true); | ||
| 298 | }); | ||
| 299 | |||
| 300 | if let Some(pin) = &cts { | ||
| 301 | pin.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 302 | pin.pad_ctrl().write(|w| { | ||
| 303 | w.set_ie(true); | ||
| 304 | }); | ||
| 305 | } | ||
| 306 | if let Some(pin) = &rts { | ||
| 307 | pin.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 308 | pin.pad_ctrl().write(|w| { | ||
| 309 | w.set_ie(true); | ||
| 310 | }); | ||
| 311 | } | ||
| 312 | |||
| 285 | let clk_base = crate::clocks::clk_peri_freq(); | 313 | let clk_base = crate::clocks::clk_peri_freq(); |
| 286 | 314 | ||
| 287 | let baud_rate_div = (8 * clk_base) / config.baudrate; | 315 | let baud_rate_div = (8 * clk_base) / config.baudrate; |
| @@ -302,10 +330,14 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||
| 302 | 330 | ||
| 303 | let (pen, eps) = match config.parity { | 331 | let (pen, eps) = match config.parity { |
| 304 | Parity::ParityNone => (false, false), | 332 | Parity::ParityNone => (false, false), |
| 305 | Parity::ParityEven => (true, true), | ||
| 306 | Parity::ParityOdd => (true, false), | 333 | Parity::ParityOdd => (true, false), |
| 334 | Parity::ParityEven => (true, true), | ||
| 307 | }; | 335 | }; |
| 308 | 336 | ||
| 337 | // PL011 needs a (dummy) line control register write to latch in the | ||
| 338 | // divisors. We don't want to actually change LCR contents here. | ||
| 339 | r.uartlcr_h().modify(|_| {}); | ||
| 340 | |||
| 309 | r.uartlcr_h().write(|w| { | 341 | r.uartlcr_h().write(|w| { |
| 310 | w.set_wlen(config.data_bits.bits()); | 342 | w.set_wlen(config.data_bits.bits()); |
| 311 | w.set_stp2(config.stop_bits == StopBits::STOP2); | 343 | w.set_stp2(config.stop_bits == StopBits::STOP2); |
| @@ -321,15 +353,6 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||
| 321 | w.set_ctsen(cts.is_some()); | 353 | w.set_ctsen(cts.is_some()); |
| 322 | w.set_rtsen(rts.is_some()); | 354 | w.set_rtsen(rts.is_some()); |
| 323 | }); | 355 | }); |
| 324 | |||
| 325 | tx.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 326 | rx.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 327 | if let Some(pin) = &cts { | ||
| 328 | pin.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 329 | } | ||
| 330 | if let Some(pin) = &rts { | ||
| 331 | pin.io().ctrl().write(|w| w.set_funcsel(2)); | ||
| 332 | } | ||
| 333 | } | 356 | } |
| 334 | 357 | ||
| 335 | Self { | 358 | Self { |
| @@ -377,6 +400,10 @@ mod eh02 { | |||
| 377 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 400 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 378 | let r = T::regs(); | 401 | let r = T::regs(); |
| 379 | unsafe { | 402 | unsafe { |
| 403 | if r.uartfr().read().rxfe() { | ||
| 404 | return Err(nb::Error::WouldBlock); | ||
| 405 | } | ||
| 406 | |||
| 380 | let dr = r.uartdr().read(); | 407 | let dr = r.uartdr().read(); |
| 381 | 408 | ||
| 382 | if dr.oe() { | 409 | if dr.oe() { |
| @@ -387,10 +414,8 @@ mod eh02 { | |||
| 387 | Err(nb::Error::Other(Error::Parity)) | 414 | Err(nb::Error::Other(Error::Parity)) |
| 388 | } else if dr.fe() { | 415 | } else if dr.fe() { |
| 389 | Err(nb::Error::Other(Error::Framing)) | 416 | Err(nb::Error::Other(Error::Framing)) |
| 390 | } else if dr.fe() { | ||
| 391 | Ok(dr.data()) | ||
| 392 | } else { | 417 | } else { |
| 393 | Err(nb::Error::WouldBlock) | 418 | Ok(dr.data()) |
| 394 | } | 419 | } |
| 395 | } | 420 | } |
| 396 | } | 421 | } |
| @@ -512,6 +537,9 @@ mod sealed { | |||
| 512 | pub trait Mode {} | 537 | pub trait Mode {} |
| 513 | 538 | ||
| 514 | pub trait Instance { | 539 | pub trait Instance { |
| 540 | const TX_DREQ: u8; | ||
| 541 | const RX_DREQ: u8; | ||
| 542 | |||
| 515 | fn regs() -> pac::uart::Uart; | 543 | fn regs() -> pac::uart::Uart; |
| 516 | } | 544 | } |
| 517 | pub trait TxPin<T: Instance> {} | 545 | pub trait TxPin<T: Instance> {} |
| @@ -538,8 +566,11 @@ impl_mode!(Async); | |||
| 538 | pub trait Instance: sealed::Instance {} | 566 | pub trait Instance: sealed::Instance {} |
| 539 | 567 | ||
| 540 | macro_rules! impl_instance { | 568 | macro_rules! impl_instance { |
| 541 | ($inst:ident, $irq:ident) => { | 569 | ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { |
| 542 | impl sealed::Instance for peripherals::$inst { | 570 | impl sealed::Instance for peripherals::$inst { |
| 571 | const TX_DREQ: u8 = $tx_dreq; | ||
| 572 | const RX_DREQ: u8 = $rx_dreq; | ||
| 573 | |||
| 543 | fn regs() -> pac::uart::Uart { | 574 | fn regs() -> pac::uart::Uart { |
| 544 | pac::$inst | 575 | pac::$inst |
| 545 | } | 576 | } |
| @@ -548,8 +579,8 @@ macro_rules! impl_instance { | |||
| 548 | }; | 579 | }; |
| 549 | } | 580 | } |
| 550 | 581 | ||
| 551 | impl_instance!(UART0, UART0); | 582 | impl_instance!(UART0, UART0, 20, 21); |
| 552 | impl_instance!(UART1, UART1); | 583 | impl_instance!(UART1, UART1, 22, 23); |
| 553 | 584 | ||
| 554 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | 585 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} |
| 555 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | 586 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} |
diff --git a/tests/rp/src/bin/dma_copy_async.rs b/tests/rp/src/bin/dma_copy_async.rs new file mode 100644 index 000000000..c53f644bd --- /dev/null +++ b/tests/rp/src/bin/dma_copy_async.rs | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::dma::copy; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_rp::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | // Check `u8` copy | ||
| 16 | { | ||
| 17 | let data: [u8; 2] = [0xC0, 0xDE]; | ||
| 18 | let mut buf = [0; 2]; | ||
| 19 | unsafe { copy(p.DMA_CH0, &data, &mut buf).await }; | ||
| 20 | assert_eq!(buf, data); | ||
| 21 | } | ||
| 22 | |||
| 23 | // Check `u16` copy | ||
| 24 | { | ||
| 25 | let data: [u16; 2] = [0xC0BE, 0xDEAD]; | ||
| 26 | let mut buf = [0; 2]; | ||
| 27 | unsafe { copy(p.DMA_CH1, &data, &mut buf).await }; | ||
| 28 | assert_eq!(buf, data); | ||
| 29 | } | ||
| 30 | |||
| 31 | // Check `u32` copy | ||
| 32 | { | ||
| 33 | let data: [u32; 2] = [0xC0BEDEAD, 0xDEADAAFF]; | ||
| 34 | let mut buf = [0; 2]; | ||
| 35 | unsafe { copy(p.DMA_CH2, &data, &mut buf).await }; | ||
| 36 | assert_eq!(buf, data); | ||
| 37 | } | ||
| 38 | |||
| 39 | info!("Test OK"); | ||
| 40 | cortex_m::asm::bkpt(); | ||
| 41 | } | ||
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs new file mode 100644 index 000000000..92f61464e --- /dev/null +++ b/tests/rp/src/bin/uart.rs | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::uart::{Config, Uart}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_rp::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 16 | |||
| 17 | let config = Config::default(); | ||
| 18 | let mut uart = Uart::new_blocking(uart, tx, rx, config); | ||
| 19 | |||
| 20 | // We can't send too many bytes, they have to fit in the FIFO. | ||
| 21 | // This is because we aren't sending+receiving at the same time. | ||
| 22 | |||
| 23 | let data = [0xC0, 0xDE]; | ||
| 24 | uart.blocking_write(&data).unwrap(); | ||
| 25 | |||
| 26 | let mut buf = [0; 2]; | ||
| 27 | uart.blocking_read(&mut buf).unwrap(); | ||
| 28 | assert_eq!(buf, data); | ||
| 29 | |||
| 30 | info!("Test OK"); | ||
| 31 | cortex_m::asm::bkpt(); | ||
| 32 | } | ||
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs new file mode 100644 index 000000000..963c22707 --- /dev/null +++ b/tests/rp/src/bin/uart_dma.rs | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::uart::{Config, Uart}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_rp::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 16 | |||
| 17 | let config = Config::default(); | ||
| 18 | let mut uart = Uart::new(uart, tx, rx, p.DMA_CH0, p.DMA_CH1, config); | ||
| 19 | |||
| 20 | // We can't send too many bytes, they have to fit in the FIFO. | ||
| 21 | // This is because we aren't sending+receiving at the same time. | ||
| 22 | |||
| 23 | let data = [0xC0, 0xDE]; | ||
| 24 | uart.write(&data).await.unwrap(); | ||
| 25 | |||
| 26 | let mut buf = [0; 2]; | ||
| 27 | uart.read(&mut buf).await.unwrap(); | ||
| 28 | assert_eq!(buf, data); | ||
| 29 | |||
| 30 | info!("Test OK"); | ||
| 31 | cortex_m::asm::bkpt(); | ||
| 32 | } | ||
