diff options
| author | Quentin Smith <[email protected]> | 2023-07-17 21:31:43 -0400 |
|---|---|---|
| committer | Quentin Smith <[email protected]> | 2023-07-17 21:31:43 -0400 |
| commit | 6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch) | |
| tree | 748f510e190bb2724750507a6e69ed1a8e08cb20 /tests/rp/src | |
| parent | d896f80405aa8963877049ed999e4aba25d6e2bb (diff) | |
| parent | 6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff) | |
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'tests/rp/src')
| -rw-r--r-- | tests/rp/src/bin/adc.rs | 86 | ||||
| -rw-r--r-- | tests/rp/src/bin/cyw43-perf.rs | 264 | ||||
| -rw-r--r-- | tests/rp/src/bin/dma_copy_async.rs | 43 | ||||
| -rw-r--r-- | tests/rp/src/bin/flash.rs | 65 | ||||
| -rw-r--r-- | tests/rp/src/bin/float.rs | 53 | ||||
| -rw-r--r-- | tests/rp/src/bin/gpio.rs | 66 | ||||
| -rw-r--r-- | tests/rp/src/bin/gpio_async.rs | 4 | ||||
| -rw-r--r-- | tests/rp/src/bin/gpio_multicore.rs | 65 | ||||
| -rw-r--r-- | tests/rp/src/bin/multicore.rs | 49 | ||||
| -rw-r--r-- | tests/rp/src/bin/pio_irq.rs | 55 | ||||
| -rw-r--r-- | tests/rp/src/bin/pwm.rs | 144 | ||||
| -rw-r--r-- | tests/rp/src/bin/spi.rs | 30 | ||||
| -rw-r--r-- | tests/rp/src/bin/spi_async.rs | 86 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart.rs | 171 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart_buffered.rs | 256 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart_dma.rs | 252 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart_upgrade.rs | 60 | ||||
| -rw-r--r-- | tests/rp/src/common.rs | 1 |
18 files changed, 1744 insertions, 6 deletions
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs new file mode 100644 index 000000000..e659844ae --- /dev/null +++ b/tests/rp/src/bin/adc.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin}; | ||
| 10 | use embassy_rp::bind_interrupts; | ||
| 11 | use embassy_rp::gpio::Pull; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 16 | }); | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async fn main(_spawner: Spawner) { | ||
| 20 | let mut p = embassy_rp::init(Default::default()); | ||
| 21 | let mut adc = Adc::new(p.ADC, Irqs, Config::default()); | ||
| 22 | |||
| 23 | { | ||
| 24 | { | ||
| 25 | let mut p = Pin::new(&mut p.PIN_26, Pull::Down); | ||
| 26 | defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); | ||
| 27 | defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | let mut p = Pin::new(&mut p.PIN_26, Pull::Up); | ||
| 31 | defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); | ||
| 32 | defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | // not bothering with async reads from now on | ||
| 36 | { | ||
| 37 | { | ||
| 38 | let mut p = Pin::new(&mut p.PIN_27, Pull::Down); | ||
| 39 | defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); | ||
| 40 | } | ||
| 41 | { | ||
| 42 | let mut p = Pin::new(&mut p.PIN_27, Pull::Up); | ||
| 43 | defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | { | ||
| 47 | { | ||
| 48 | let mut p = Pin::new(&mut p.PIN_28, Pull::Down); | ||
| 49 | defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); | ||
| 50 | } | ||
| 51 | { | ||
| 52 | let mut p = Pin::new(&mut p.PIN_28, Pull::Up); | ||
| 53 | defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | { | ||
| 57 | // gp29 is connected to vsys through a 200k/100k divider, | ||
| 58 | // adding pulls should change the value | ||
| 59 | let low = { | ||
| 60 | let mut p = Pin::new(&mut p.PIN_29, Pull::Down); | ||
| 61 | adc.blocking_read(&mut p).unwrap() | ||
| 62 | }; | ||
| 63 | let none = { | ||
| 64 | let mut p = Pin::new(&mut p.PIN_29, Pull::None); | ||
| 65 | adc.blocking_read(&mut p).unwrap() | ||
| 66 | }; | ||
| 67 | let up = { | ||
| 68 | let mut p = Pin::new(&mut p.PIN_29, Pull::Up); | ||
| 69 | adc.blocking_read(&mut p).unwrap() | ||
| 70 | }; | ||
| 71 | defmt::assert!(low < none); | ||
| 72 | defmt::assert!(none < up); | ||
| 73 | } | ||
| 74 | |||
| 75 | let temp = convert_to_celsius(adc.read_temperature().await.unwrap()); | ||
| 76 | defmt::assert!(temp > 0.0); | ||
| 77 | defmt::assert!(temp < 60.0); | ||
| 78 | |||
| 79 | info!("Test OK"); | ||
| 80 | cortex_m::asm::bkpt(); | ||
| 81 | } | ||
| 82 | |||
| 83 | fn convert_to_celsius(raw_temp: u16) -> f32 { | ||
| 84 | // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet | ||
| 85 | 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721 as f32 | ||
| 86 | } | ||
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs new file mode 100644 index 000000000..bc127e2e5 --- /dev/null +++ b/tests/rp/src/bin/cyw43-perf.rs | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use cyw43_pio::PioSpi; | ||
| 8 | use defmt::{assert, panic, *}; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_futures::join::join; | ||
| 11 | use embassy_net::tcp::TcpSocket; | ||
| 12 | use embassy_net::{Config, Ipv4Address, Stack, StackResources}; | ||
| 13 | use embassy_rp::gpio::{Level, Output}; | ||
| 14 | use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; | ||
| 15 | use embassy_rp::pio::{InterruptHandler, Pio}; | ||
| 16 | use embassy_rp::{bind_interrupts, rom_data}; | ||
| 17 | use embassy_time::{with_timeout, Duration, Timer}; | ||
| 18 | use static_cell::make_static; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | bind_interrupts!(struct Irqs { | ||
| 22 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 23 | }); | ||
| 24 | |||
| 25 | teleprobe_meta::timeout!(120); | ||
| 26 | |||
| 27 | #[embassy_executor::task] | ||
| 28 | async fn wifi_task( | ||
| 29 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, | ||
| 30 | ) -> ! { | ||
| 31 | runner.run().await | ||
| 32 | } | ||
| 33 | |||
| 34 | #[embassy_executor::task] | ||
| 35 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | ||
| 36 | stack.run().await | ||
| 37 | } | ||
| 38 | |||
| 39 | #[embassy_executor::main] | ||
| 40 | async fn main(spawner: Spawner) { | ||
| 41 | info!("Hello World!"); | ||
| 42 | let p = embassy_rp::init(Default::default()); | ||
| 43 | |||
| 44 | // needed for reading the firmware from flash via XIP. | ||
| 45 | unsafe { | ||
| 46 | rom_data::flash_exit_xip(); | ||
| 47 | rom_data::flash_enter_cmd_xip(); | ||
| 48 | } | ||
| 49 | |||
| 50 | // cyw43 firmware needs to be flashed manually: | ||
| 51 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000 | ||
| 52 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000 | ||
| 53 | let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) }; | ||
| 54 | let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) }; | ||
| 55 | |||
| 56 | let pwr = Output::new(p.PIN_23, Level::Low); | ||
| 57 | let cs = Output::new(p.PIN_25, Level::High); | ||
| 58 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 59 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | ||
| 60 | |||
| 61 | let state = make_static!(cyw43::State::new()); | ||
| 62 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | ||
| 63 | unwrap!(spawner.spawn(wifi_task(runner))); | ||
| 64 | |||
| 65 | control.init(clm).await; | ||
| 66 | control | ||
| 67 | .set_power_management(cyw43::PowerManagementMode::PowerSave) | ||
| 68 | .await; | ||
| 69 | |||
| 70 | // Generate random seed | ||
| 71 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | ||
| 72 | |||
| 73 | // Init network stack | ||
| 74 | let stack = &*make_static!(Stack::new( | ||
| 75 | net_device, | ||
| 76 | Config::dhcpv4(Default::default()), | ||
| 77 | make_static!(StackResources::<2>::new()), | ||
| 78 | seed | ||
| 79 | )); | ||
| 80 | |||
| 81 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 82 | |||
| 83 | loop { | ||
| 84 | match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { | ||
| 85 | Ok(_) => break, | ||
| 86 | Err(err) => { | ||
| 87 | panic!("join failed with status={}", err.status); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | info!("Waiting for DHCP up..."); | ||
| 93 | while stack.config_v4().is_none() { | ||
| 94 | Timer::after(Duration::from_millis(100)).await; | ||
| 95 | } | ||
| 96 | info!("IP addressing up!"); | ||
| 97 | |||
| 98 | let down = test_download(stack).await; | ||
| 99 | let up = test_upload(stack).await; | ||
| 100 | let updown = test_upload_download(stack).await; | ||
| 101 | |||
| 102 | assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); | ||
| 103 | assert!(up > TEST_EXPECTED_UPLOAD_KBPS); | ||
| 104 | assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); | ||
| 105 | |||
| 106 | info!("Test OK"); | ||
| 107 | cortex_m::asm::bkpt(); | ||
| 108 | } | ||
| 109 | |||
| 110 | // Test-only wifi network, no internet access! | ||
| 111 | const WIFI_NETWORK: &str = "EmbassyTest"; | ||
| 112 | const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; | ||
| 113 | |||
| 114 | const TEST_DURATION: usize = 10; | ||
| 115 | const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300; | ||
| 116 | const TEST_EXPECTED_UPLOAD_KBPS: usize = 300; | ||
| 117 | const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300; | ||
| 118 | const RX_BUFFER_SIZE: usize = 4096; | ||
| 119 | const TX_BUFFER_SIZE: usize = 4096; | ||
| 120 | const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); | ||
| 121 | const DOWNLOAD_PORT: u16 = 4321; | ||
| 122 | const UPLOAD_PORT: u16 = 4322; | ||
| 123 | const UPLOAD_DOWNLOAD_PORT: u16 = 4323; | ||
| 124 | |||
| 125 | async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 126 | info!("Testing download..."); | ||
| 127 | |||
| 128 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 129 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 130 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 131 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 132 | |||
| 133 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); | ||
| 134 | if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { | ||
| 135 | error!("connect error: {:?}", e); | ||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | info!("connected, testing..."); | ||
| 139 | |||
| 140 | let mut rx_buf = [0; 4096]; | ||
| 141 | let mut total: usize = 0; | ||
| 142 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 143 | loop { | ||
| 144 | match socket.read(&mut rx_buf).await { | ||
| 145 | Ok(0) => { | ||
| 146 | error!("read EOF"); | ||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | Ok(n) => total += n, | ||
| 150 | Err(e) => { | ||
| 151 | error!("read error: {:?}", e); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | }) | ||
| 157 | .await | ||
| 158 | .ok(); | ||
| 159 | |||
| 160 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 161 | info!("download: {} kB/s", kbps); | ||
| 162 | kbps | ||
| 163 | } | ||
| 164 | |||
| 165 | async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 166 | info!("Testing upload..."); | ||
| 167 | |||
| 168 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 169 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 170 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 171 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 172 | |||
| 173 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); | ||
| 174 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { | ||
| 175 | error!("connect error: {:?}", e); | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | info!("connected, testing..."); | ||
| 179 | |||
| 180 | let buf = [0; 4096]; | ||
| 181 | let mut total: usize = 0; | ||
| 182 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 183 | loop { | ||
| 184 | match socket.write(&buf).await { | ||
| 185 | Ok(0) => { | ||
| 186 | error!("write zero?!??!?!"); | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | Ok(n) => total += n, | ||
| 190 | Err(e) => { | ||
| 191 | error!("write error: {:?}", e); | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | }) | ||
| 197 | .await | ||
| 198 | .ok(); | ||
| 199 | |||
| 200 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 201 | info!("upload: {} kB/s", kbps); | ||
| 202 | kbps | ||
| 203 | } | ||
| 204 | |||
| 205 | async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 206 | info!("Testing upload+download..."); | ||
| 207 | |||
| 208 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 209 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 210 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 211 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 212 | |||
| 213 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); | ||
| 214 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { | ||
| 215 | error!("connect error: {:?}", e); | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | info!("connected, testing..."); | ||
| 219 | |||
| 220 | let (mut reader, mut writer) = socket.split(); | ||
| 221 | |||
| 222 | let tx_buf = [0; 4096]; | ||
| 223 | let mut rx_buf = [0; 4096]; | ||
| 224 | let mut total: usize = 0; | ||
| 225 | let tx_fut = async { | ||
| 226 | loop { | ||
| 227 | match writer.write(&tx_buf).await { | ||
| 228 | Ok(0) => { | ||
| 229 | error!("write zero?!??!?!"); | ||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | Ok(_) => {} | ||
| 233 | Err(e) => { | ||
| 234 | error!("write error: {:?}", e); | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | }; | ||
| 240 | |||
| 241 | let rx_fut = async { | ||
| 242 | loop { | ||
| 243 | match reader.read(&mut rx_buf).await { | ||
| 244 | Ok(0) => { | ||
| 245 | error!("read EOF"); | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | Ok(n) => total += n, | ||
| 249 | Err(e) => { | ||
| 250 | error!("read error: {:?}", e); | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | } | ||
| 255 | }; | ||
| 256 | |||
| 257 | with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) | ||
| 258 | .await | ||
| 259 | .ok(); | ||
| 260 | |||
| 261 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 262 | info!("upload+download: {} kB/s", kbps); | ||
| 263 | kbps | ||
| 264 | } | ||
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..2c0b559a9 --- /dev/null +++ b/tests/rp/src/bin/dma_copy_async.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert_eq, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::dma::copy; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_rp::init(Default::default()); | ||
| 15 | info!("Hello World!"); | ||
| 16 | |||
| 17 | // Check `u8` copy | ||
| 18 | { | ||
| 19 | let data: [u8; 2] = [0xC0, 0xDE]; | ||
| 20 | let mut buf = [0; 2]; | ||
| 21 | unsafe { copy(p.DMA_CH0, &data, &mut buf).await }; | ||
| 22 | assert_eq!(buf, data); | ||
| 23 | } | ||
| 24 | |||
| 25 | // Check `u16` copy | ||
| 26 | { | ||
| 27 | let data: [u16; 2] = [0xC0BE, 0xDEAD]; | ||
| 28 | let mut buf = [0; 2]; | ||
| 29 | unsafe { copy(p.DMA_CH1, &data, &mut buf).await }; | ||
| 30 | assert_eq!(buf, data); | ||
| 31 | } | ||
| 32 | |||
| 33 | // Check `u32` copy | ||
| 34 | { | ||
| 35 | let data: [u32; 2] = [0xC0BEDEAD, 0xDEADAAFF]; | ||
| 36 | let mut buf = [0; 2]; | ||
| 37 | unsafe { copy(p.DMA_CH2, &data, &mut buf).await }; | ||
| 38 | assert_eq!(buf, data); | ||
| 39 | } | ||
| 40 | |||
| 41 | info!("Test OK"); | ||
| 42 | cortex_m::asm::bkpt(); | ||
| 43 | } | ||
diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs new file mode 100644 index 000000000..cf9b86df5 --- /dev/null +++ b/tests/rp/src/bin/flash.rs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE}; | ||
| 10 | use embassy_time::{Duration, Timer}; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | const ADDR_OFFSET: u32 = 0x4000; | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async fn main(_spawner: Spawner) { | ||
| 17 | let p = embassy_rp::init(Default::default()); | ||
| 18 | info!("Hello World!"); | ||
| 19 | |||
| 20 | // add some delay to give an attached debug probe time to parse the | ||
| 21 | // defmt RTT header. Reading that header might touch flash memory, which | ||
| 22 | // interferes with flash write operations. | ||
| 23 | // https://github.com/knurling-rs/defmt/pull/683 | ||
| 24 | Timer::after(Duration::from_millis(10)).await; | ||
| 25 | |||
| 26 | let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH); | ||
| 27 | |||
| 28 | // Get JEDEC id | ||
| 29 | let jedec = defmt::unwrap!(flash.jedec_id()); | ||
| 30 | info!("jedec id: 0x{:x}", jedec); | ||
| 31 | |||
| 32 | // Get unique id | ||
| 33 | let mut uid = [0; 8]; | ||
| 34 | defmt::unwrap!(flash.unique_id(&mut uid)); | ||
| 35 | info!("unique id: {:?}", uid); | ||
| 36 | |||
| 37 | let mut buf = [0u8; ERASE_SIZE]; | ||
| 38 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | ||
| 39 | |||
| 40 | info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32); | ||
| 41 | info!("Contents start with {=[u8]}", buf[0..4]); | ||
| 42 | |||
| 43 | defmt::unwrap!(flash.erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32)); | ||
| 44 | |||
| 45 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | ||
| 46 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); | ||
| 47 | if buf.iter().any(|x| *x != 0xFF) { | ||
| 48 | defmt::panic!("unexpected"); | ||
| 49 | } | ||
| 50 | |||
| 51 | for b in buf.iter_mut() { | ||
| 52 | *b = 0xDA; | ||
| 53 | } | ||
| 54 | |||
| 55 | defmt::unwrap!(flash.write(ADDR_OFFSET, &mut buf)); | ||
| 56 | |||
| 57 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | ||
| 58 | info!("Contents after write starts with {=[u8]}", buf[0..4]); | ||
| 59 | if buf.iter().any(|x| *x != 0xDA) { | ||
| 60 | defmt::panic!("unexpected"); | ||
| 61 | } | ||
| 62 | |||
| 63 | info!("Test OK"); | ||
| 64 | cortex_m::asm::bkpt(); | ||
| 65 | } | ||
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs new file mode 100644 index 000000000..0e0de85fa --- /dev/null +++ b/tests/rp/src/bin/float.rs | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::pac; | ||
| 10 | use embassy_time::{Duration, Timer}; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | embassy_rp::init(Default::default()); | ||
| 16 | info!("Hello World!"); | ||
| 17 | |||
| 18 | const PI_F: f32 = 3.1415926535f32; | ||
| 19 | const PI_D: f64 = 3.14159265358979323846f64; | ||
| 20 | |||
| 21 | pac::BUSCTRL | ||
| 22 | .perfsel(0) | ||
| 23 | .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM)); | ||
| 24 | |||
| 25 | for i in 0..=360 { | ||
| 26 | let rad_f = (i as f32) * PI_F / 180.0; | ||
| 27 | info!( | ||
| 28 | "{}° float: {=f32} / {=f32} / {=f32} / {=f32}", | ||
| 29 | i, | ||
| 30 | rad_f, | ||
| 31 | rad_f - PI_F, | ||
| 32 | rad_f + PI_F, | ||
| 33 | rad_f % PI_F | ||
| 34 | ); | ||
| 35 | let rad_d = (i as f64) * PI_D / 180.0; | ||
| 36 | info!( | ||
| 37 | "{}° double: {=f64} / {=f64} / {=f64} / {=f64}", | ||
| 38 | i, | ||
| 39 | rad_d, | ||
| 40 | rad_d - PI_D, | ||
| 41 | rad_d + PI_D, | ||
| 42 | rad_d % PI_D | ||
| 43 | ); | ||
| 44 | Timer::after(Duration::from_millis(10)).await; | ||
| 45 | } | ||
| 46 | |||
| 47 | let rom_accesses = pac::BUSCTRL.perfctr(0).read().perfctr(); | ||
| 48 | // every float operation used here uses at least 10 cycles | ||
| 49 | defmt::assert!(rom_accesses >= 360 * 12 * 10); | ||
| 50 | |||
| 51 | info!("Test OK"); | ||
| 52 | cortex_m::asm::bkpt(); | ||
| 53 | } | ||
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index af22fe27d..946b7dc88 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 4 | 6 | ||
| 5 | use defmt::{assert, *}; | 7 | use defmt::{assert, *}; |
| 6 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| @@ -19,14 +21,46 @@ async fn main(_spawner: Spawner) { | |||
| 19 | let b = Input::new(&mut b, Pull::None); | 21 | let b = Input::new(&mut b, Pull::None); |
| 20 | 22 | ||
| 21 | { | 23 | { |
| 22 | let _a = Output::new(&mut a, Level::Low); | 24 | let a = Output::new(&mut a, Level::Low); |
| 23 | delay(); | 25 | delay(); |
| 24 | assert!(b.is_low()); | 26 | assert!(b.is_low()); |
| 27 | assert!(!b.is_high()); | ||
| 28 | assert!(a.is_set_low()); | ||
| 29 | assert!(!a.is_set_high()); | ||
| 25 | } | 30 | } |
| 26 | { | 31 | { |
| 27 | let _a = Output::new(&mut a, Level::High); | 32 | let mut a = Output::new(&mut a, Level::High); |
| 28 | delay(); | 33 | delay(); |
| 34 | assert!(!b.is_low()); | ||
| 29 | assert!(b.is_high()); | 35 | assert!(b.is_high()); |
| 36 | assert!(!a.is_set_low()); | ||
| 37 | assert!(a.is_set_high()); | ||
| 38 | |||
| 39 | // Test is_set_low / is_set_high | ||
| 40 | a.set_low(); | ||
| 41 | delay(); | ||
| 42 | assert!(b.is_low()); | ||
| 43 | assert!(a.is_set_low()); | ||
| 44 | assert!(!a.is_set_high()); | ||
| 45 | |||
| 46 | a.set_high(); | ||
| 47 | delay(); | ||
| 48 | assert!(b.is_high()); | ||
| 49 | assert!(!a.is_set_low()); | ||
| 50 | assert!(a.is_set_high()); | ||
| 51 | |||
| 52 | // Test toggle | ||
| 53 | a.toggle(); | ||
| 54 | delay(); | ||
| 55 | assert!(b.is_low()); | ||
| 56 | assert!(a.is_set_low()); | ||
| 57 | assert!(!a.is_set_high()); | ||
| 58 | |||
| 59 | a.toggle(); | ||
| 60 | delay(); | ||
| 61 | assert!(b.is_high()); | ||
| 62 | assert!(!a.is_set_low()); | ||
| 63 | assert!(a.is_set_high()); | ||
| 30 | } | 64 | } |
| 31 | } | 65 | } |
| 32 | 66 | ||
| @@ -78,6 +112,7 @@ async fn main(_spawner: Spawner) { | |||
| 78 | a.set_as_input(); | 112 | a.set_as_input(); |
| 79 | 113 | ||
| 80 | // When an OutputOpenDrain is high, it doesn't drive the pin. | 114 | // When an OutputOpenDrain is high, it doesn't drive the pin. |
| 115 | b.set_high(); | ||
| 81 | a.set_pull(Pull::Up); | 116 | a.set_pull(Pull::Up); |
| 82 | delay(); | 117 | delay(); |
| 83 | assert!(a.is_high()); | 118 | assert!(a.is_high()); |
| @@ -85,9 +120,8 @@ async fn main(_spawner: Spawner) { | |||
| 85 | delay(); | 120 | delay(); |
| 86 | assert!(a.is_low()); | 121 | assert!(a.is_low()); |
| 87 | 122 | ||
| 88 | b.set_low(); | ||
| 89 | |||
| 90 | // When an OutputOpenDrain is low, it drives the pin low. | 123 | // When an OutputOpenDrain is low, it drives the pin low. |
| 124 | b.set_low(); | ||
| 91 | a.set_pull(Pull::Up); | 125 | a.set_pull(Pull::Up); |
| 92 | delay(); | 126 | delay(); |
| 93 | assert!(a.is_low()); | 127 | assert!(a.is_low()); |
| @@ -95,14 +129,36 @@ async fn main(_spawner: Spawner) { | |||
| 95 | delay(); | 129 | delay(); |
| 96 | assert!(a.is_low()); | 130 | assert!(a.is_low()); |
| 97 | 131 | ||
| 132 | // Check high again | ||
| 98 | b.set_high(); | 133 | b.set_high(); |
| 99 | |||
| 100 | a.set_pull(Pull::Up); | 134 | a.set_pull(Pull::Up); |
| 101 | delay(); | 135 | delay(); |
| 102 | assert!(a.is_high()); | 136 | assert!(a.is_high()); |
| 103 | a.set_pull(Pull::Down); | 137 | a.set_pull(Pull::Down); |
| 104 | delay(); | 138 | delay(); |
| 105 | assert!(a.is_low()); | 139 | assert!(a.is_low()); |
| 140 | |||
| 141 | // When an OutputOpenDrain is high, it reads the input value in the pin. | ||
| 142 | b.set_high(); | ||
| 143 | a.set_as_input(); | ||
| 144 | a.set_pull(Pull::Up); | ||
| 145 | delay(); | ||
| 146 | assert!(b.is_high()); | ||
| 147 | a.set_as_output(); | ||
| 148 | a.set_low(); | ||
| 149 | delay(); | ||
| 150 | assert!(b.is_low()); | ||
| 151 | |||
| 152 | // When an OutputOpenDrain is low, it always reads low. | ||
| 153 | b.set_low(); | ||
| 154 | a.set_as_input(); | ||
| 155 | a.set_pull(Pull::Up); | ||
| 156 | delay(); | ||
| 157 | assert!(b.is_low()); | ||
| 158 | a.set_as_output(); | ||
| 159 | a.set_low(); | ||
| 160 | delay(); | ||
| 161 | assert!(b.is_low()); | ||
| 106 | } | 162 | } |
| 107 | 163 | ||
| 108 | // FLEX | 164 | // FLEX |
diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs index 1eeaac1f6..532494de5 100644 --- a/tests/rp/src/bin/gpio_async.rs +++ b/tests/rp/src/bin/gpio_async.rs | |||
| @@ -1,12 +1,14 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 4 | 6 | ||
| 5 | use defmt::{assert, *}; | 7 | use defmt::{assert, *}; |
| 6 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | ||
| 7 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 10 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| 8 | use embassy_time::{Duration, Instant, Timer}; | 11 | use embassy_time::{Duration, Instant, Timer}; |
| 9 | use futures::future::join; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 13 | ||
| 12 | #[embassy_executor::main] | 14 | #[embassy_executor::main] |
diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs new file mode 100644 index 000000000..780112bc1 --- /dev/null +++ b/tests/rp/src/bin/gpio_multicore.rs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{info, unwrap}; | ||
| 8 | use embassy_executor::Executor; | ||
| 9 | use embassy_executor::_export::StaticCell; | ||
| 10 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | ||
| 11 | use embassy_rp::multicore::{spawn_core1, Stack}; | ||
| 12 | use embassy_rp::peripherals::{PIN_0, PIN_1}; | ||
| 13 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 14 | use embassy_sync::channel::Channel; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | static mut CORE1_STACK: Stack<1024> = Stack::new(); | ||
| 18 | static EXECUTOR0: StaticCell<Executor> = StaticCell::new(); | ||
| 19 | static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); | ||
| 20 | static CHANNEL0: Channel<CriticalSectionRawMutex, (), 1> = Channel::new(); | ||
| 21 | static CHANNEL1: Channel<CriticalSectionRawMutex, (), 1> = Channel::new(); | ||
| 22 | |||
| 23 | #[cortex_m_rt::entry] | ||
| 24 | fn main() -> ! { | ||
| 25 | let p = embassy_rp::init(Default::default()); | ||
| 26 | spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { | ||
| 27 | let executor1 = EXECUTOR1.init(Executor::new()); | ||
| 28 | executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1)))); | ||
| 29 | }); | ||
| 30 | let executor0 = EXECUTOR0.init(Executor::new()); | ||
| 31 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0)))); | ||
| 32 | } | ||
| 33 | |||
| 34 | #[embassy_executor::task] | ||
| 35 | async fn core0_task(p: PIN_0) { | ||
| 36 | info!("CORE0 is running"); | ||
| 37 | |||
| 38 | let mut pin = Output::new(p, Level::Low); | ||
| 39 | |||
| 40 | CHANNEL0.send(()).await; | ||
| 41 | CHANNEL1.recv().await; | ||
| 42 | |||
| 43 | pin.set_high(); | ||
| 44 | |||
| 45 | CHANNEL1.recv().await; | ||
| 46 | |||
| 47 | info!("Test OK"); | ||
| 48 | cortex_m::asm::bkpt(); | ||
| 49 | } | ||
| 50 | |||
| 51 | #[embassy_executor::task] | ||
| 52 | async fn core1_task(p: PIN_1) { | ||
| 53 | info!("CORE1 is running"); | ||
| 54 | |||
| 55 | CHANNEL0.recv().await; | ||
| 56 | |||
| 57 | let mut pin = Input::new(p, Pull::Down); | ||
| 58 | let wait = pin.wait_for_rising_edge(); | ||
| 59 | |||
| 60 | CHANNEL1.send(()).await; | ||
| 61 | |||
| 62 | wait.await; | ||
| 63 | |||
| 64 | CHANNEL1.send(()).await; | ||
| 65 | } | ||
diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs new file mode 100644 index 000000000..114889dec --- /dev/null +++ b/tests/rp/src/bin/multicore.rs | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{info, unwrap}; | ||
| 8 | use embassy_executor::Executor; | ||
| 9 | use embassy_executor::_export::StaticCell; | ||
| 10 | use embassy_rp::multicore::{spawn_core1, Stack}; | ||
| 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, bool, 1> = Channel::new(); | ||
| 19 | static CHANNEL1: Channel<CriticalSectionRawMutex, bool, 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()))); | ||
| 27 | }); | ||
| 28 | let executor0 = EXECUTOR0.init(Executor::new()); | ||
| 29 | executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); | ||
| 30 | } | ||
| 31 | |||
| 32 | #[embassy_executor::task] | ||
| 33 | async fn core0_task() { | ||
| 34 | info!("CORE0 is running"); | ||
| 35 | let ping = true; | ||
| 36 | CHANNEL0.send(ping).await; | ||
| 37 | let pong = CHANNEL1.recv().await; | ||
| 38 | assert_eq!(ping, pong); | ||
| 39 | |||
| 40 | info!("Test OK"); | ||
| 41 | cortex_m::asm::bkpt(); | ||
| 42 | } | ||
| 43 | |||
| 44 | #[embassy_executor::task] | ||
| 45 | async fn core1_task() { | ||
| 46 | info!("CORE1 is running"); | ||
| 47 | let ping = CHANNEL0.recv().await; | ||
| 48 | CHANNEL1.send(ping).await; | ||
| 49 | } | ||
diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs new file mode 100644 index 000000000..45004424a --- /dev/null +++ b/tests/rp/src/bin/pio_irq.rs | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::info; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::bind_interrupts; | ||
| 10 | use embassy_rp::peripherals::PIO0; | ||
| 11 | use embassy_rp::pio::{Config, InterruptHandler, Pio}; | ||
| 12 | use embassy_rp::relocate::RelocatedProgram; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | let p = embassy_rp::init(Default::default()); | ||
| 22 | let pio = p.PIO0; | ||
| 23 | let Pio { | ||
| 24 | mut common, | ||
| 25 | sm0: mut sm, | ||
| 26 | irq_flags, | ||
| 27 | .. | ||
| 28 | } = Pio::new(pio, Irqs); | ||
| 29 | |||
| 30 | let prg = pio_proc::pio_asm!( | ||
| 31 | "irq set 0", | ||
| 32 | "irq wait 0", | ||
| 33 | "irq set 1", | ||
| 34 | // pause execution here | ||
| 35 | "irq wait 1", | ||
| 36 | ); | ||
| 37 | |||
| 38 | let relocated = RelocatedProgram::new(&prg.program); | ||
| 39 | let mut cfg = Config::default(); | ||
| 40 | cfg.use_program(&common.load_program(&relocated), &[]); | ||
| 41 | sm.set_config(&cfg); | ||
| 42 | sm.set_enable(true); | ||
| 43 | |||
| 44 | // not using the wait futures on purpose because they clear the irq bits, | ||
| 45 | // and we want to see in which order they are set. | ||
| 46 | while !irq_flags.check(0) {} | ||
| 47 | cortex_m::asm::nop(); | ||
| 48 | assert!(!irq_flags.check(1)); | ||
| 49 | irq_flags.clear(0); | ||
| 50 | cortex_m::asm::nop(); | ||
| 51 | assert!(irq_flags.check(1)); | ||
| 52 | |||
| 53 | info!("Test OK"); | ||
| 54 | cortex_m::asm::bkpt(); | ||
| 55 | } | ||
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs new file mode 100644 index 000000000..c71d21ef9 --- /dev/null +++ b/tests/rp/src/bin/pwm.rs | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert, assert_eq, assert_ne, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | ||
| 10 | use embassy_rp::pwm::{Config, InputMode, Pwm}; | ||
| 11 | use embassy_time::{Duration, Timer}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let mut p = embassy_rp::init(Default::default()); | ||
| 17 | info!("Hello World!"); | ||
| 18 | |||
| 19 | // Connections on CI device: 6 -> 9, 7 -> 11 | ||
| 20 | let (mut p6, mut p7, mut p9, mut p11) = (p.PIN_6, p.PIN_7, p.PIN_9, p.PIN_11); | ||
| 21 | |||
| 22 | let cfg = { | ||
| 23 | let mut c = Config::default(); | ||
| 24 | c.divider = 125.into(); | ||
| 25 | c.top = 10000; | ||
| 26 | c.compare_a = 5000; | ||
| 27 | c.compare_b = 5000; | ||
| 28 | c | ||
| 29 | }; | ||
| 30 | |||
| 31 | // Test free-running clock | ||
| 32 | { | ||
| 33 | let pwm = Pwm::new_free(&mut p.PWM_CH3, cfg.clone()); | ||
| 34 | cortex_m::asm::delay(125); | ||
| 35 | let ctr = pwm.counter(); | ||
| 36 | assert!(ctr > 0); | ||
| 37 | assert!(ctr < 100); | ||
| 38 | cortex_m::asm::delay(125); | ||
| 39 | assert!(ctr < pwm.counter()); | ||
| 40 | } | ||
| 41 | |||
| 42 | for invert_a in [false, true] { | ||
| 43 | info!("free-running, invert A: {}", invert_a); | ||
| 44 | let mut cfg = cfg.clone(); | ||
| 45 | cfg.invert_a = invert_a; | ||
| 46 | cfg.invert_b = !invert_a; | ||
| 47 | |||
| 48 | // Test output from A | ||
| 49 | { | ||
| 50 | let pin1 = Input::new(&mut p9, Pull::None); | ||
| 51 | let _pwm = Pwm::new_output_a(&mut p.PWM_CH3, &mut p6, cfg.clone()); | ||
| 52 | Timer::after(Duration::from_millis(1)).await; | ||
| 53 | assert_eq!(pin1.is_low(), invert_a); | ||
| 54 | Timer::after(Duration::from_millis(5)).await; | ||
| 55 | assert_eq!(pin1.is_high(), invert_a); | ||
| 56 | Timer::after(Duration::from_millis(5)).await; | ||
| 57 | assert_eq!(pin1.is_low(), invert_a); | ||
| 58 | Timer::after(Duration::from_millis(5)).await; | ||
| 59 | assert_eq!(pin1.is_high(), invert_a); | ||
| 60 | } | ||
| 61 | |||
| 62 | // Test output from B | ||
| 63 | { | ||
| 64 | let pin2 = Input::new(&mut p11, Pull::None); | ||
| 65 | let _pwm = Pwm::new_output_b(&mut p.PWM_CH3, &mut p7, cfg.clone()); | ||
| 66 | Timer::after(Duration::from_millis(1)).await; | ||
| 67 | assert_ne!(pin2.is_low(), invert_a); | ||
| 68 | Timer::after(Duration::from_millis(5)).await; | ||
| 69 | assert_ne!(pin2.is_high(), invert_a); | ||
| 70 | Timer::after(Duration::from_millis(5)).await; | ||
| 71 | assert_ne!(pin2.is_low(), invert_a); | ||
| 72 | Timer::after(Duration::from_millis(5)).await; | ||
| 73 | assert_ne!(pin2.is_high(), invert_a); | ||
| 74 | } | ||
| 75 | |||
| 76 | // Test output from A+B | ||
| 77 | { | ||
| 78 | let pin1 = Input::new(&mut p9, Pull::None); | ||
| 79 | let pin2 = Input::new(&mut p11, Pull::None); | ||
| 80 | let _pwm = Pwm::new_output_ab(&mut p.PWM_CH3, &mut p6, &mut p7, cfg.clone()); | ||
| 81 | Timer::after(Duration::from_millis(1)).await; | ||
| 82 | assert_eq!(pin1.is_low(), invert_a); | ||
| 83 | assert_ne!(pin2.is_low(), invert_a); | ||
| 84 | Timer::after(Duration::from_millis(5)).await; | ||
| 85 | assert_eq!(pin1.is_high(), invert_a); | ||
| 86 | assert_ne!(pin2.is_high(), invert_a); | ||
| 87 | Timer::after(Duration::from_millis(5)).await; | ||
| 88 | assert_eq!(pin1.is_low(), invert_a); | ||
| 89 | assert_ne!(pin2.is_low(), invert_a); | ||
| 90 | Timer::after(Duration::from_millis(5)).await; | ||
| 91 | assert_eq!(pin1.is_high(), invert_a); | ||
| 92 | assert_ne!(pin2.is_high(), invert_a); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | // Test level-gated | ||
| 97 | { | ||
| 98 | let mut pin2 = Output::new(&mut p11, Level::Low); | ||
| 99 | let pwm = Pwm::new_input(&mut p.PWM_CH3, &mut p7, InputMode::Level, cfg.clone()); | ||
| 100 | assert_eq!(pwm.counter(), 0); | ||
| 101 | Timer::after(Duration::from_millis(5)).await; | ||
| 102 | assert_eq!(pwm.counter(), 0); | ||
| 103 | pin2.set_high(); | ||
| 104 | Timer::after(Duration::from_millis(1)).await; | ||
| 105 | pin2.set_low(); | ||
| 106 | let ctr = pwm.counter(); | ||
| 107 | assert!(ctr >= 1000); | ||
| 108 | Timer::after(Duration::from_millis(1)).await; | ||
| 109 | assert_eq!(pwm.counter(), ctr); | ||
| 110 | } | ||
| 111 | |||
| 112 | // Test rising-gated | ||
| 113 | { | ||
| 114 | let mut pin2 = Output::new(&mut p11, Level::Low); | ||
| 115 | let pwm = Pwm::new_input(&mut p.PWM_CH3, &mut p7, InputMode::RisingEdge, cfg.clone()); | ||
| 116 | assert_eq!(pwm.counter(), 0); | ||
| 117 | Timer::after(Duration::from_millis(5)).await; | ||
| 118 | assert_eq!(pwm.counter(), 0); | ||
| 119 | pin2.set_high(); | ||
| 120 | Timer::after(Duration::from_millis(1)).await; | ||
| 121 | pin2.set_low(); | ||
| 122 | assert_eq!(pwm.counter(), 1); | ||
| 123 | Timer::after(Duration::from_millis(1)).await; | ||
| 124 | assert_eq!(pwm.counter(), 1); | ||
| 125 | } | ||
| 126 | |||
| 127 | // Test falling-gated | ||
| 128 | { | ||
| 129 | let mut pin2 = Output::new(&mut p11, Level::High); | ||
| 130 | let pwm = Pwm::new_input(&mut p.PWM_CH3, &mut p7, InputMode::FallingEdge, cfg.clone()); | ||
| 131 | assert_eq!(pwm.counter(), 0); | ||
| 132 | Timer::after(Duration::from_millis(5)).await; | ||
| 133 | assert_eq!(pwm.counter(), 0); | ||
| 134 | pin2.set_low(); | ||
| 135 | Timer::after(Duration::from_millis(1)).await; | ||
| 136 | pin2.set_high(); | ||
| 137 | assert_eq!(pwm.counter(), 1); | ||
| 138 | Timer::after(Duration::from_millis(1)).await; | ||
| 139 | assert_eq!(pwm.counter(), 1); | ||
| 140 | } | ||
| 141 | |||
| 142 | info!("Test OK"); | ||
| 143 | cortex_m::asm::bkpt(); | ||
| 144 | } | ||
diff --git a/tests/rp/src/bin/spi.rs b/tests/rp/src/bin/spi.rs new file mode 100644 index 000000000..84dfa5a2c --- /dev/null +++ b/tests/rp/src/bin/spi.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert_eq, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::spi::{Config, Spi}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_rp::init(Default::default()); | ||
| 15 | info!("Hello World!"); | ||
| 16 | |||
| 17 | let clk = p.PIN_2; | ||
| 18 | let mosi = p.PIN_3; | ||
| 19 | let miso = p.PIN_4; | ||
| 20 | |||
| 21 | let mut spi = Spi::new_blocking(p.SPI0, clk, mosi, miso, Config::default()); | ||
| 22 | |||
| 23 | let tx_buf = [1_u8, 2, 3, 4, 5, 6]; | ||
| 24 | let mut rx_buf = [0_u8; 6]; | ||
| 25 | spi.blocking_transfer(&mut rx_buf, &tx_buf).unwrap(); | ||
| 26 | assert_eq!(rx_buf, tx_buf); | ||
| 27 | |||
| 28 | info!("Test OK"); | ||
| 29 | cortex_m::asm::bkpt(); | ||
| 30 | } | ||
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs new file mode 100644 index 000000000..a4080b03d --- /dev/null +++ b/tests/rp/src/bin/spi_async.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | //! Make sure to connect GPIO pins 3 (`PIN_3`) and 4 (`PIN_4`) together | ||
| 2 | //! to run this test. | ||
| 3 | //! | ||
| 4 | #![no_std] | ||
| 5 | #![no_main] | ||
| 6 | #![feature(type_alias_impl_trait)] | ||
| 7 | #[path = "../common.rs"] | ||
| 8 | mod common; | ||
| 9 | |||
| 10 | use defmt::{assert_eq, *}; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_rp::spi::{Config, Spi}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async fn main(_spawner: Spawner) { | ||
| 17 | let p = embassy_rp::init(Default::default()); | ||
| 18 | info!("Hello World!"); | ||
| 19 | |||
| 20 | let clk = p.PIN_2; | ||
| 21 | let mosi = p.PIN_3; | ||
| 22 | let miso = p.PIN_4; | ||
| 23 | |||
| 24 | let mut spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); | ||
| 25 | |||
| 26 | // equal rx & tx buffers | ||
| 27 | { | ||
| 28 | let tx_buf = [1_u8, 2, 3, 4, 5, 6]; | ||
| 29 | let mut rx_buf = [0_u8; 6]; | ||
| 30 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 31 | assert_eq!(rx_buf, tx_buf); | ||
| 32 | } | ||
| 33 | |||
| 34 | // tx > rx buffer | ||
| 35 | { | ||
| 36 | let tx_buf = [7_u8, 8, 9, 10, 11, 12]; | ||
| 37 | |||
| 38 | let mut rx_buf = [0_u8; 3]; | ||
| 39 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 40 | assert_eq!(rx_buf, tx_buf[..3]); | ||
| 41 | |||
| 42 | defmt::info!("tx > rx buffer - OK"); | ||
| 43 | } | ||
| 44 | |||
| 45 | // we make sure to that clearing FIFO works after the uneven buffers | ||
| 46 | |||
| 47 | // equal rx & tx buffers | ||
| 48 | { | ||
| 49 | let tx_buf = [13_u8, 14, 15, 16, 17, 18]; | ||
| 50 | let mut rx_buf = [0_u8; 6]; | ||
| 51 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 52 | assert_eq!(rx_buf, tx_buf); | ||
| 53 | |||
| 54 | defmt::info!("buffer rx length == tx length - OK"); | ||
| 55 | } | ||
| 56 | |||
| 57 | // rx > tx buffer | ||
| 58 | { | ||
| 59 | let tx_buf = [19_u8, 20, 21]; | ||
| 60 | let mut rx_buf = [0_u8; 6]; | ||
| 61 | |||
| 62 | // we should have written dummy data to tx buffer to sync clock. | ||
| 63 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 64 | |||
| 65 | assert_eq!( | ||
| 66 | rx_buf[..3], | ||
| 67 | tx_buf, | ||
| 68 | "only the first 3 TX bytes should have been received in the RX buffer" | ||
| 69 | ); | ||
| 70 | assert_eq!(rx_buf[3..], [0, 0, 0], "the rest of the RX bytes should be empty"); | ||
| 71 | defmt::info!("buffer rx length > tx length - OK"); | ||
| 72 | } | ||
| 73 | |||
| 74 | // equal rx & tx buffers | ||
| 75 | { | ||
| 76 | let tx_buf = [22_u8, 23, 24, 25, 26, 27]; | ||
| 77 | let mut rx_buf = [0_u8; 6]; | ||
| 78 | spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); | ||
| 79 | |||
| 80 | assert_eq!(rx_buf, tx_buf); | ||
| 81 | defmt::info!("buffer rx length = tx length - OK"); | ||
| 82 | } | ||
| 83 | |||
| 84 | info!("Test OK"); | ||
| 85 | cortex_m::asm::bkpt(); | ||
| 86 | } | ||
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs new file mode 100644 index 000000000..2331c7d36 --- /dev/null +++ b/tests/rp/src/bin/uart.rs | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert_eq, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::gpio::{Level, Output}; | ||
| 10 | use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx}; | ||
| 11 | use embassy_time::{Duration, Timer}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { | ||
| 15 | let mut buf = [255; N]; | ||
| 16 | uart.blocking_read(&mut buf)?; | ||
| 17 | Ok(buf) | ||
| 18 | } | ||
| 19 | |||
| 20 | fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { | ||
| 21 | let mut buf = [255; N]; | ||
| 22 | uart.blocking_read(&mut buf)?; | ||
| 23 | Ok(buf) | ||
| 24 | } | ||
| 25 | |||
| 26 | async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) { | ||
| 27 | pin.set_low(); | ||
| 28 | Timer::after(Duration::from_millis(1)).await; | ||
| 29 | for i in 0..8 { | ||
| 30 | if v & (1 << i) == 0 { | ||
| 31 | pin.set_low(); | ||
| 32 | } else { | ||
| 33 | pin.set_high(); | ||
| 34 | } | ||
| 35 | Timer::after(Duration::from_millis(1)).await; | ||
| 36 | } | ||
| 37 | if let Some(b) = parity { | ||
| 38 | if b { | ||
| 39 | pin.set_high(); | ||
| 40 | } else { | ||
| 41 | pin.set_low(); | ||
| 42 | } | ||
| 43 | Timer::after(Duration::from_millis(1)).await; | ||
| 44 | } | ||
| 45 | pin.set_high(); | ||
| 46 | Timer::after(Duration::from_millis(1)).await; | ||
| 47 | } | ||
| 48 | |||
| 49 | #[embassy_executor::main] | ||
| 50 | async fn main(_spawner: Spawner) { | ||
| 51 | let p = embassy_rp::init(Default::default()); | ||
| 52 | info!("Hello World!"); | ||
| 53 | |||
| 54 | let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 55 | |||
| 56 | { | ||
| 57 | let config = Config::default(); | ||
| 58 | let mut uart = Uart::new_blocking(&mut uart, &mut tx, &mut rx, config); | ||
| 59 | |||
| 60 | // 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. | ||
| 62 | |||
| 63 | let data = [0xC0, 0xDE]; | ||
| 64 | uart.blocking_write(&data).unwrap(); | ||
| 65 | assert_eq!(read(&mut uart).unwrap(), data); | ||
| 66 | } | ||
| 67 | |||
| 68 | info!("test overflow detection"); | ||
| 69 | { | ||
| 70 | let config = Config::default(); | ||
| 71 | let mut uart = Uart::new_blocking(&mut uart, &mut tx, &mut rx, config); | ||
| 72 | |||
| 73 | let data = [ | ||
| 74 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 75 | 30, 31, 32, | ||
| 76 | ]; | ||
| 77 | let overflow = [ | ||
| 78 | 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, | ||
| 79 | ]; | ||
| 80 | uart.blocking_write(&data).unwrap(); | ||
| 81 | uart.blocking_write(&overflow).unwrap(); | ||
| 82 | while uart.busy() {} | ||
| 83 | |||
| 84 | // prefix in fifo is valid | ||
| 85 | assert_eq!(read(&mut uart).unwrap(), data); | ||
| 86 | // next received character causes overrun error and is discarded | ||
| 87 | uart.blocking_write(&[1, 2, 3]).unwrap(); | ||
| 88 | assert_eq!(read::<1>(&mut uart).unwrap_err(), Error::Overrun); | ||
| 89 | assert_eq!(read(&mut uart).unwrap(), [2, 3]); | ||
| 90 | } | ||
| 91 | |||
| 92 | info!("test break detection"); | ||
| 93 | { | ||
| 94 | let config = Config::default(); | ||
| 95 | let mut uart = Uart::new_blocking(&mut uart, &mut tx, &mut rx, config); | ||
| 96 | |||
| 97 | // break on empty fifo | ||
| 98 | uart.send_break(20).await; | ||
| 99 | uart.blocking_write(&[64]).unwrap(); | ||
| 100 | assert_eq!(read::<1>(&mut uart).unwrap_err(), Error::Break); | ||
| 101 | assert_eq!(read(&mut uart).unwrap(), [64]); | ||
| 102 | |||
| 103 | // break on partially filled fifo | ||
| 104 | uart.blocking_write(&[65; 2]).unwrap(); | ||
| 105 | uart.send_break(20).await; | ||
| 106 | uart.blocking_write(&[66]).unwrap(); | ||
| 107 | assert_eq!(read(&mut uart).unwrap(), [65; 2]); | ||
| 108 | assert_eq!(read::<1>(&mut uart).unwrap_err(), Error::Break); | ||
| 109 | assert_eq!(read(&mut uart).unwrap(), [66]); | ||
| 110 | } | ||
| 111 | |||
| 112 | // parity detection. here we bitbang to not require two uarts. | ||
| 113 | info!("test parity error detection"); | ||
| 114 | { | ||
| 115 | let mut pin = Output::new(&mut tx, Level::High); | ||
| 116 | let mut config = Config::default(); | ||
| 117 | config.baudrate = 1000; | ||
| 118 | config.parity = Parity::ParityEven; | ||
| 119 | let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); | ||
| 120 | |||
| 121 | async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u8) { | ||
| 122 | send(pin, v, Some(parity != 0)).await; | ||
| 123 | } | ||
| 124 | |||
| 125 | // first check that we can send correctly | ||
| 126 | chr(&mut pin, 64, 1).await; | ||
| 127 | assert_eq!(read1(&mut uart).unwrap(), [64]); | ||
| 128 | |||
| 129 | // all good, check real errors | ||
| 130 | chr(&mut pin, 2, 1).await; | ||
| 131 | chr(&mut pin, 3, 0).await; | ||
| 132 | chr(&mut pin, 4, 0).await; | ||
| 133 | chr(&mut pin, 5, 0).await; | ||
| 134 | assert_eq!(read1(&mut uart).unwrap(), [2, 3]); | ||
| 135 | assert_eq!(read1::<1>(&mut uart).unwrap_err(), Error::Parity); | ||
| 136 | assert_eq!(read1(&mut uart).unwrap(), [5]); | ||
| 137 | } | ||
| 138 | |||
| 139 | // framing error detection. here we bitbang because there's no other way. | ||
| 140 | info!("test framing error detection"); | ||
| 141 | { | ||
| 142 | let mut pin = Output::new(&mut tx, Level::High); | ||
| 143 | let mut config = Config::default(); | ||
| 144 | config.baudrate = 1000; | ||
| 145 | let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); | ||
| 146 | |||
| 147 | async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { | ||
| 148 | if good { | ||
| 149 | send(pin, v, None).await; | ||
| 150 | } else { | ||
| 151 | send(pin, v, Some(false)).await; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | // first check that we can send correctly | ||
| 156 | chr(&mut pin, 64, true).await; | ||
| 157 | assert_eq!(read1(&mut uart).unwrap(), [64]); | ||
| 158 | |||
| 159 | // all good, check real errors | ||
| 160 | chr(&mut pin, 2, true).await; | ||
| 161 | chr(&mut pin, 3, true).await; | ||
| 162 | chr(&mut pin, 4, false).await; | ||
| 163 | chr(&mut pin, 5, true).await; | ||
| 164 | assert_eq!(read1(&mut uart).unwrap(), [2, 3]); | ||
| 165 | assert_eq!(read1::<1>(&mut uart).unwrap_err(), Error::Framing); | ||
| 166 | assert_eq!(read1(&mut uart).unwrap(), [5]); | ||
| 167 | } | ||
| 168 | |||
| 169 | info!("Test OK"); | ||
| 170 | cortex_m::asm::bkpt(); | ||
| 171 | } | ||
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs new file mode 100644 index 000000000..e74e9986c --- /dev/null +++ b/tests/rp/src/bin/uart_buffered.rs | |||
| @@ -0,0 +1,256 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert_eq, panic, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::bind_interrupts; | ||
| 10 | use embassy_rp::gpio::{Level, Output}; | ||
| 11 | use embassy_rp::peripherals::UART0; | ||
| 12 | use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity}; | ||
| 13 | use embassy_time::{Duration, Timer}; | ||
| 14 | use embedded_io::asynch::{Read, ReadExactError, Write}; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | UART0_IRQ => BufferedInterruptHandler<UART0>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> { | ||
| 22 | let mut buf = [255; N]; | ||
| 23 | match uart.read_exact(&mut buf).await { | ||
| 24 | Ok(()) => Ok(buf), | ||
| 25 | // we should not ever produce an Eof condition | ||
| 26 | Err(ReadExactError::UnexpectedEof) => panic!(), | ||
| 27 | Err(ReadExactError::Other(e)) => Err(e), | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> { | ||
| 32 | let mut buf = [255; N]; | ||
| 33 | match uart.read_exact(&mut buf).await { | ||
| 34 | Ok(()) => Ok(buf), | ||
| 35 | // we should not ever produce an Eof condition | ||
| 36 | Err(ReadExactError::UnexpectedEof) => panic!(), | ||
| 37 | Err(ReadExactError::Other(e)) => Err(e), | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) { | ||
| 42 | pin.set_low(); | ||
| 43 | Timer::after(Duration::from_millis(1)).await; | ||
| 44 | for i in 0..8 { | ||
| 45 | if v & (1 << i) == 0 { | ||
| 46 | pin.set_low(); | ||
| 47 | } else { | ||
| 48 | pin.set_high(); | ||
| 49 | } | ||
| 50 | Timer::after(Duration::from_millis(1)).await; | ||
| 51 | } | ||
| 52 | if let Some(b) = parity { | ||
| 53 | if b { | ||
| 54 | pin.set_high(); | ||
| 55 | } else { | ||
| 56 | pin.set_low(); | ||
| 57 | } | ||
| 58 | Timer::after(Duration::from_millis(1)).await; | ||
| 59 | } | ||
| 60 | pin.set_high(); | ||
| 61 | Timer::after(Duration::from_millis(1)).await; | ||
| 62 | } | ||
| 63 | |||
| 64 | #[embassy_executor::main] | ||
| 65 | async fn main(_spawner: Spawner) { | ||
| 66 | let p = embassy_rp::init(Default::default()); | ||
| 67 | info!("Hello World!"); | ||
| 68 | |||
| 69 | let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 70 | |||
| 71 | { | ||
| 72 | let config = Config::default(); | ||
| 73 | let tx_buf = &mut [0u8; 16]; | ||
| 74 | let rx_buf = &mut [0u8; 16]; | ||
| 75 | let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config); | ||
| 76 | |||
| 77 | // Make sure we send more bytes than fits in the FIFO, to test the actual | ||
| 78 | // bufferedUart. | ||
| 79 | |||
| 80 | let data = [ | ||
| 81 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 82 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, | ||
| 83 | ]; | ||
| 84 | uart.write_all(&data).await.unwrap(); | ||
| 85 | info!("Done writing"); | ||
| 86 | |||
| 87 | assert_eq!(read(&mut uart).await.unwrap(), data); | ||
| 88 | } | ||
| 89 | |||
| 90 | info!("test overflow detection"); | ||
| 91 | { | ||
| 92 | let config = Config::default(); | ||
| 93 | let tx_buf = &mut [0u8; 16]; | ||
| 94 | let rx_buf = &mut [0u8; 16]; | ||
| 95 | let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config); | ||
| 96 | |||
| 97 | // Make sure we send more bytes than fits in the FIFO, to test the actual | ||
| 98 | // bufferedUart. | ||
| 99 | |||
| 100 | let data = [ | ||
| 101 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 102 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, | ||
| 103 | ]; | ||
| 104 | let overflow = [ | ||
| 105 | 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, | ||
| 106 | ]; | ||
| 107 | // give each block time to settle into the fifo. we want the overrun to occur at a well-defined point. | ||
| 108 | uart.write_all(&data).await.unwrap(); | ||
| 109 | uart.blocking_flush().unwrap(); | ||
| 110 | while uart.busy() {} | ||
| 111 | uart.write_all(&overflow).await.unwrap(); | ||
| 112 | uart.blocking_flush().unwrap(); | ||
| 113 | while uart.busy() {} | ||
| 114 | |||
| 115 | // already buffered/fifod prefix is valid | ||
| 116 | assert_eq!(read(&mut uart).await.unwrap(), data); | ||
| 117 | // next received character causes overrun error and is discarded | ||
| 118 | uart.write_all(&[1, 2, 3]).await.unwrap(); | ||
| 119 | uart.blocking_flush().unwrap(); | ||
| 120 | assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Overrun); | ||
| 121 | assert_eq!(read(&mut uart).await.unwrap(), [2, 3]); | ||
| 122 | } | ||
| 123 | |||
| 124 | info!("test break detection"); | ||
| 125 | { | ||
| 126 | let mut config = Config::default(); | ||
| 127 | config.baudrate = 1000; | ||
| 128 | let tx_buf = &mut [0u8; 16]; | ||
| 129 | let rx_buf = &mut [0u8; 16]; | ||
| 130 | let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config); | ||
| 131 | |||
| 132 | // break on empty buffer | ||
| 133 | uart.send_break(20).await; | ||
| 134 | assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Break); | ||
| 135 | uart.write_all(&[64]).await.unwrap(); | ||
| 136 | assert_eq!(read(&mut uart).await.unwrap(), [64]); | ||
| 137 | |||
| 138 | // break on partially filled buffer | ||
| 139 | uart.write_all(&[65; 2]).await.unwrap(); | ||
| 140 | uart.send_break(20).await; | ||
| 141 | uart.write_all(&[66]).await.unwrap(); | ||
| 142 | assert_eq!(read(&mut uart).await.unwrap(), [65; 2]); | ||
| 143 | assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Break); | ||
| 144 | assert_eq!(read(&mut uart).await.unwrap(), [66]); | ||
| 145 | |||
| 146 | // break on full buffer | ||
| 147 | uart.write_all(&[64; 16]).await.unwrap(); | ||
| 148 | uart.send_break(20).await; | ||
| 149 | uart.write_all(&[65]).await.unwrap(); | ||
| 150 | assert_eq!(read(&mut uart).await.unwrap(), [64; 16]); | ||
| 151 | assert_eq!(read::<1>(&mut uart).await.unwrap_err(), Error::Break); | ||
| 152 | assert_eq!(read(&mut uart).await.unwrap(), [65]); | ||
| 153 | } | ||
| 154 | |||
| 155 | // parity detection. here we bitbang to not require two uarts. | ||
| 156 | info!("test parity error detection"); | ||
| 157 | { | ||
| 158 | let mut pin = Output::new(&mut tx, Level::High); | ||
| 159 | // choose a very slow baud rate to make tests reliable even with O0 | ||
| 160 | let mut config = Config::default(); | ||
| 161 | config.baudrate = 1000; | ||
| 162 | config.parity = Parity::ParityEven; | ||
| 163 | let rx_buf = &mut [0u8; 16]; | ||
| 164 | let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); | ||
| 165 | |||
| 166 | async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) { | ||
| 167 | send(pin, v, Some(parity != 0)).await; | ||
| 168 | } | ||
| 169 | |||
| 170 | // first check that we can send correctly | ||
| 171 | chr(&mut pin, 64, 1).await; | ||
| 172 | assert_eq!(read1(&mut uart).await.unwrap(), [64]); | ||
| 173 | |||
| 174 | // parity on empty buffer | ||
| 175 | chr(&mut pin, 64, 0).await; | ||
| 176 | chr(&mut pin, 4, 1).await; | ||
| 177 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity); | ||
| 178 | assert_eq!(read1(&mut uart).await.unwrap(), [4]); | ||
| 179 | |||
| 180 | // parity on partially filled buffer | ||
| 181 | chr(&mut pin, 64, 1).await; | ||
| 182 | chr(&mut pin, 32, 1).await; | ||
| 183 | chr(&mut pin, 64, 0).await; | ||
| 184 | chr(&mut pin, 65, 0).await; | ||
| 185 | assert_eq!(read1(&mut uart).await.unwrap(), [64, 32]); | ||
| 186 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity); | ||
| 187 | assert_eq!(read1(&mut uart).await.unwrap(), [65]); | ||
| 188 | |||
| 189 | // parity on full buffer | ||
| 190 | for i in 0..16 { | ||
| 191 | chr(&mut pin, i, i.count_ones() % 2).await; | ||
| 192 | } | ||
| 193 | chr(&mut pin, 64, 0).await; | ||
| 194 | chr(&mut pin, 65, 0).await; | ||
| 195 | assert_eq!( | ||
| 196 | read1(&mut uart).await.unwrap(), | ||
| 197 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] | ||
| 198 | ); | ||
| 199 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity); | ||
| 200 | assert_eq!(read1(&mut uart).await.unwrap(), [65]); | ||
| 201 | } | ||
| 202 | |||
| 203 | // framing error detection. here we bitbang because there's no other way. | ||
| 204 | info!("test framing error detection"); | ||
| 205 | { | ||
| 206 | let mut pin = Output::new(&mut tx, Level::High); | ||
| 207 | // choose a very slow baud rate to make tests reliable even with O0 | ||
| 208 | let mut config = Config::default(); | ||
| 209 | config.baudrate = 1000; | ||
| 210 | let rx_buf = &mut [0u8; 16]; | ||
| 211 | let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); | ||
| 212 | |||
| 213 | async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { | ||
| 214 | if good { | ||
| 215 | send(pin, v, None).await; | ||
| 216 | } else { | ||
| 217 | send(pin, v, Some(false)).await; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | // first check that we can send correctly | ||
| 222 | chr(&mut pin, 64, true).await; | ||
| 223 | assert_eq!(read1(&mut uart).await.unwrap(), [64]); | ||
| 224 | |||
| 225 | // framing on empty buffer | ||
| 226 | chr(&mut pin, 64, false).await; | ||
| 227 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing); | ||
| 228 | chr(&mut pin, 65, true).await; | ||
| 229 | assert_eq!(read1(&mut uart).await.unwrap(), [65]); | ||
| 230 | |||
| 231 | // framing on partially filled buffer | ||
| 232 | chr(&mut pin, 64, true).await; | ||
| 233 | chr(&mut pin, 32, true).await; | ||
| 234 | chr(&mut pin, 64, false).await; | ||
| 235 | chr(&mut pin, 65, true).await; | ||
| 236 | assert_eq!(read1(&mut uart).await.unwrap(), [64, 32]); | ||
| 237 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing); | ||
| 238 | assert_eq!(read1(&mut uart).await.unwrap(), [65]); | ||
| 239 | |||
| 240 | // framing on full buffer | ||
| 241 | for i in 0..16 { | ||
| 242 | chr(&mut pin, i, true).await; | ||
| 243 | } | ||
| 244 | chr(&mut pin, 64, false).await; | ||
| 245 | chr(&mut pin, 65, true).await; | ||
| 246 | assert_eq!( | ||
| 247 | read1(&mut uart).await.unwrap(), | ||
| 248 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] | ||
| 249 | ); | ||
| 250 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing); | ||
| 251 | assert_eq!(read1(&mut uart).await.unwrap(), [65]); | ||
| 252 | } | ||
| 253 | |||
| 254 | info!("Test OK"); | ||
| 255 | cortex_m::asm::bkpt(); | ||
| 256 | } | ||
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs new file mode 100644 index 000000000..fee6c825d --- /dev/null +++ b/tests/rp/src/bin/uart_dma.rs | |||
| @@ -0,0 +1,252 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert_eq, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::bind_interrupts; | ||
| 10 | use embassy_rp::gpio::{Level, Output}; | ||
| 11 | use embassy_rp::peripherals::UART0; | ||
| 12 | use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx}; | ||
| 13 | use embassy_time::{Duration, Timer}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | UART0_IRQ => InterruptHandler<UART0>; | ||
| 18 | }); | ||
| 19 | |||
| 20 | async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> { | ||
| 21 | let mut buf = [255; N]; | ||
| 22 | uart.read(&mut buf).await?; | ||
| 23 | Ok(buf) | ||
| 24 | } | ||
| 25 | |||
| 26 | async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> { | ||
| 27 | let mut buf = [255; N]; | ||
| 28 | uart.read(&mut buf).await?; | ||
| 29 | Ok(buf) | ||
| 30 | } | ||
| 31 | |||
| 32 | async fn send(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: Option<bool>) { | ||
| 33 | pin.set_low(); | ||
| 34 | Timer::after(Duration::from_millis(1)).await; | ||
| 35 | for i in 0..8 { | ||
| 36 | if v & (1 << i) == 0 { | ||
| 37 | pin.set_low(); | ||
| 38 | } else { | ||
| 39 | pin.set_high(); | ||
| 40 | } | ||
| 41 | Timer::after(Duration::from_millis(1)).await; | ||
| 42 | } | ||
| 43 | if let Some(b) = parity { | ||
| 44 | if b { | ||
| 45 | pin.set_high(); | ||
| 46 | } else { | ||
| 47 | pin.set_low(); | ||
| 48 | } | ||
| 49 | Timer::after(Duration::from_millis(1)).await; | ||
| 50 | } | ||
| 51 | pin.set_high(); | ||
| 52 | Timer::after(Duration::from_millis(1)).await; | ||
| 53 | } | ||
| 54 | |||
| 55 | #[embassy_executor::main] | ||
| 56 | async fn main(_spawner: Spawner) { | ||
| 57 | let mut p = embassy_rp::init(Default::default()); | ||
| 58 | info!("Hello World!"); | ||
| 59 | |||
| 60 | let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 61 | |||
| 62 | // We can't send too many bytes, they have to fit in the FIFO. | ||
| 63 | // This is because we aren't sending+receiving at the same time. | ||
| 64 | { | ||
| 65 | let config = Config::default(); | ||
| 66 | let mut uart = Uart::new( | ||
| 67 | &mut uart, | ||
| 68 | &mut tx, | ||
| 69 | &mut rx, | ||
| 70 | Irqs, | ||
| 71 | &mut p.DMA_CH0, | ||
| 72 | &mut p.DMA_CH1, | ||
| 73 | config, | ||
| 74 | ); | ||
| 75 | |||
| 76 | let data = [0xC0, 0xDE]; | ||
| 77 | uart.write(&data).await.unwrap(); | ||
| 78 | |||
| 79 | let mut buf = [0; 2]; | ||
| 80 | uart.read(&mut buf).await.unwrap(); | ||
| 81 | assert_eq!(buf, data); | ||
| 82 | } | ||
| 83 | |||
| 84 | info!("test overflow detection"); | ||
| 85 | { | ||
| 86 | let config = Config::default(); | ||
| 87 | let mut uart = Uart::new( | ||
| 88 | &mut uart, | ||
| 89 | &mut tx, | ||
| 90 | &mut rx, | ||
| 91 | Irqs, | ||
| 92 | &mut p.DMA_CH0, | ||
| 93 | &mut p.DMA_CH1, | ||
| 94 | config, | ||
| 95 | ); | ||
| 96 | |||
| 97 | uart.blocking_write(&[42; 32]).unwrap(); | ||
| 98 | uart.blocking_write(&[1, 2, 3]).unwrap(); | ||
| 99 | uart.blocking_flush().unwrap(); | ||
| 100 | |||
| 101 | // can receive regular fifo contents | ||
| 102 | assert_eq!(read(&mut uart).await, Ok([42; 16])); | ||
| 103 | assert_eq!(read(&mut uart).await, Ok([42; 16])); | ||
| 104 | // receiving the rest fails with overrun | ||
| 105 | assert_eq!(read::<16>(&mut uart).await, Err(Error::Overrun)); | ||
| 106 | // new data is accepted, latest overrunning byte first | ||
| 107 | assert_eq!(read(&mut uart).await, Ok([3])); | ||
| 108 | uart.blocking_write(&[8, 9]).unwrap(); | ||
| 109 | Timer::after(Duration::from_millis(1)).await; | ||
| 110 | assert_eq!(read(&mut uart).await, Ok([8, 9])); | ||
| 111 | } | ||
| 112 | |||
| 113 | info!("test break detection"); | ||
| 114 | { | ||
| 115 | let config = Config::default(); | ||
| 116 | let (mut tx, mut rx) = Uart::new( | ||
| 117 | &mut uart, | ||
| 118 | &mut tx, | ||
| 119 | &mut rx, | ||
| 120 | Irqs, | ||
| 121 | &mut p.DMA_CH0, | ||
| 122 | &mut p.DMA_CH1, | ||
| 123 | config, | ||
| 124 | ) | ||
| 125 | .split(); | ||
| 126 | |||
| 127 | // break before read | ||
| 128 | tx.send_break(20).await; | ||
| 129 | tx.write(&[64]).await.unwrap(); | ||
| 130 | assert_eq!(read1::<1>(&mut rx).await.unwrap_err(), Error::Break); | ||
| 131 | assert_eq!(read1(&mut rx).await.unwrap(), [64]); | ||
| 132 | |||
| 133 | // break during read | ||
| 134 | { | ||
| 135 | let r = read1::<2>(&mut rx); | ||
| 136 | tx.write(&[2]).await.unwrap(); | ||
| 137 | tx.send_break(20).await; | ||
| 138 | tx.write(&[3]).await.unwrap(); | ||
| 139 | assert_eq!(r.await.unwrap_err(), Error::Break); | ||
| 140 | assert_eq!(read1(&mut rx).await.unwrap(), [3]); | ||
| 141 | } | ||
| 142 | |||
| 143 | // break after read | ||
| 144 | { | ||
| 145 | let r = read1(&mut rx); | ||
| 146 | tx.write(&[2]).await.unwrap(); | ||
| 147 | tx.send_break(20).await; | ||
| 148 | tx.write(&[3]).await.unwrap(); | ||
| 149 | assert_eq!(r.await.unwrap(), [2]); | ||
| 150 | assert_eq!(read1::<1>(&mut rx).await.unwrap_err(), Error::Break); | ||
| 151 | assert_eq!(read1(&mut rx).await.unwrap(), [3]); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | // parity detection. here we bitbang to not require two uarts. | ||
| 156 | info!("test parity error detection"); | ||
| 157 | { | ||
| 158 | let mut pin = Output::new(&mut tx, Level::High); | ||
| 159 | // choose a very slow baud rate to make tests reliable even with O0 | ||
| 160 | let mut config = Config::default(); | ||
| 161 | config.baudrate = 1000; | ||
| 162 | config.parity = Parity::ParityEven; | ||
| 163 | let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); | ||
| 164 | |||
| 165 | async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, parity: u32) { | ||
| 166 | send(pin, v, Some(parity != 0)).await; | ||
| 167 | } | ||
| 168 | |||
| 169 | // first check that we can send correctly | ||
| 170 | chr(&mut pin, 32, 1).await; | ||
| 171 | assert_eq!(read1(&mut uart).await.unwrap(), [32]); | ||
| 172 | |||
| 173 | // parity error before read | ||
| 174 | chr(&mut pin, 32, 0).await; | ||
| 175 | chr(&mut pin, 31, 1).await; | ||
| 176 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity); | ||
| 177 | assert_eq!(read1(&mut uart).await.unwrap(), [31]); | ||
| 178 | |||
| 179 | // parity error during read | ||
| 180 | { | ||
| 181 | let r = read1::<2>(&mut uart); | ||
| 182 | chr(&mut pin, 2, 1).await; | ||
| 183 | chr(&mut pin, 32, 0).await; | ||
| 184 | chr(&mut pin, 3, 0).await; | ||
| 185 | assert_eq!(r.await.unwrap_err(), Error::Parity); | ||
| 186 | assert_eq!(read1(&mut uart).await.unwrap(), [3]); | ||
| 187 | } | ||
| 188 | |||
| 189 | // parity error after read | ||
| 190 | { | ||
| 191 | let r = read1(&mut uart); | ||
| 192 | chr(&mut pin, 2, 1).await; | ||
| 193 | chr(&mut pin, 32, 0).await; | ||
| 194 | chr(&mut pin, 3, 0).await; | ||
| 195 | assert_eq!(r.await.unwrap(), [2]); | ||
| 196 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Parity); | ||
| 197 | assert_eq!(read1(&mut uart).await.unwrap(), [3]); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | // framing error detection. here we bitbang because there's no other way. | ||
| 202 | info!("test framing error detection"); | ||
| 203 | { | ||
| 204 | let mut pin = Output::new(&mut tx, Level::High); | ||
| 205 | // choose a very slow baud rate to make tests reliable even with O0 | ||
| 206 | let mut config = Config::default(); | ||
| 207 | config.baudrate = 1000; | ||
| 208 | let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); | ||
| 209 | |||
| 210 | async fn chr(pin: &mut Output<'_, impl embassy_rp::gpio::Pin>, v: u8, good: bool) { | ||
| 211 | if good { | ||
| 212 | send(pin, v, None).await; | ||
| 213 | } else { | ||
| 214 | send(pin, v, Some(false)).await; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | // first check that we can send correctly | ||
| 219 | chr(&mut pin, 32, true).await; | ||
| 220 | assert_eq!(read1(&mut uart).await.unwrap(), [32]); | ||
| 221 | |||
| 222 | // parity error before read | ||
| 223 | chr(&mut pin, 32, false).await; | ||
| 224 | chr(&mut pin, 31, true).await; | ||
| 225 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing); | ||
| 226 | assert_eq!(read1(&mut uart).await.unwrap(), [31]); | ||
| 227 | |||
| 228 | // parity error during read | ||
| 229 | { | ||
| 230 | let r = read1::<2>(&mut uart); | ||
| 231 | chr(&mut pin, 2, true).await; | ||
| 232 | chr(&mut pin, 32, false).await; | ||
| 233 | chr(&mut pin, 3, true).await; | ||
| 234 | assert_eq!(r.await.unwrap_err(), Error::Framing); | ||
| 235 | assert_eq!(read1(&mut uart).await.unwrap(), [3]); | ||
| 236 | } | ||
| 237 | |||
| 238 | // parity error after read | ||
| 239 | { | ||
| 240 | let r = read1(&mut uart); | ||
| 241 | chr(&mut pin, 2, true).await; | ||
| 242 | chr(&mut pin, 32, false).await; | ||
| 243 | chr(&mut pin, 3, true).await; | ||
| 244 | assert_eq!(r.await.unwrap(), [2]); | ||
| 245 | assert_eq!(read1::<1>(&mut uart).await.unwrap_err(), Error::Framing); | ||
| 246 | assert_eq!(read1(&mut uart).await.unwrap(), [3]); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | info!("Test OK"); | ||
| 251 | cortex_m::asm::bkpt(); | ||
| 252 | } | ||
diff --git a/tests/rp/src/bin/uart_upgrade.rs b/tests/rp/src/bin/uart_upgrade.rs new file mode 100644 index 000000000..760e53954 --- /dev/null +++ b/tests/rp/src/bin/uart_upgrade.rs | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use defmt::{assert_eq, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_rp::bind_interrupts; | ||
| 10 | use embassy_rp::peripherals::UART0; | ||
| 11 | use embassy_rp::uart::{BufferedInterruptHandler, Config, Uart}; | ||
| 12 | use embedded_io::asynch::{Read, Write}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | UART0_IRQ => BufferedInterruptHandler<UART0>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) { | ||
| 21 | let p = embassy_rp::init(Default::default()); | ||
| 22 | info!("Hello World!"); | ||
| 23 | |||
| 24 | let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 25 | |||
| 26 | let config = Config::default(); | ||
| 27 | let mut uart = Uart::new_blocking(uart, tx, rx, config); | ||
| 28 | |||
| 29 | // We can't send too many bytes, they have to fit in the FIFO. | ||
| 30 | // This is because we aren't sending+receiving at the same time. | ||
| 31 | |||
| 32 | let data = [0xC0, 0xDE]; | ||
| 33 | uart.blocking_write(&data).unwrap(); | ||
| 34 | |||
| 35 | let mut buf = [0; 2]; | ||
| 36 | uart.blocking_read(&mut buf).unwrap(); | ||
| 37 | assert_eq!(buf, data); | ||
| 38 | |||
| 39 | let tx_buf = &mut [0u8; 16]; | ||
| 40 | let rx_buf = &mut [0u8; 16]; | ||
| 41 | |||
| 42 | let mut uart = uart.into_buffered(Irqs, tx_buf, rx_buf); | ||
| 43 | |||
| 44 | // Make sure we send more bytes than fits in the FIFO, to test the actual | ||
| 45 | // bufferedUart. | ||
| 46 | |||
| 47 | let data = [ | ||
| 48 | 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 49 | 30, 31, | ||
| 50 | ]; | ||
| 51 | uart.write_all(&data).await.unwrap(); | ||
| 52 | info!("Done writing"); | ||
| 53 | |||
| 54 | let mut buf = [0; 31]; | ||
| 55 | uart.read_exact(&mut buf).await.unwrap(); | ||
| 56 | assert_eq!(buf, data); | ||
| 57 | |||
| 58 | info!("Test OK"); | ||
| 59 | cortex_m::asm::bkpt(); | ||
| 60 | } | ||
diff --git a/tests/rp/src/common.rs b/tests/rp/src/common.rs new file mode 100644 index 000000000..955674f27 --- /dev/null +++ b/tests/rp/src/common.rs | |||
| @@ -0,0 +1 @@ | |||
| teleprobe_meta::target!(b"rpi-pico"); | |||
