Add HIL tests of DMA & UART, and correctly set DREQ for uart DMA
This commit is contained in:
		| @@ -41,18 +41,38 @@ pub unsafe fn read<'a, C: Channel, W: Word>( | |||||||
|     ch: impl Peripheral<P = C> + 'a, |     ch: impl Peripheral<P = C> + 'a, | ||||||
|     from: *const W, |     from: *const W, | ||||||
|     to: &mut [W], |     to: &mut [W], | ||||||
|  |     dreq: u8, | ||||||
| ) -> Transfer<'a, C> { | ) -> Transfer<'a, C> { | ||||||
|     let (ptr, len) = crate::dma::slice_ptr_parts_mut(to); |     let (to_ptr, len) = crate::dma::slice_ptr_parts_mut(to); | ||||||
|     copy_inner(ch, from as *const u32, ptr as *mut u32, len, W::size(), false, true) |     copy_inner( | ||||||
|  |         ch, | ||||||
|  |         from as *const u32, | ||||||
|  |         to_ptr as *mut u32, | ||||||
|  |         len, | ||||||
|  |         W::size(), | ||||||
|  |         false, | ||||||
|  |         true, | ||||||
|  |         dreq, | ||||||
|  |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub unsafe fn write<'a, C: Channel, W: Word>( | pub unsafe fn write<'a, C: Channel, W: Word>( | ||||||
|     ch: impl Peripheral<P = C> + 'a, |     ch: impl Peripheral<P = C> + 'a, | ||||||
|     from: &[W], |     from: &[W], | ||||||
|     to: *mut W, |     to: *mut W, | ||||||
|  |     dreq: u8, | ||||||
| ) -> Transfer<'a, C> { | ) -> Transfer<'a, C> { | ||||||
|     let (from_ptr, len) = crate::dma::slice_ptr_parts(from); |     let (from_ptr, len) = crate::dma::slice_ptr_parts(from); | ||||||
|     copy_inner(ch, from_ptr as *const u32, to as *mut u32, len, W::size(), true, false) |     copy_inner( | ||||||
|  |         ch, | ||||||
|  |         from_ptr as *const u32, | ||||||
|  |         to as *mut u32, | ||||||
|  |         len, | ||||||
|  |         W::size(), | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         dreq, | ||||||
|  |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub unsafe fn copy<'a, C: Channel, W: Word>( | pub unsafe fn copy<'a, C: Channel, W: Word>( | ||||||
| @@ -71,6 +91,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>( | |||||||
|         W::size(), |         W::size(), | ||||||
|         true, |         true, | ||||||
|         true, |         true, | ||||||
|  |         vals::TreqSel::PERMANENT.0, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -82,6 +103,7 @@ fn copy_inner<'a, C: Channel>( | |||||||
|     data_size: DataSize, |     data_size: DataSize, | ||||||
|     incr_read: bool, |     incr_read: bool, | ||||||
|     incr_write: bool, |     incr_write: bool, | ||||||
|  |     dreq: u8, | ||||||
| ) -> Transfer<'a, C> { | ) -> Transfer<'a, C> { | ||||||
|     into_ref!(ch); |     into_ref!(ch); | ||||||
|  |  | ||||||
| @@ -95,6 +117,9 @@ fn copy_inner<'a, C: Channel>( | |||||||
|         compiler_fence(Ordering::SeqCst); |         compiler_fence(Ordering::SeqCst); | ||||||
|  |  | ||||||
|         p.ctrl_trig().write(|w| { |         p.ctrl_trig().write(|w| { | ||||||
|  |             // TODO: Add all DREQ options to pac vals::TreqSel, and use | ||||||
|  |             // `set_treq:sel` | ||||||
|  |             w.0 = ((dreq as u32) & 0x3f) << 15usize; | ||||||
|             w.set_data_size(data_size); |             w.set_data_size(data_size); | ||||||
|             w.set_incr_read(incr_read); |             w.set_incr_read(incr_read); | ||||||
|             w.set_incr_write(incr_write); |             w.set_incr_write(incr_write); | ||||||
|   | |||||||
| @@ -113,7 +113,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||||||
|  |  | ||||||
|     pub fn blocking_flush(&mut self) -> Result<(), Error> { |     pub fn blocking_flush(&mut self) -> Result<(), Error> { | ||||||
|         let r = T::regs(); |         let r = T::regs(); | ||||||
|         unsafe { while r.uartfr().read().txff() {} } |         unsafe { while !r.uartfr().read().txfe() {} } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -127,7 +127,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> { | |||||||
|             }); |             }); | ||||||
|             // If we don't assign future to a variable, the data register pointer |             // If we don't assign future to a variable, the data register pointer | ||||||
|             // is held across an await and makes the future non-Send. |             // is held across an await and makes the future non-Send. | ||||||
|             crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _) |             crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) | ||||||
|         }; |         }; | ||||||
|         transfer.await; |         transfer.await; | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @@ -147,6 +147,10 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||||||
|         unsafe { |         unsafe { | ||||||
|             for b in buffer { |             for b in buffer { | ||||||
|                 *b = loop { |                 *b = loop { | ||||||
|  |                     if r.uartfr().read().rxfe() { | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                     let dr = r.uartdr().read(); |                     let dr = r.uartdr().read(); | ||||||
|  |  | ||||||
|                     if dr.oe() { |                     if dr.oe() { | ||||||
| @@ -157,7 +161,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||||||
|                         return Err(Error::Parity); |                         return Err(Error::Parity); | ||||||
|                     } else if dr.fe() { |                     } else if dr.fe() { | ||||||
|                         return Err(Error::Framing); |                         return Err(Error::Framing); | ||||||
|                     } else if dr.fe() { |                     } else { | ||||||
|                         break dr.data(); |                         break dr.data(); | ||||||
|                     } |                     } | ||||||
|                 }; |                 }; | ||||||
| @@ -176,7 +180,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||||||
|             }); |             }); | ||||||
|             // If we don't assign future to a variable, the data register pointer |             // If we don't assign future to a variable, the data register pointer | ||||||
|             // is held across an await and makes the future non-Send. |             // is held across an await and makes the future non-Send. | ||||||
|             crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer) |             crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) | ||||||
|         }; |         }; | ||||||
|         transfer.await; |         transfer.await; | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @@ -282,6 +286,30 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||||||
|         unsafe { |         unsafe { | ||||||
|             let r = T::regs(); |             let r = T::regs(); | ||||||
|  |  | ||||||
|  |             tx.io().ctrl().write(|w| w.set_funcsel(2)); | ||||||
|  |             rx.io().ctrl().write(|w| w.set_funcsel(2)); | ||||||
|  |  | ||||||
|  |             tx.pad_ctrl().write(|w| { | ||||||
|  |                 w.set_ie(true); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             rx.pad_ctrl().write(|w| { | ||||||
|  |                 w.set_ie(true); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             if let Some(pin) = &cts { | ||||||
|  |                 pin.io().ctrl().write(|w| w.set_funcsel(2)); | ||||||
|  |                 pin.pad_ctrl().write(|w| { | ||||||
|  |                     w.set_ie(true); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             if let Some(pin) = &rts { | ||||||
|  |                 pin.io().ctrl().write(|w| w.set_funcsel(2)); | ||||||
|  |                 pin.pad_ctrl().write(|w| { | ||||||
|  |                     w.set_ie(true); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             let clk_base = crate::clocks::clk_peri_freq(); |             let clk_base = crate::clocks::clk_peri_freq(); | ||||||
|  |  | ||||||
|             let baud_rate_div = (8 * clk_base) / config.baudrate; |             let baud_rate_div = (8 * clk_base) / config.baudrate; | ||||||
| @@ -302,10 +330,14 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||||||
|  |  | ||||||
|             let (pen, eps) = match config.parity { |             let (pen, eps) = match config.parity { | ||||||
|                 Parity::ParityNone => (false, false), |                 Parity::ParityNone => (false, false), | ||||||
|                 Parity::ParityEven => (true, true), |  | ||||||
|                 Parity::ParityOdd => (true, false), |                 Parity::ParityOdd => (true, false), | ||||||
|  |                 Parity::ParityEven => (true, true), | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|  |             // PL011 needs a (dummy) line control register write to latch in the | ||||||
|  |             // divisors. We don't want to actually change LCR contents here. | ||||||
|  |             r.uartlcr_h().modify(|_| {}); | ||||||
|  |  | ||||||
|             r.uartlcr_h().write(|w| { |             r.uartlcr_h().write(|w| { | ||||||
|                 w.set_wlen(config.data_bits.bits()); |                 w.set_wlen(config.data_bits.bits()); | ||||||
|                 w.set_stp2(config.stop_bits == StopBits::STOP2); |                 w.set_stp2(config.stop_bits == StopBits::STOP2); | ||||||
| @@ -321,15 +353,6 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||||||
|                 w.set_ctsen(cts.is_some()); |                 w.set_ctsen(cts.is_some()); | ||||||
|                 w.set_rtsen(rts.is_some()); |                 w.set_rtsen(rts.is_some()); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             tx.io().ctrl().write(|w| w.set_funcsel(2)); |  | ||||||
|             rx.io().ctrl().write(|w| w.set_funcsel(2)); |  | ||||||
|             if let Some(pin) = &cts { |  | ||||||
|                 pin.io().ctrl().write(|w| w.set_funcsel(2)); |  | ||||||
|             } |  | ||||||
|             if let Some(pin) = &rts { |  | ||||||
|                 pin.io().ctrl().write(|w| w.set_funcsel(2)); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Self { |         Self { | ||||||
| @@ -377,6 +400,10 @@ mod eh02 { | |||||||
|         fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |         fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | ||||||
|             let r = T::regs(); |             let r = T::regs(); | ||||||
|             unsafe { |             unsafe { | ||||||
|  |                 if r.uartfr().read().rxfe() { | ||||||
|  |                     return Err(nb::Error::WouldBlock); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 let dr = r.uartdr().read(); |                 let dr = r.uartdr().read(); | ||||||
|  |  | ||||||
|                 if dr.oe() { |                 if dr.oe() { | ||||||
| @@ -387,10 +414,8 @@ mod eh02 { | |||||||
|                     Err(nb::Error::Other(Error::Parity)) |                     Err(nb::Error::Other(Error::Parity)) | ||||||
|                 } else if dr.fe() { |                 } else if dr.fe() { | ||||||
|                     Err(nb::Error::Other(Error::Framing)) |                     Err(nb::Error::Other(Error::Framing)) | ||||||
|                 } else if dr.fe() { |  | ||||||
|                     Ok(dr.data()) |  | ||||||
|                 } else { |                 } else { | ||||||
|                     Err(nb::Error::WouldBlock) |                     Ok(dr.data()) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -512,6 +537,9 @@ mod sealed { | |||||||
|     pub trait Mode {} |     pub trait Mode {} | ||||||
|  |  | ||||||
|     pub trait Instance { |     pub trait Instance { | ||||||
|  |         const TX_DREQ: u8; | ||||||
|  |         const RX_DREQ: u8; | ||||||
|  |  | ||||||
|         fn regs() -> pac::uart::Uart; |         fn regs() -> pac::uart::Uart; | ||||||
|     } |     } | ||||||
|     pub trait TxPin<T: Instance> {} |     pub trait TxPin<T: Instance> {} | ||||||
| @@ -538,8 +566,11 @@ impl_mode!(Async); | |||||||
| pub trait Instance: sealed::Instance {} | pub trait Instance: sealed::Instance {} | ||||||
|  |  | ||||||
| macro_rules! impl_instance { | macro_rules! impl_instance { | ||||||
|     ($inst:ident, $irq:ident) => { |     ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { | ||||||
|         impl sealed::Instance for peripherals::$inst { |         impl sealed::Instance for peripherals::$inst { | ||||||
|  |             const TX_DREQ: u8 = $tx_dreq; | ||||||
|  |             const RX_DREQ: u8 = $rx_dreq; | ||||||
|  |  | ||||||
|             fn regs() -> pac::uart::Uart { |             fn regs() -> pac::uart::Uart { | ||||||
|                 pac::$inst |                 pac::$inst | ||||||
|             } |             } | ||||||
| @@ -548,8 +579,8 @@ macro_rules! impl_instance { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl_instance!(UART0, UART0); | impl_instance!(UART0, UART0, 20, 21); | ||||||
| impl_instance!(UART1, UART1); | impl_instance!(UART1, UART1, 22, 23); | ||||||
|  |  | ||||||
| pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | ||||||
| pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								tests/rp/src/bin/dma_copy_async.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/rp/src/bin/dma_copy_async.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | #![feature(type_alias_impl_trait)] | ||||||
|  |  | ||||||
|  | use defmt::{assert_eq, *}; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_rp::dma::copy; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  |  | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_rp::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  |  | ||||||
|  |     // Check `u8` copy | ||||||
|  |     { | ||||||
|  |         let data: [u8; 2] = [0xC0, 0xDE]; | ||||||
|  |         let mut buf = [0; 2]; | ||||||
|  |         unsafe { copy(p.DMA_CH0, &data, &mut buf).await }; | ||||||
|  |         assert_eq!(buf, data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Check `u16` copy | ||||||
|  |     { | ||||||
|  |         let data: [u16; 2] = [0xC0BE, 0xDEAD]; | ||||||
|  |         let mut buf = [0; 2]; | ||||||
|  |         unsafe { copy(p.DMA_CH1, &data, &mut buf).await }; | ||||||
|  |         assert_eq!(buf, data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Check `u32` copy | ||||||
|  |     { | ||||||
|  |         let data: [u32; 2] = [0xC0BEDEAD, 0xDEADAAFF]; | ||||||
|  |         let mut buf = [0; 2]; | ||||||
|  |         unsafe { copy(p.DMA_CH2, &data, &mut buf).await }; | ||||||
|  |         assert_eq!(buf, data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     info!("Test OK"); | ||||||
|  |     cortex_m::asm::bkpt(); | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								tests/rp/src/bin/uart.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/rp/src/bin/uart.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | #![feature(type_alias_impl_trait)] | ||||||
|  |  | ||||||
|  | use defmt::{assert_eq, *}; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_rp::uart::{Config, Uart}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  |  | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_rp::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  |  | ||||||
|  |     let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||||||
|  |  | ||||||
|  |     let config = Config::default(); | ||||||
|  |     let mut uart = Uart::new_blocking(uart, tx, rx, config); | ||||||
|  |  | ||||||
|  |     // We can't send too many bytes, they have to fit in the FIFO. | ||||||
|  |     // This is because we aren't sending+receiving at the same time. | ||||||
|  |  | ||||||
|  |     let data = [0xC0, 0xDE]; | ||||||
|  |     uart.blocking_write(&data).unwrap(); | ||||||
|  |  | ||||||
|  |     let mut buf = [0; 2]; | ||||||
|  |     uart.blocking_read(&mut buf).unwrap(); | ||||||
|  |     assert_eq!(buf, data); | ||||||
|  |  | ||||||
|  |     info!("Test OK"); | ||||||
|  |     cortex_m::asm::bkpt(); | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								tests/rp/src/bin/uart_dma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/rp/src/bin/uart_dma.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | #![feature(type_alias_impl_trait)] | ||||||
|  |  | ||||||
|  | use defmt::{assert_eq, *}; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_rp::uart::{Config, Uart}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  |  | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_rp::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  |  | ||||||
|  |     let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||||||
|  |  | ||||||
|  |     let config = Config::default(); | ||||||
|  |     let mut uart = Uart::new(uart, tx, rx, p.DMA_CH0, p.DMA_CH1, config); | ||||||
|  |  | ||||||
|  |     // We can't send too many bytes, they have to fit in the FIFO. | ||||||
|  |     // This is because we aren't sending+receiving at the same time. | ||||||
|  |  | ||||||
|  |     let data = [0xC0, 0xDE]; | ||||||
|  |     uart.write(&data).await.unwrap(); | ||||||
|  |  | ||||||
|  |     let mut buf = [0; 2]; | ||||||
|  |     uart.read(&mut buf).await.unwrap(); | ||||||
|  |     assert_eq!(buf, data); | ||||||
|  |  | ||||||
|  |     info!("Test OK"); | ||||||
|  |     cortex_m::asm::bkpt(); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user