aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
committerQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
commit6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch)
tree748f510e190bb2724750507a6e69ed1a8e08cb20 /tests
parentd896f80405aa8963877049ed999e4aba25d6e2bb (diff)
parent6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff)
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'tests')
-rw-r--r--tests/nrf/.cargo/config.toml9
-rw-r--r--tests/nrf/Cargo.toml26
-rw-r--r--tests/nrf/build.rs17
-rw-r--r--tests/nrf/link_ram.x254
-rw-r--r--tests/nrf/memory.x5
-rw-r--r--tests/nrf/src/bin/buffered_uart.rs80
-rw-r--r--tests/nrf/src/bin/buffered_uart_spam.rs93
-rw-r--r--tests/nrf/src/bin/timer.rs27
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs270
-rw-r--r--tests/nrf/src/common.rs1
-rw-r--r--tests/perf-server/Cargo.toml8
-rwxr-xr-xtests/perf-server/deploy.sh11
-rw-r--r--tests/perf-server/perf-server.service16
-rw-r--r--tests/perf-server/src/main.rs90
-rw-r--r--tests/riscv32/.cargo/config.toml5
-rw-r--r--tests/riscv32/Cargo.toml46
-rw-r--r--tests/riscv32/build.rs8
-rw-r--r--tests/riscv32/memory.x14
-rw-r--r--tests/riscv32/src/bin/empty.rs16
-rw-r--r--tests/rp/.cargo/config.toml10
-rw-r--r--tests/rp/Cargo.toml28
-rw-r--r--tests/rp/build.rs1
-rw-r--r--tests/rp/src/bin/adc.rs86
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs264
-rw-r--r--tests/rp/src/bin/dma_copy_async.rs43
-rw-r--r--tests/rp/src/bin/flash.rs65
-rw-r--r--tests/rp/src/bin/float.rs53
-rw-r--r--tests/rp/src/bin/gpio.rs66
-rw-r--r--tests/rp/src/bin/gpio_async.rs4
-rw-r--r--tests/rp/src/bin/gpio_multicore.rs65
-rw-r--r--tests/rp/src/bin/multicore.rs49
-rw-r--r--tests/rp/src/bin/pio_irq.rs55
-rw-r--r--tests/rp/src/bin/pwm.rs144
-rw-r--r--tests/rp/src/bin/spi.rs30
-rw-r--r--tests/rp/src/bin/spi_async.rs86
-rw-r--r--tests/rp/src/bin/uart.rs171
-rw-r--r--tests/rp/src/bin/uart_buffered.rs256
-rw-r--r--tests/rp/src/bin/uart_dma.rs252
-rw-r--r--tests/rp/src/bin/uart_upgrade.rs60
-rw-r--r--tests/rp/src/common.rs1
-rw-r--r--tests/stm32/.cargo/config.toml4
-rw-r--r--tests/stm32/Cargo.toml110
-rw-r--r--tests/stm32/build.rs22
-rw-r--r--tests/stm32/gen_test.py44
-rw-r--r--tests/stm32/src/bin/can.rs81
-rw-r--r--tests/stm32/src/bin/gpio.rs46
-rw-r--r--tests/stm32/src/bin/rtc.rs50
-rw-r--r--tests/stm32/src/bin/sdmmc.rs145
-rw-r--r--tests/stm32/src/bin/spi.rs28
-rw-r--r--tests/stm32/src/bin/spi_dma.rs26
-rw-r--r--tests/stm32/src/bin/timer.rs6
-rw-r--r--tests/stm32/src/bin/usart.rs132
-rw-r--r--tests/stm32/src/bin/usart_dma.rs84
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs198
-rw-r--r--tests/stm32/src/bin/wpan_ble.rs251
-rw-r--r--tests/stm32/src/bin/wpan_mac.rs120
-rw-r--r--tests/stm32/src/common.rs44
-rw-r--r--tests/stm32/src/example_common.rs31
-rw-r--r--tests/utils/Cargo.toml10
-rw-r--r--tests/utils/src/bin/saturate_serial.rs53
60 files changed, 4133 insertions, 137 deletions
diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf/.cargo/config.toml
new file mode 100644
index 000000000..03995f963
--- /dev/null
+++ b/tests/nrf/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "teleprobe local run --chip nRF52840_xxAA --elf"
3runner = "teleprobe client run"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
new file mode 100644
index 000000000..7ce51aa5e
--- /dev/null
+++ b/tests/nrf/Cargo.toml
@@ -0,0 +1,26 @@
1[package]
2edition = "2021"
3name = "embassy-nrf-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8teleprobe-meta = "1"
9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] }
14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
15embedded-io = { version = "0.4.0", features = ["async"] }
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
18embedded-hal-async = { version = "0.2.0-alpha.2" }
19static_cell = { version = "1.1", features = [ "nightly" ] }
20
21defmt = "0.3"
22defmt-rtt = "0.4"
23
24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
25cortex-m-rt = "0.7.0"
26panic-probe = { version = "0.3", features = ["print-defmt"] } \ No newline at end of file
diff --git a/tests/nrf/build.rs b/tests/nrf/build.rs
new file mode 100644
index 000000000..93e2a28cf
--- /dev/null
+++ b/tests/nrf/build.rs
@@ -0,0 +1,17 @@
1use std::error::Error;
2use std::path::PathBuf;
3use std::{env, fs};
4
5fn main() -> Result<(), Box<dyn Error>> {
6 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
7 fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
8 println!("cargo:rustc-link-search={}", out.display());
9 println!("cargo:rerun-if-changed=link_ram.x");
10
11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
15
16 Ok(())
17}
diff --git a/tests/nrf/link_ram.x b/tests/nrf/link_ram.x
new file mode 100644
index 000000000..26da86baa
--- /dev/null
+++ b/tests/nrf/link_ram.x
@@ -0,0 +1,254 @@
1/* ##### EMBASSY NOTE
2 Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in
3 Adjusted to put everything in RAM
4*/
5
6/* # Developer notes
7
8- Symbols that start with a double underscore (__) are considered "private"
9
10- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
11 overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
12 static mut __sbss }`).
13
14- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
15 symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
16 needed" by any of the preceding objects (linker arguments)
17
18- `PROVIDE` is used to provide default values that can be overridden by a user linker script
19
20- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
21 the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization
22 routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see
23 "Address (..) is out of bounds" in the disassembly produced by `objdump`.
24*/
25
26/* Provides information about the memory layout of the device */
27/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */
28INCLUDE memory.x
29
30/* # Entry point = reset vector */
31EXTERN(__RESET_VECTOR);
32EXTERN(Reset);
33ENTRY(Reset);
34
35/* # Exception vectors */
36/* This is effectively weak aliasing at the linker level */
37/* The user can override any of these aliases by defining the corresponding symbol themselves (cf.
38 the `exception!` macro) */
39EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */
40
41EXTERN(DefaultHandler);
42
43PROVIDE(NonMaskableInt = DefaultHandler);
44EXTERN(HardFaultTrampoline);
45PROVIDE(MemoryManagement = DefaultHandler);
46PROVIDE(BusFault = DefaultHandler);
47PROVIDE(UsageFault = DefaultHandler);
48PROVIDE(SecureFault = DefaultHandler);
49PROVIDE(SVCall = DefaultHandler);
50PROVIDE(DebugMonitor = DefaultHandler);
51PROVIDE(PendSV = DefaultHandler);
52PROVIDE(SysTick = DefaultHandler);
53
54PROVIDE(DefaultHandler = DefaultHandler_);
55PROVIDE(HardFault = HardFault_);
56
57/* # Interrupt vectors */
58EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
59
60/* # Pre-initialization function */
61/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function,
62 then the function this points to will be called before the RAM is initialized. */
63PROVIDE(__pre_init = DefaultPreInit);
64
65/* # Sections */
66SECTIONS
67{
68 PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
69
70 /* ## Sections in RAM */
71 /* ### Vector table */
72 .vector_table ORIGIN(RAM) :
73 {
74 /* Initial Stack Pointer (SP) value */
75 LONG(_stack_start);
76
77 /* Reset vector */
78 KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */
79 __reset_vector = .;
80
81 /* Exceptions */
82 KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */
83 __eexceptions = .;
84
85 /* Device specific interrupts */
86 KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
87 } > RAM
88
89 PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));
90
91 /* ### .text */
92 .text _stext :
93 {
94 __stext = .;
95 *(.Reset);
96
97 *(.text .text.*);
98
99 /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
100 so must be placed close to it. */
101 *(.HardFaultTrampoline);
102 *(.HardFault.*);
103
104 . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */
105 __etext = .;
106 } > RAM
107
108 /* ### .rodata */
109 .rodata : ALIGN(4)
110 {
111 . = ALIGN(4);
112 __srodata = .;
113 *(.rodata .rodata.*);
114
115 /* 4-byte align the end (VMA) of this section.
116 This is required by LLD to ensure the LMA of the following .data
117 section will have the correct alignment. */
118 . = ALIGN(4);
119 __erodata = .;
120 } > RAM
121
122 /* ## Sections in RAM */
123 /* ### .data */
124 .data : ALIGN(4)
125 {
126 . = ALIGN(4);
127 __sdata = .;
128 __edata = .;
129 *(.data .data.*);
130 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
131 } > RAM
132 /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to
133 * use the .data loading mechanism by pushing __edata. Note: do not change
134 * output region or load region in those user sections! */
135 . = ALIGN(4);
136
137 /* LMA of .data */
138 __sidata = LOADADDR(.data);
139
140 /* ### .gnu.sgstubs
141 This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
142 /* Security Attribution Unit blocks must be 32 bytes aligned. */
143 /* Note that this pads the RAM usage to 32 byte alignment. */
144 .gnu.sgstubs : ALIGN(32)
145 {
146 . = ALIGN(32);
147 __veneer_base = .;
148 *(.gnu.sgstubs*)
149 . = ALIGN(32);
150 __veneer_limit = .;
151 } > RAM
152
153 /* ### .bss */
154 .bss (NOLOAD) : ALIGN(4)
155 {
156 . = ALIGN(4);
157 __sbss = .;
158 *(.bss .bss.*);
159 *(COMMON); /* Uninitialized C statics */
160 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
161 } > RAM
162 /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to
163 * use the .bss zeroing mechanism by pushing __ebss. Note: do not change
164 * output region or load region in those user sections! */
165 . = ALIGN(4);
166 __ebss = .;
167
168 /* ### .uninit */
169 .uninit (NOLOAD) : ALIGN(4)
170 {
171 . = ALIGN(4);
172 __suninit = .;
173 *(.uninit .uninit.*);
174 . = ALIGN(4);
175 __euninit = .;
176 } > RAM
177
178 /* Place the heap right after `.uninit` in RAM */
179 PROVIDE(__sheap = __euninit);
180
181 /* ## .got */
182 /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
183 the input files and raise an error if relocatable code is found */
184 .got (NOLOAD) :
185 {
186 KEEP(*(.got .got.*));
187 }
188
189 /* ## Discarded sections */
190 /DISCARD/ :
191 {
192 /* Unused exception related info that only wastes space */
193 *(.ARM.exidx);
194 *(.ARM.exidx.*);
195 *(.ARM.extab.*);
196 }
197}
198
199/* Do not exceed this mark in the error messages below | */
200/* # Alignment checks */
201ASSERT(ORIGIN(RAM) % 4 == 0, "
202ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
203
204ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
205BUG(cortex-m-rt): .data is not 4-byte aligned");
206
207ASSERT(__sidata % 4 == 0, "
208BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
209
210ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
211BUG(cortex-m-rt): .bss is not 4-byte aligned");
212
213ASSERT(__sheap % 4 == 0, "
214BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
215
216/* # Position checks */
217
218/* ## .vector_table */
219ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, "
220BUG(cortex-m-rt): the reset vector is missing");
221
222ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, "
223BUG(cortex-m-rt): the exception vectors are missing");
224
225ASSERT(SIZEOF(.vector_table) > 0x40, "
226ERROR(cortex-m-rt): The interrupt vectors are missing.
227Possible solutions, from most likely to less likely:
228- Link to a svd2rust generated device crate
229- Check that you actually use the device/hal/bsp crate in your code
230- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
231may be enabling it)
232- Supply the interrupt handlers yourself. Check the documentation for details.");
233
234/* ## .text */
235ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
236ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
237Set _stext to an address greater than the end of .vector_table (See output of `nm`)");
238
239ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), "
240ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory.
241Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'");
242
243/* # Other checks */
244ASSERT(SIZEOF(.got) == 0, "
245ERROR(cortex-m-rt): .got section detected in the input object files
246Dynamic relocations are not supported. If you are linking to C code compiled using
247the 'cc' crate then modify your build script to compile the C code _without_
248the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
249/* Do not exceed this mark in the error messages above | */
250
251
252/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */
253/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */
254INCLUDE device.x \ No newline at end of file
diff --git a/tests/nrf/memory.x b/tests/nrf/memory.x
new file mode 100644
index 000000000..58900a7bd
--- /dev/null
+++ b/tests/nrf/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x20000000, LENGTH = 256K
5}
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs
new file mode 100644
index 000000000..72a4cb4ef
--- /dev/null
+++ b/tests/nrf/src/bin/buffered_uart.rs
@@ -0,0 +1,80 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use defmt::{assert_eq, *};
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_nrf::buffered_uarte::{self, BufferedUarte};
11use embassy_nrf::{bind_interrupts, peripherals, uarte};
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default());
21 let mut config = uarte::Config::default();
22 config.parity = uarte::Parity::EXCLUDED;
23 config.baudrate = uarte::Baudrate::BAUD1M;
24
25 let mut tx_buffer = [0u8; 1024];
26 let mut rx_buffer = [0u8; 1024];
27
28 let mut u = BufferedUarte::new(
29 p.UARTE0,
30 p.TIMER0,
31 p.PPI_CH0,
32 p.PPI_CH1,
33 p.PPI_GROUP0,
34 Irqs,
35 p.P1_03,
36 p.P1_02,
37 config.clone(),
38 &mut rx_buffer,
39 &mut tx_buffer,
40 );
41
42 info!("uarte initialized!");
43
44 let (mut rx, mut tx) = u.split();
45
46 const COUNT: usize = 40_000;
47
48 let tx_fut = async {
49 let mut tx_buf = [0; 215];
50 let mut i = 0;
51 while i < COUNT {
52 let n = tx_buf.len().min(COUNT - i);
53 let tx_buf = &mut tx_buf[..n];
54 for (j, b) in tx_buf.iter_mut().enumerate() {
55 *b = (i + j) as u8;
56 }
57 let n = unwrap!(tx.write(tx_buf).await);
58 i += n;
59 }
60 };
61 let rx_fut = async {
62 let mut i = 0;
63 while i < COUNT {
64 let buf = unwrap!(rx.fill_buf().await);
65
66 for &b in buf {
67 assert_eq!(b, i as u8);
68 i = i + 1;
69 }
70
71 let n = buf.len();
72 rx.consume(n);
73 }
74 };
75
76 join(rx_fut, tx_fut).await;
77
78 info!("Test OK");
79 cortex_m::asm::bkpt();
80}
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs
new file mode 100644
index 000000000..50960206f
--- /dev/null
+++ b/tests/nrf/src/bin/buffered_uart_spam.rs
@@ -0,0 +1,93 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use core::mem;
8use core::ptr::NonNull;
9
10use defmt::{assert_eq, *};
11use embassy_executor::Spawner;
12use embassy_nrf::buffered_uarte::{self, BufferedUarte};
13use embassy_nrf::gpio::{Level, Output, OutputDrive};
14use embassy_nrf::ppi::{Event, Ppi, Task};
15use embassy_nrf::uarte::Uarte;
16use embassy_nrf::{bind_interrupts, pac, peripherals, uarte};
17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
22 UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;
23});
24
25#[embassy_executor::main]
26async fn main(_spawner: Spawner) {
27 let mut p = embassy_nrf::init(Default::default());
28 let mut config = uarte::Config::default();
29 config.parity = uarte::Parity::EXCLUDED;
30 config.baudrate = uarte::Baudrate::BAUD1M;
31
32 let mut tx_buffer = [0u8; 1024];
33 let mut rx_buffer = [0u8; 1024];
34
35 mem::forget(Output::new(&mut p.P1_02, Level::High, OutputDrive::Standard));
36
37 let mut u = BufferedUarte::new(
38 p.UARTE0,
39 p.TIMER0,
40 p.PPI_CH0,
41 p.PPI_CH1,
42 p.PPI_GROUP0,
43 Irqs,
44 p.P1_03,
45 p.P1_04,
46 config.clone(),
47 &mut rx_buffer,
48 &mut tx_buffer,
49 );
50
51 info!("uarte initialized!");
52
53 // uarte needs some quiet time to start rxing properly.
54 Timer::after(Duration::from_millis(10)).await;
55
56 // Tx spam in a loop.
57 const NSPAM: usize = 17;
58 static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
59 let _spam = Uarte::new(p.UARTE1, Irqs, p.P1_01, p.P1_02, config.clone());
60 let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) };
61 let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) };
62 let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) };
63 let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task);
64 spam_ppi.enable();
65 let p = unsafe { TX_BUF.as_mut_ptr() };
66 spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) });
67 spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) });
68 spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) });
69
70 let mut i = 0;
71 let mut total = 0;
72 while total < 256 * 1024 {
73 let buf = unwrap!(u.fill_buf().await);
74 //info!("rx {}", buf);
75
76 for &b in buf {
77 assert_eq!(b, unsafe { TX_BUF[i] });
78
79 i = i + 1;
80 if i == NSPAM {
81 i = 0;
82 }
83 }
84
85 // Read bytes have to be explicitly consumed, otherwise fill_buf() will return them again
86 let n = buf.len();
87 u.consume(n);
88 total += n;
89 }
90
91 info!("Test OK");
92 cortex_m::asm::bkpt();
93}
diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf/src/bin/timer.rs
new file mode 100644
index 000000000..607c5bbf1
--- /dev/null
+++ b/tests/nrf/src/bin/timer.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"]
5mod common;
6
7use defmt::{assert, info};
8use embassy_executor::Spawner;
9use embassy_time::{Duration, Instant, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let _p = embassy_nrf::init(Default::default());
15 info!("Hello World!");
16
17 let start = Instant::now();
18 Timer::after(Duration::from_millis(100)).await;
19 let end = Instant::now();
20 let ms = (end - start).as_millis();
21 info!("slept for {} ms", ms);
22 assert!(ms >= 99);
23 assert!(ms < 110);
24
25 info!("Test OK");
26 cortex_m::asm::bkpt();
27}
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
new file mode 100644
index 000000000..398ab9d27
--- /dev/null
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -0,0 +1,270 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../common.rs"]
6mod common;
7
8use defmt::{error, info, unwrap};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Ipv4Address, Stack, StackResources};
13use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
14use embassy_nrf::rng::Rng;
15use embassy_nrf::spim::{self, Spim};
16use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{with_timeout, Delay, Duration, Timer};
18use embedded_hal_async::spi::ExclusiveDevice;
19use static_cell::make_static;
20use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
21
22teleprobe_meta::timeout!(120);
23
24bind_interrupts!(struct Irqs {
25 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
26 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
27});
28
29#[embassy_executor::task]
30async fn wifi_task(
31 runner: hosted::Runner<
32 'static,
33 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>, Delay>,
34 Input<'static, AnyPin>,
35 Output<'static, peripherals::P1_05>,
36 >,
37) -> ! {
38 runner.run().await
39}
40
41type MyDriver = hosted::NetDriver<'static>;
42
43#[embassy_executor::task]
44async fn net_task(stack: &'static Stack<MyDriver>) -> ! {
45 stack.run().await
46}
47
48#[embassy_executor::main]
49async fn main(spawner: Spawner) {
50 info!("Hello World!");
51
52 let p = embassy_nrf::init(Default::default());
53
54 let miso = p.P0_28;
55 let sck = p.P0_29;
56 let mosi = p.P0_30;
57 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
58 let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
59 let ready = Input::new(p.P1_04.degrade(), Pull::None);
60 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
61
62 let mut config = spim::Config::default();
63 config.frequency = spim::Frequency::M32;
64 config.mode = spim::MODE_2; // !!!
65 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
66 let spi = ExclusiveDevice::new(spi, cs, Delay);
67
68 let (device, mut control, runner) = embassy_net_esp_hosted::new(
69 make_static!(embassy_net_esp_hosted::State::new()),
70 spi,
71 handshake,
72 ready,
73 reset,
74 )
75 .await;
76
77 unwrap!(spawner.spawn(wifi_task(runner)));
78
79 control.init().await;
80 control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
81
82 // Generate random seed
83 let mut rng = Rng::new(p.RNG, Irqs);
84 let mut seed = [0; 8];
85 rng.blocking_fill_bytes(&mut seed);
86 let seed = u64::from_le_bytes(seed);
87
88 // Init network stack
89 let stack = &*make_static!(Stack::new(
90 device,
91 Config::dhcpv4(Default::default()),
92 make_static!(StackResources::<2>::new()),
93 seed
94 ));
95
96 unwrap!(spawner.spawn(net_task(stack)));
97
98 info!("Waiting for DHCP up...");
99 while stack.config_v4().is_none() {
100 Timer::after(Duration::from_millis(100)).await;
101 }
102 info!("IP addressing up!");
103
104 let down = test_download(stack).await;
105 let up = test_upload(stack).await;
106 let updown = test_upload_download(stack).await;
107
108 assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
109 assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
110 assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
111
112 info!("Test OK");
113 cortex_m::asm::bkpt();
114}
115
116// Test-only wifi network, no internet access!
117const WIFI_NETWORK: &str = "EmbassyTest";
118const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
119
120const TEST_DURATION: usize = 10;
121const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 150;
122const TEST_EXPECTED_UPLOAD_KBPS: usize = 150;
123const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150;
124const RX_BUFFER_SIZE: usize = 4096;
125const TX_BUFFER_SIZE: usize = 4096;
126const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
127const DOWNLOAD_PORT: u16 = 4321;
128const UPLOAD_PORT: u16 = 4322;
129const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
130
131async fn test_download(stack: &'static Stack<MyDriver>) -> usize {
132 info!("Testing download...");
133
134 let mut rx_buffer = [0; RX_BUFFER_SIZE];
135 let mut tx_buffer = [0; TX_BUFFER_SIZE];
136 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
137 socket.set_timeout(Some(Duration::from_secs(10)));
138
139 info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
140 if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
141 error!("connect error: {:?}", e);
142 return 0;
143 }
144 info!("connected, testing...");
145
146 let mut rx_buf = [0; 4096];
147 let mut total: usize = 0;
148 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
149 loop {
150 match socket.read(&mut rx_buf).await {
151 Ok(0) => {
152 error!("read EOF");
153 return 0;
154 }
155 Ok(n) => total += n,
156 Err(e) => {
157 error!("read error: {:?}", e);
158 return 0;
159 }
160 }
161 }
162 })
163 .await
164 .ok();
165
166 let kbps = (total + 512) / 1024 / TEST_DURATION;
167 info!("download: {} kB/s", kbps);
168 kbps
169}
170
171async fn test_upload(stack: &'static Stack<MyDriver>) -> usize {
172 info!("Testing upload...");
173
174 let mut rx_buffer = [0; RX_BUFFER_SIZE];
175 let mut tx_buffer = [0; TX_BUFFER_SIZE];
176 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
177 socket.set_timeout(Some(Duration::from_secs(10)));
178
179 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
180 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
181 error!("connect error: {:?}", e);
182 return 0;
183 }
184 info!("connected, testing...");
185
186 let buf = [0; 4096];
187 let mut total: usize = 0;
188 with_timeout(Duration::from_secs(TEST_DURATION as _), async {
189 loop {
190 match socket.write(&buf).await {
191 Ok(0) => {
192 error!("write zero?!??!?!");
193 return 0;
194 }
195 Ok(n) => total += n,
196 Err(e) => {
197 error!("write error: {:?}", e);
198 return 0;
199 }
200 }
201 }
202 })
203 .await
204 .ok();
205
206 let kbps = (total + 512) / 1024 / TEST_DURATION;
207 info!("upload: {} kB/s", kbps);
208 kbps
209}
210
211async fn test_upload_download(stack: &'static Stack<MyDriver>) -> usize {
212 info!("Testing upload+download...");
213
214 let mut rx_buffer = [0; RX_BUFFER_SIZE];
215 let mut tx_buffer = [0; TX_BUFFER_SIZE];
216 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
217 socket.set_timeout(Some(Duration::from_secs(10)));
218
219 info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
220 if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
221 error!("connect error: {:?}", e);
222 return 0;
223 }
224 info!("connected, testing...");
225
226 let (mut reader, mut writer) = socket.split();
227
228 let tx_buf = [0; 4096];
229 let mut rx_buf = [0; 4096];
230 let mut total: usize = 0;
231 let tx_fut = async {
232 loop {
233 match writer.write(&tx_buf).await {
234 Ok(0) => {
235 error!("write zero?!??!?!");
236 return 0;
237 }
238 Ok(_) => {}
239 Err(e) => {
240 error!("write error: {:?}", e);
241 return 0;
242 }
243 }
244 }
245 };
246
247 let rx_fut = async {
248 loop {
249 match reader.read(&mut rx_buf).await {
250 Ok(0) => {
251 error!("read EOF");
252 return 0;
253 }
254 Ok(n) => total += n,
255 Err(e) => {
256 error!("read error: {:?}", e);
257 return 0;
258 }
259 }
260 }
261 };
262
263 with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
264 .await
265 .ok();
266
267 let kbps = (total + 512) / 1024 / TEST_DURATION;
268 info!("upload+download: {} kB/s", kbps);
269 kbps
270}
diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs
new file mode 100644
index 000000000..1a05ac1c5
--- /dev/null
+++ b/tests/nrf/src/common.rs
@@ -0,0 +1 @@
teleprobe_meta::target!(b"nrf52840-dk");
diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml
new file mode 100644
index 000000000..532039050
--- /dev/null
+++ b/tests/perf-server/Cargo.toml
@@ -0,0 +1,8 @@
1[package]
2name = "perf-server"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7log = "0.4.17"
8pretty_env_logger = "0.4.0"
diff --git a/tests/perf-server/deploy.sh b/tests/perf-server/deploy.sh
new file mode 100755
index 000000000..032e99c30
--- /dev/null
+++ b/tests/perf-server/deploy.sh
@@ -0,0 +1,11 @@
1#!/bin/bash
2
3set -euxo pipefail
4
5[email protected]
6
7cargo build --release
8ssh $HOST -- systemctl stop perf-server
9scp target/release/perf-server $HOST:/root
10scp perf-server.service $HOST:/etc/systemd/system/
11ssh $HOST -- 'systemctl daemon-reload; systemctl restart perf-server' \ No newline at end of file
diff --git a/tests/perf-server/perf-server.service b/tests/perf-server/perf-server.service
new file mode 100644
index 000000000..c14c5d16f
--- /dev/null
+++ b/tests/perf-server/perf-server.service
@@ -0,0 +1,16 @@
1[Unit]
2Description=perf-server
3After=network.target
4StartLimitIntervalSec=0
5
6[Service]
7Type=simple
8Restart=always
9RestartSec=1
10User=root
11ExecStart=/root/perf-server
12Environment=RUST_BACKTRACE=1
13Environment=RUST_LOG=info
14
15[Install]
16WantedBy=multi-user.target
diff --git a/tests/perf-server/src/main.rs b/tests/perf-server/src/main.rs
new file mode 100644
index 000000000..f6e7efc59
--- /dev/null
+++ b/tests/perf-server/src/main.rs
@@ -0,0 +1,90 @@
1use std::io::{Read, Write};
2use std::net::{TcpListener, TcpStream};
3use std::thread::spawn;
4use std::time::Duration;
5
6use log::info;
7
8fn main() {
9 pretty_env_logger::init();
10 spawn(|| rx_listen());
11 spawn(|| rxtx_listen());
12 tx_listen();
13}
14
15fn tx_listen() {
16 info!("tx: listening on 0.0.0.0:4321");
17 let listener = TcpListener::bind("0.0.0.0:4321").unwrap();
18 loop {
19 let (socket, addr) = listener.accept().unwrap();
20 info!("tx: received connection from: {}", addr);
21 spawn(|| tx_conn(socket));
22 }
23}
24
25fn tx_conn(mut socket: TcpStream) {
26 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
27 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
28
29 let buf = [0; 1024];
30 loop {
31 if let Err(e) = socket.write_all(&buf) {
32 info!("tx: failed to write to socket; err = {:?}", e);
33 return;
34 }
35 }
36}
37
38fn rx_listen() {
39 info!("rx: listening on 0.0.0.0:4322");
40 let listener = TcpListener::bind("0.0.0.0:4322").unwrap();
41 loop {
42 let (socket, addr) = listener.accept().unwrap();
43 info!("rx: received connection from: {}", addr);
44 spawn(|| rx_conn(socket));
45 }
46}
47
48fn rx_conn(mut socket: TcpStream) {
49 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
50 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
51
52 let mut buf = [0; 1024];
53 loop {
54 if let Err(e) = socket.read_exact(&mut buf) {
55 info!("rx: failed to read from socket; err = {:?}", e);
56 return;
57 }
58 }
59}
60
61fn rxtx_listen() {
62 info!("rxtx: listening on 0.0.0.0:4323");
63 let listener = TcpListener::bind("0.0.0.0:4323").unwrap();
64 loop {
65 let (socket, addr) = listener.accept().unwrap();
66 info!("rxtx: received connection from: {}", addr);
67 spawn(|| rxtx_conn(socket));
68 }
69}
70
71fn rxtx_conn(mut socket: TcpStream) {
72 socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap();
73 socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap();
74
75 let mut buf = [0; 1024];
76 loop {
77 match socket.read(&mut buf) {
78 Ok(n) => {
79 if let Err(e) = socket.write_all(&buf[..n]) {
80 info!("rxtx: failed to write to socket; err = {:?}", e);
81 return;
82 }
83 }
84 Err(e) => {
85 info!("rxtx: failed to read from socket; err = {:?}", e);
86 return;
87 }
88 }
89 }
90}
diff --git a/tests/riscv32/.cargo/config.toml b/tests/riscv32/.cargo/config.toml
new file mode 100644
index 000000000..58299b54e
--- /dev/null
+++ b/tests/riscv32/.cargo/config.toml
@@ -0,0 +1,5 @@
1[target.riscv32imac-unknown-none-elf]
2runner = "true"
3
4[build]
5target = "riscv32imac-unknown-none-elf"
diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml
new file mode 100644
index 000000000..61f886c0c
--- /dev/null
+++ b/tests/riscv32/Cargo.toml
@@ -0,0 +1,46 @@
1[package]
2edition = "2021"
3name = "embassy-riscv-tests"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8critical-section = { version = "1.1.1", features = ["restore-state-bool"] }
9embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
10embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] }
11embassy-time = { version = "0.1.2", path = "../../embassy-time" }
12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13
14riscv-rt = "0.11"
15riscv = { version = "0.10", features = ["critical-section-single-hart"] }
16
17
18[profile.dev]
19debug = 2
20debug-assertions = true
21opt-level = 's'
22overflow-checks = true
23
24[profile.release]
25codegen-units = 1
26debug = 2
27debug-assertions = false
28incremental = false
29lto = "fat"
30opt-level = 's'
31overflow-checks = false
32
33# do not optimize proc-macro crates = faster builds from scratch
34[profile.dev.build-override]
35codegen-units = 8
36debug = false
37debug-assertions = false
38opt-level = 0
39overflow-checks = false
40
41[profile.release.build-override]
42codegen-units = 8
43debug = false
44debug-assertions = false
45opt-level = 0
46overflow-checks = false
diff --git a/tests/riscv32/build.rs b/tests/riscv32/build.rs
new file mode 100644
index 000000000..e4a26c4a1
--- /dev/null
+++ b/tests/riscv32/build.rs
@@ -0,0 +1,8 @@
1use std::error::Error;
2
3fn main() -> Result<(), Box<dyn Error>> {
4 println!("cargo:rustc-link-arg-bins=-Tmemory.x");
5 println!("cargo:rustc-link-arg-bins=-Tlink.x");
6
7 Ok(())
8}
diff --git a/tests/riscv32/memory.x b/tests/riscv32/memory.x
new file mode 100644
index 000000000..316d577d4
--- /dev/null
+++ b/tests/riscv32/memory.x
@@ -0,0 +1,14 @@
1MEMORY
2{
3 ROM : ORIGIN = 0x80000000, LENGTH = 0x00020000
4 RAM : ORIGIN = 0x84000000, LENGTH = 0x00008000
5}
6
7REGION_ALIAS("REGION_TEXT", ROM);
8REGION_ALIAS("REGION_RODATA", ROM);
9REGION_ALIAS("REGION_DATA", RAM);
10REGION_ALIAS("REGION_BSS", RAM);
11REGION_ALIAS("REGION_HEAP", RAM);
12REGION_ALIAS("REGION_STACK", RAM);
13
14_stack_start = ORIGIN(RAM) + LENGTH(RAM) - 4;
diff --git a/tests/riscv32/src/bin/empty.rs b/tests/riscv32/src/bin/empty.rs
new file mode 100644
index 000000000..1874caec4
--- /dev/null
+++ b/tests/riscv32/src/bin/empty.rs
@@ -0,0 +1,16 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6
7#[panic_handler]
8fn panic(_info: &core::panic::PanicInfo) -> ! {
9 loop {}
10}
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 // Don't do anything, just make sure it compiles.
15 loop {}
16}
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml
index 0330025e4..bc92e788b 100644
--- a/tests/rp/.cargo/config.toml
+++ b/tests/rp/.cargo/config.toml
@@ -1,10 +1,12 @@
1[unstable] 1[unstable]
2build-std = ["core"] 2# enabling these breaks the float tests during linking, with intrinsics
3build-std-features = ["panic_immediate_abort"] 3# duplicated between embassy-rp and compilter_builtins
4#build-std = ["core"]
5#build-std-features = ["panic_immediate_abort"]
4 6
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 7[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6#runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" 8runner = "teleprobe client run"
7runner = "teleprobe local run --chip RP2040 --elf" 9#runner = "teleprobe local run --chip RP2040 --elf"
8 10
9rustflags = [ 11rustflags = [
10 # Code-size optimizations. 12 # Code-size optimizations.
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 4d6877ccd..f2c902787 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -2,23 +2,35 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-rp-tests" 3name = "embassy-rp-tests"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8teleprobe-meta = "1.1"
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
17cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
11 18
12defmt = "0.3.0" 19defmt = "0.3.0"
13defmt-rtt = "0.3.0" 20defmt-rtt = "0.4"
14 21
15cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 22cortex-m = { version = "0.7.6" }
16cortex-m-rt = "0.7.0" 23cortex-m-rt = "0.7.0"
17embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
18embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 25embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
19embedded-hal-async = { version = "0.1.0-alpha.1" } 26embedded-hal-async = { version = "=0.2.0-alpha.2" }
20panic-probe = { version = "0.3.0", features = ["print-defmt"] } 27panic-probe = { version = "0.3.0", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 28futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
29embedded-io = { version = "0.4.0", features = ["async"] }
30embedded-storage = { version = "0.3" }
31static_cell = { version = "1.1", features = ["nightly"]}
32pio = "0.2"
33pio-proc = "0.2"
22 34
23[profile.dev] 35[profile.dev]
24debug = 2 36debug = 2
diff --git a/tests/rp/build.rs b/tests/rp/build.rs
index 6f4872249..93e2a28cf 100644
--- a/tests/rp/build.rs
+++ b/tests/rp/build.rs
@@ -11,6 +11,7 @@ fn main() -> Result<(), Box<dyn Error>> {
11 println!("cargo:rustc-link-arg-bins=--nmagic"); 11 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); 12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
14 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
14 15
15 Ok(()) 16 Ok(())
16} 17}
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"]
5mod common;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::Pull;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 ADC_IRQ_FIFO => InterruptHandler;
16});
17
18#[embassy_executor::main]
19async 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
83fn 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"]
5mod common;
6
7use cyw43_pio::PioSpi;
8use defmt::{assert, panic, *};
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Ipv4Address, Stack, StackResources};
13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::{InterruptHandler, Pio};
16use embassy_rp::{bind_interrupts, rom_data};
17use embassy_time::{with_timeout, Duration, Timer};
18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _};
20
21bind_interrupts!(struct Irqs {
22 PIO0_IRQ_0 => InterruptHandler<PIO0>;
23});
24
25teleprobe_meta::timeout!(120);
26
27#[embassy_executor::task]
28async 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]
35async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
36 stack.run().await
37}
38
39#[embassy_executor::main]
40async 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!
111const WIFI_NETWORK: &str = "EmbassyTest";
112const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
113
114const TEST_DURATION: usize = 10;
115const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300;
116const TEST_EXPECTED_UPLOAD_KBPS: usize = 300;
117const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300;
118const RX_BUFFER_SIZE: usize = 4096;
119const TX_BUFFER_SIZE: usize = 4096;
120const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
121const DOWNLOAD_PORT: u16 = 4321;
122const UPLOAD_PORT: u16 = 4322;
123const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
124
125async 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
165async 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
205async 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"]
5mod common;
6
7use defmt::{assert_eq, *};
8use embassy_executor::Spawner;
9use embassy_rp::dma::copy;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async 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"]
5mod common;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDR_OFFSET: u32 = 0x4000;
14
15#[embassy_executor::main]
16async 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"]
5mod common;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::pac;
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async 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"]
5mod common;
4 6
5use defmt::{assert, *}; 7use defmt::{assert, *};
6use embassy_executor::Spawner; 8use 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"]
5mod common;
4 6
5use defmt::{assert, *}; 7use defmt::{assert, *};
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join;
7use embassy_rp::gpio::{Input, Level, Output, Pull}; 10use embassy_rp::gpio::{Input, Level, Output, Pull};
8use embassy_time::{Duration, Instant, Timer}; 11use embassy_time::{Duration, Instant, Timer};
9use futures::future::join;
10use {defmt_rtt as _, panic_probe as _}; 12use {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"]
5mod common;
6
7use defmt::{info, unwrap};
8use embassy_executor::Executor;
9use embassy_executor::_export::StaticCell;
10use embassy_rp::gpio::{Input, Level, Output, Pull};
11use embassy_rp::multicore::{spawn_core1, Stack};
12use embassy_rp::peripherals::{PIN_0, PIN_1};
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14use embassy_sync::channel::Channel;
15use {defmt_rtt as _, panic_probe as _};
16
17static mut CORE1_STACK: Stack<1024> = Stack::new();
18static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
19static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
20static CHANNEL0: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
21static CHANNEL1: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
22
23#[cortex_m_rt::entry]
24fn 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]
35async 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]
52async 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"]
5mod common;
6
7use defmt::{info, unwrap};
8use embassy_executor::Executor;
9use embassy_executor::_export::StaticCell;
10use embassy_rp::multicore::{spawn_core1, Stack};
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
12use embassy_sync::channel::Channel;
13use {defmt_rtt as _, panic_probe as _};
14
15static mut CORE1_STACK: Stack<1024> = Stack::new();
16static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
17static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
18static CHANNEL0: Channel<CriticalSectionRawMutex, bool, 1> = Channel::new();
19static CHANNEL1: Channel<CriticalSectionRawMutex, bool, 1> = Channel::new();
20
21#[cortex_m_rt::entry]
22fn 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]
33async 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]
45async 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"]
5mod common;
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Config, InterruptHandler, Pio};
12use embassy_rp::relocate::RelocatedProgram;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 PIO0_IRQ_0 => InterruptHandler<PIO0>;
17});
18
19#[embassy_executor::main]
20async 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"]
5mod common;
6
7use defmt::{assert, assert_eq, assert_ne, *};
8use embassy_executor::Spawner;
9use embassy_rp::gpio::{Input, Level, Output, Pull};
10use embassy_rp::pwm::{Config, InputMode, Pwm};
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async 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"]
5mod common;
6
7use defmt::{assert_eq, *};
8use embassy_executor::Spawner;
9use embassy_rp::spi::{Config, Spi};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async 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"]
8mod common;
9
10use defmt::{assert_eq, *};
11use embassy_executor::Spawner;
12use embassy_rp::spi::{Config, Spi};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async 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"]
5mod common;
6
7use defmt::{assert_eq, *};
8use embassy_executor::Spawner;
9use embassy_rp::gpio::{Level, Output};
10use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx};
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14fn 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
20fn 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
26async 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]
50async 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"]
5mod common;
6
7use defmt::{assert_eq, panic, *};
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::peripherals::UART0;
12use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
13use embassy_time::{Duration, Timer};
14use embedded_io::asynch::{Read, ReadExactError, Write};
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 UART0_IRQ => BufferedInterruptHandler<UART0>;
19});
20
21async 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
31async 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
41async 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]
65async 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"]
5mod common;
6
7use defmt::{assert_eq, *};
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::peripherals::UART0;
12use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx};
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 UART0_IRQ => InterruptHandler<UART0>;
18});
19
20async 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
26async 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
32async 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]
56async 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"]
5mod common;
6
7use defmt::{assert_eq, *};
8use embassy_executor::Spawner;
9use embassy_rp::bind_interrupts;
10use embassy_rp::peripherals::UART0;
11use embassy_rp::uart::{BufferedInterruptHandler, Config, Uart};
12use embedded_io::asynch::{Read, Write};
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 UART0_IRQ => BufferedInterruptHandler<UART0>;
17});
18
19#[embassy_executor::main]
20async 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");
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml
index 29c4799a1..07761b01c 100644
--- a/tests/stm32/.cargo/config.toml
+++ b/tests/stm32/.cargo/config.toml
@@ -3,7 +3,7 @@ build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" 6runner = "teleprobe client run"
7#runner = "teleprobe local run --chip STM32F103C8 --elf" 7#runner = "teleprobe local run --chip STM32F103C8 --elf"
8 8
9rustflags = [ 9rustflags = [
@@ -17,4 +17,4 @@ rustflags = [
17target = "thumbv7m-none-eabi" 17target = "thumbv7m-none-eabi"
18 18
19[env] 19[env]
20DEFMT_LOG = "trace" 20DEFMT_LOG = "trace" \ No newline at end of file
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index f1441d00c..3007cd1e6 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -2,31 +2,115 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32-tests" 3name = "embassy-stm32-tests"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6autobins = false
5 7
6[features] 8[features]
7stm32f103c8 = ["embassy-stm32/stm32f103c8"] # Blue Pill 9stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill
8stm32f429zi = ["embassy-stm32/stm32f429zi"] # Nucleo 10stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "can", "not-gpdma"] # Nucleo "sdmmc"
9stm32g071rb = ["embassy-stm32/stm32g071rb"] # Nucleo 11stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
10stm32g491re = ["embassy-stm32/stm32g491re"] # Nucleo 12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
11stm32h755zi = ["embassy-stm32/stm32h755zi-cm7"] # Nucleo 13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
12stm32wb55rg = ["embassy-stm32/stm32wb55rg"] # Nucleo 14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo
16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
13stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
14 18
19sdmmc = []
20chrono = ["embassy-stm32/chrono", "dep:chrono"]
21can = []
22ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
23mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
24embassy-stm32-wpan = []
25not-gpdma = []
26
15[dependencies] 27[dependencies]
16embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 28teleprobe-meta = "1"
17embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 29
18embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-32768hz"] } 30embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
19embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] } 31embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
32embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
33embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
34embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
35embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] }
20 36
21defmt = "0.3.0" 37defmt = "0.3.0"
22defmt-rtt = "0.3.0" 38defmt-rtt = "0.4"
23 39
24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 40cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 41cortex-m-rt = "0.7.0"
26embedded-hal = "0.2.6" 42embedded-hal = "0.2.6"
27embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 43embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
28embedded-hal-async = { version = "0.1.0-alpha.1" } 44embedded-hal-async = { version = "=0.2.0-alpha.2" }
29panic-probe = { version = "0.3.0", features = ["print-defmt"] } 45panic-probe = { version = "0.3.0", features = ["print-defmt"] }
46rand_core = { version = "0.6", default-features = false }
47rand_chacha = { version = "0.3", default-features = false }
48
49chrono = { version = "^0.4", default-features = false, optional = true}
50
51# BEGIN TESTS
52# Generated by gen_test.py. DO NOT EDIT.
53[[bin]]
54name = "can"
55path = "src/bin/can.rs"
56required-features = [ "can",]
57
58[[bin]]
59name = "gpio"
60path = "src/bin/gpio.rs"
61required-features = []
62
63[[bin]]
64name = "rtc"
65path = "src/bin/rtc.rs"
66required-features = [ "chrono",]
67
68[[bin]]
69name = "sdmmc"
70path = "src/bin/sdmmc.rs"
71required-features = [ "sdmmc",]
72
73[[bin]]
74name = "spi"
75path = "src/bin/spi.rs"
76required-features = []
77
78[[bin]]
79name = "spi_dma"
80path = "src/bin/spi_dma.rs"
81required-features = []
82
83[[bin]]
84name = "timer"
85path = "src/bin/timer.rs"
86required-features = []
87
88[[bin]]
89name = "usart"
90path = "src/bin/usart.rs"
91required-features = []
92
93[[bin]]
94name = "usart_dma"
95path = "src/bin/usart_dma.rs"
96required-features = []
97
98[[bin]]
99name = "usart_rx_ringbuffered"
100path = "src/bin/usart_rx_ringbuffered.rs"
101required-features = [ "not-gpdma",]
102
103[[bin]]
104name = "wpan_ble"
105path = "src/bin/wpan_ble.rs"
106required-features = [ "ble",]
107
108[[bin]]
109name = "wpan_mac"
110path = "src/bin/wpan_mac.rs"
111required-features = [ "mac",]
112
113# END TESTS
30 114
31[profile.dev] 115[profile.dev]
32debug = 2 116debug = 2
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index 6f4872249..2e71954d7 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -6,11 +6,27 @@ fn main() -> Result<(), Box<dyn Error>> {
6 let out = PathBuf::from(env::var("OUT_DIR").unwrap()); 6 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
7 fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); 7 fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
8 println!("cargo:rustc-link-search={}", out.display()); 8 println!("cargo:rustc-link-search={}", out.display());
9 println!("cargo:rerun-if-changed=link_ram.x");
10
11 println!("cargo:rustc-link-arg-bins=--nmagic"); 9 println!("cargo:rustc-link-arg-bins=--nmagic");
12 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); 10
11 // too little RAM to run from RAM.
12 if cfg!(any(
13 feature = "stm32f103c8",
14 feature = "stm32c031c6",
15 feature = "stm32wb55rg"
16 )) {
17 println!("cargo:rustc-link-arg-bins=-Tlink.x");
18 println!("cargo:rerun-if-changed=link.x");
19 } else {
20 println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
21 println!("cargo:rerun-if-changed=link_ram.x");
22 }
23
24 if cfg!(feature = "stm32wb55rg") {
25 println!("cargo:rustc-link-arg-bins=-Ttl_mbox.x");
26 }
27
13 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 28 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
29 println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
14 30
15 Ok(()) 31 Ok(())
16} 32}
diff --git a/tests/stm32/gen_test.py b/tests/stm32/gen_test.py
new file mode 100644
index 000000000..8ff156c0e
--- /dev/null
+++ b/tests/stm32/gen_test.py
@@ -0,0 +1,44 @@
1import os
2import toml
3from glob import glob
4
5abspath = os.path.abspath(__file__)
6dname = os.path.dirname(abspath)
7os.chdir(dname)
8
9# ======= load test list
10tests = {}
11for f in sorted(glob('./src/bin/*.rs')):
12 name = os.path.splitext(os.path.basename(f))[0]
13 features = []
14 with open(f, 'r') as f:
15 for line in f:
16 if line.startswith('// required-features:'):
17 features = line.split(':', 2)[1].strip().split(',')
18
19 tests[name] = features
20
21# ========= Update Cargo.toml
22
23things = {
24 'bin': [
25 {
26 'name': f'{name}',
27 'path': f'src/bin/{name}.rs',
28 'required-features': features,
29 }
30 for name, features in tests.items()
31 ]
32}
33
34SEPARATOR_START = '# BEGIN TESTS\n'
35SEPARATOR_END = '# END TESTS\n'
36HELP = '# Generated by gen_test.py. DO NOT EDIT.\n'
37with open('Cargo.toml', 'r') as f:
38 data = f.read()
39before, data = data.split(SEPARATOR_START, maxsplit=1)
40_, after = data.split(SEPARATOR_END, maxsplit=1)
41data = before + SEPARATOR_START + HELP + \
42 toml.dumps(things) + SEPARATOR_END + after
43with open('Cargo.toml', 'w') as f:
44 f.write(data)
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
new file mode 100644
index 000000000..8bdd3c24f
--- /dev/null
+++ b/tests/stm32/src/bin/can.rs
@@ -0,0 +1,81 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5// required-features: can
6
7#[path = "../common.rs"]
8mod common;
9use common::*;
10use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::can::bxcan::filter::Mask32;
13use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
14use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
15use embassy_stm32::gpio::{Input, Pull};
16use embassy_stm32::peripherals::CAN1;
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 CAN1_RX0 => Rx0InterruptHandler<CAN1>;
21 CAN1_RX1 => Rx1InterruptHandler<CAN1>;
22 CAN1_SCE => SceInterruptHandler<CAN1>;
23 CAN1_TX => TxInterruptHandler<CAN1>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut p = embassy_stm32::init(config());
29 info!("Hello World!");
30
31 // HW is connected as follows:
32 // PB13 -> PD0
33 // PB12 -> PD1
34
35 // The next two lines are a workaround for testing without transceiver.
36 // To synchronise to the bus the RX input needs to see a high level.
37 // Use `mem::forget()` to release the borrow on the pin but keep the
38 // pull-up resistor enabled.
39 let rx_pin = Input::new(&mut p.PD0, Pull::Up);
40 core::mem::forget(rx_pin);
41
42 let mut can = Can::new(p.CAN1, p.PD0, p.PD1, Irqs);
43
44 info!("Configuring can...");
45
46 can.as_mut()
47 .modify_filters()
48 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
49
50 can.set_bitrate(1_000_000);
51 can.as_mut()
52 .modify_config()
53 .set_loopback(true) // Receive own frames
54 .set_silent(true)
55 // .set_bit_timing(0x001c0003)
56 .enable();
57
58 info!("Can configured");
59
60 let mut i: u8 = 0;
61 loop {
62 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
63
64 info!("Transmitting frame...");
65 can.write(&tx_frame).await;
66
67 info!("Receiving frame...");
68 let (time, rx_frame) = can.read().await.unwrap();
69
70 info!("loopback time {}", time);
71 info!("loopback frame {=u8}", rx_frame.data().unwrap()[0]);
72
73 i += 1;
74 if i > 10 {
75 break;
76 }
77 }
78
79 info!("Test OK");
80 cortex_m::asm::bkpt();
81}
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index 18fd85d44..aad174431 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -1,13 +1,13 @@
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"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert; 8use defmt::assert;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Speed}; 10use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Speed};
10use example_common::*;
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
@@ -30,20 +30,56 @@ async fn main(_spawner: Spawner) {
30 let (mut a, mut b) = (p.PB6, p.PB7); 30 let (mut a, mut b) = (p.PB6, p.PB7);
31 #[cfg(feature = "stm32u585ai")] 31 #[cfg(feature = "stm32u585ai")]
32 let (mut a, mut b) = (p.PD9, p.PD8); 32 let (mut a, mut b) = (p.PD9, p.PD8);
33 #[cfg(feature = "stm32h563zi")]
34 let (mut a, mut b) = (p.PB6, p.PB7);
35 #[cfg(feature = "stm32c031c6")]
36 let (mut a, mut b) = (p.PB6, p.PB7);
33 37
34 // Test initial output 38 // Test initial output
35 { 39 {
36 let b = Input::new(&mut b, Pull::None); 40 let b = Input::new(&mut b, Pull::None);
37 41
38 { 42 {
39 let _a = Output::new(&mut a, Level::Low, Speed::Low); 43 let a = Output::new(&mut a, Level::Low, Speed::Low);
40 delay(); 44 delay();
41 assert!(b.is_low()); 45 assert!(b.is_low());
46 assert!(!b.is_high());
47 assert!(a.is_set_low());
48 assert!(!a.is_set_high());
42 } 49 }
43 { 50 {
44 let _a = Output::new(&mut a, Level::High, Speed::Low); 51 let mut a = Output::new(&mut a, Level::High, Speed::Low);
52 delay();
53 assert!(!b.is_low());
54 assert!(b.is_high());
55 assert!(!a.is_set_low());
56 assert!(a.is_set_high());
57
58 // Test is_set_low / is_set_high
59 a.set_low();
60 delay();
61 assert!(b.is_low());
62 assert!(a.is_set_low());
63 assert!(!a.is_set_high());
64
65 a.set_high();
66 delay();
67 assert!(b.is_high());
68 assert!(!a.is_set_low());
69 assert!(a.is_set_high());
70
71 // Test toggle
72 a.toggle();
73 delay();
74 assert!(b.is_low());
75 assert!(a.is_set_low());
76 assert!(!a.is_set_high());
77
78 a.toggle();
45 delay(); 79 delay();
46 assert!(b.is_high()); 80 assert!(b.is_high());
81 assert!(!a.is_set_low());
82 assert!(a.is_set_high());
47 } 83 }
48 } 84 }
49 85
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
new file mode 100644
index 000000000..194b153d5
--- /dev/null
+++ b/tests/stm32/src/bin/rtc.rs
@@ -0,0 +1,50 @@
1// required-features: chrono
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use chrono::{NaiveDate, NaiveDateTime};
10use common::*;
11use defmt::assert;
12use embassy_executor::Spawner;
13use embassy_stm32::pac;
14use embassy_stm32::rtc::{Rtc, RtcConfig};
15use embassy_time::{Duration, Timer};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(config());
20 info!("Hello World!");
21
22 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
23 .unwrap()
24 .and_hms_opt(10, 30, 15)
25 .unwrap();
26
27 info!("Starting LSI");
28
29 pac::RCC.csr().modify(|w| w.set_lsion(true));
30 while !pac::RCC.csr().read().lsirdy() {}
31
32 info!("Started LSI");
33
34 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
35
36 rtc.set_datetime(now.into()).expect("datetime not set");
37
38 info!("Waiting 5 seconds");
39 Timer::after(Duration::from_millis(5000)).await;
40
41 let then: NaiveDateTime = rtc.now().unwrap().into();
42 let seconds = (then - now).num_seconds();
43
44 defmt::info!("measured = {}", seconds);
45
46 assert!(seconds > 3 && seconds < 7);
47
48 info!("Test OK");
49 cortex_m::asm::bkpt();
50}
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs
new file mode 100644
index 000000000..515025386
--- /dev/null
+++ b/tests/stm32/src/bin/sdmmc.rs
@@ -0,0 +1,145 @@
1// required-features: sdmmc
2#![no_std]
3#![no_main]
4#![feature(type_alias_impl_trait)]
5#[path = "../common.rs"]
6mod common;
7
8use defmt::{assert_eq, *};
9use embassy_executor::Spawner;
10use embassy_stm32::sdmmc::{DataBlock, Sdmmc};
11use embassy_stm32::time::mhz;
12use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 SDIO => sdmmc::InterruptHandler<peripherals::SDIO>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 info!("Hello World!");
22
23 let mut config = Config::default();
24 config.rcc.sys_ck = Some(mhz(48));
25 config.rcc.pll48 = true;
26 let p = embassy_stm32::init(config);
27
28 #[cfg(feature = "stm32f429zi")]
29 let (mut sdmmc, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) =
30 (p.SDIO, p.DMA2_CH3, p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11);
31
32 // Arbitrary block index
33 let block_idx = 16;
34
35 let mut pattern1 = DataBlock([0u8; 512]);
36 let mut pattern2 = DataBlock([0u8; 512]);
37 for i in 0..512 {
38 pattern1[i] = i as u8;
39 pattern2[i] = !i as u8;
40 }
41
42 let mut block = DataBlock([0u8; 512]);
43
44 // ======== Try 4bit. ==============
45 info!("initializing in 4-bit mode...");
46 let mut s = Sdmmc::new_4bit(
47 &mut sdmmc,
48 Irqs,
49 &mut dma,
50 &mut clk,
51 &mut cmd,
52 &mut d0,
53 &mut d1,
54 &mut d2,
55 &mut d3,
56 Default::default(),
57 );
58
59 let mut err = None;
60 loop {
61 match s.init_card(mhz(24)).await {
62 Ok(_) => break,
63 Err(e) => {
64 if err != Some(e) {
65 info!("waiting for card: {:?}", e);
66 err = Some(e);
67 }
68 }
69 }
70 }
71
72 let card = unwrap!(s.card());
73
74 info!("Card: {:#?}", Debug2Format(card));
75 info!("Clock: {}", s.clock());
76
77 info!("writing pattern1...");
78 s.write_block(block_idx, &pattern1).await.unwrap();
79
80 info!("reading...");
81 s.read_block(block_idx, &mut block).await.unwrap();
82 assert_eq!(block, pattern1);
83
84 info!("writing pattern2...");
85 s.write_block(block_idx, &pattern2).await.unwrap();
86
87 info!("reading...");
88 s.read_block(block_idx, &mut block).await.unwrap();
89 assert_eq!(block, pattern2);
90
91 drop(s);
92
93 // ======== Try 1bit. ==============
94 info!("initializing in 1-bit mode...");
95 let mut s = Sdmmc::new_1bit(
96 &mut sdmmc,
97 Irqs,
98 &mut dma,
99 &mut clk,
100 &mut cmd,
101 &mut d0,
102 Default::default(),
103 );
104
105 let mut err = None;
106 loop {
107 match s.init_card(mhz(24)).await {
108 Ok(_) => break,
109 Err(e) => {
110 if err != Some(e) {
111 info!("waiting for card: {:?}", e);
112 err = Some(e);
113 }
114 }
115 }
116 }
117
118 let card = unwrap!(s.card());
119
120 info!("Card: {:#?}", Debug2Format(card));
121 info!("Clock: {}", s.clock());
122
123 info!("reading pattern2 written in 4bit mode...");
124 s.read_block(block_idx, &mut block).await.unwrap();
125 assert_eq!(block, pattern2);
126
127 info!("writing pattern1...");
128 s.write_block(block_idx, &pattern1).await.unwrap();
129
130 info!("reading...");
131 s.read_block(block_idx, &mut block).await.unwrap();
132 assert_eq!(block, pattern1);
133
134 info!("writing pattern2...");
135 s.write_block(block_idx, &pattern2).await.unwrap();
136
137 info!("reading...");
138 s.read_block(block_idx, &mut block).await.unwrap();
139 assert_eq!(block, pattern2);
140
141 drop(s);
142
143 info!("Test OK");
144 cortex_m::asm::bkpt();
145}
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index 1c5dc87c0..819ecae3c 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -1,15 +1,15 @@
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"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
10use embassy_stm32::spi::{self, Spi}; 11use embassy_stm32::spi::{self, Spi};
11use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
12use example_common::*;
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
@@ -17,22 +17,26 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 17 info!("Hello World!");
18 18
19 #[cfg(feature = "stm32f103c8")] 19 #[cfg(feature = "stm32f103c8")]
20 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 20 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
21 #[cfg(feature = "stm32f429zi")] 21 #[cfg(feature = "stm32f429zi")]
22 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 22 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
23 #[cfg(feature = "stm32h755zi")] 23 #[cfg(feature = "stm32h755zi")]
24 let (sck, mosi, miso) = (p.PA5, p.PB5, p.PA6); 24 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PB5, p.PA6);
25 #[cfg(feature = "stm32g491re")] 25 #[cfg(feature = "stm32g491re")]
26 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 26 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
27 #[cfg(feature = "stm32g071rb")] 27 #[cfg(feature = "stm32g071rb")]
28 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 28 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
29 #[cfg(feature = "stm32wb55rg")] 29 #[cfg(feature = "stm32wb55rg")]
30 let (sck, mosi, miso) = (p.PA5, p.PA7, p.PA6); 30 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
31 #[cfg(feature = "stm32u585ai")] 31 #[cfg(feature = "stm32u585ai")]
32 let (sck, mosi, miso) = (p.PE13, p.PE15, p.PE14); 32 let (spi, sck, mosi, miso) = (p.SPI1, p.PE13, p.PE15, p.PE14);
33 #[cfg(feature = "stm32h563zi")]
34 let (spi, sck, mosi, miso) = (p.SPI4, p.PE12, p.PE14, p.PE13);
35 #[cfg(feature = "stm32c031c6")]
36 let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
33 37
34 let mut spi = Spi::new( 38 let mut spi = Spi::new(
35 p.SPI1, 39 spi,
36 sck, // Arduino D13 40 sck, // Arduino D13
37 mosi, // Arduino D11 41 mosi, // Arduino D11
38 miso, // Arduino D12 42 miso, // Arduino D12
@@ -46,7 +50,7 @@ async fn main(_spawner: Spawner) {
46 50
47 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. 51 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
48 // so we should get the data we sent back. 52 // so we should get the data we sent back.
49 let mut buf = data; 53 let mut buf = [0; 9];
50 spi.blocking_transfer(&mut buf, &data).unwrap(); 54 spi.blocking_transfer(&mut buf, &data).unwrap();
51 assert_eq!(buf, data); 55 assert_eq!(buf, data);
52 56
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index cb2152e0b..78aad24e1 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -1,14 +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"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::spi::{self, Spi};
10use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
11use example_common::*;
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
@@ -16,22 +16,26 @@ async fn main(_spawner: Spawner) {
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 #[cfg(feature = "stm32f103c8")] 18 #[cfg(feature = "stm32f103c8")]
19 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2); 19 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2);
20 #[cfg(feature = "stm32f429zi")] 20 #[cfg(feature = "stm32f429zi")]
21 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2); 21 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2);
22 #[cfg(feature = "stm32h755zi")] 22 #[cfg(feature = "stm32h755zi")]
23 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); 23 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1);
24 #[cfg(feature = "stm32g491re")] 24 #[cfg(feature = "stm32g491re")]
25 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); 25 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
26 #[cfg(feature = "stm32g071rb")] 26 #[cfg(feature = "stm32g071rb")]
27 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); 27 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
28 #[cfg(feature = "stm32wb55rg")] 28 #[cfg(feature = "stm32wb55rg")]
29 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); 29 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
30 #[cfg(feature = "stm32u585ai")] 30 #[cfg(feature = "stm32u585ai")]
31 let (sck, mosi, miso, tx_dma, rx_dma) = (p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1); 31 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1);
32 #[cfg(feature = "stm32h563zi")]
33 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI4, p.PE12, p.PE14, p.PE13, p.GPDMA1_CH0, p.GPDMA1_CH1);
34 #[cfg(feature = "stm32c031c6")]
35 let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2);
32 36
33 let mut spi = Spi::new( 37 let mut spi = Spi::new(
34 p.SPI1, 38 spi,
35 sck, // Arduino D13 39 sck, // Arduino D13
36 mosi, // Arduino D11 40 mosi, // Arduino D11
37 miso, // Arduino D12 41 miso, // Arduino D12
diff --git a/tests/stm32/src/bin/timer.rs b/tests/stm32/src/bin/timer.rs
index e00e43bf1..f8b453cda 100644
--- a/tests/stm32/src/bin/timer.rs
+++ b/tests/stm32/src/bin/timer.rs
@@ -1,13 +1,13 @@
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"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert; 8use defmt::assert;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_time::{Duration, Instant, Timer}; 10use embassy_time::{Duration, Instant, Timer};
10use example_common::*;
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index 7673bfe6d..394005b82 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -1,14 +1,42 @@
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"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Error, Uart};
11use example_common::*; 12use embassy_stm32::{bind_interrupts, peripherals, usart};
13use embassy_time::{Duration, Instant};
14
15#[cfg(any(
16 feature = "stm32f103c8",
17 feature = "stm32g491re",
18 feature = "stm32g071rb",
19 feature = "stm32h755zi",
20 feature = "stm32c031c6",
21))]
22bind_interrupts!(struct Irqs {
23 USART1 => usart::InterruptHandler<peripherals::USART1>;
24});
25
26#[cfg(feature = "stm32u585ai")]
27bind_interrupts!(struct Irqs {
28 USART3 => usart::InterruptHandler<peripherals::USART3>;
29});
30
31#[cfg(feature = "stm32f429zi")]
32bind_interrupts!(struct Irqs {
33 USART6 => usart::InterruptHandler<peripherals::USART6>;
34});
35
36#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))]
37bind_interrupts!(struct Irqs {
38 LPUART1 => usart::InterruptHandler<peripherals::LPUART1>;
39});
12 40
13#[embassy_executor::main] 41#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 42async fn main(_spawner: Spawner) {
@@ -18,32 +46,96 @@ async fn main(_spawner: Spawner) {
18 // Arduino pins D0 and D1 46 // Arduino pins D0 and D1
19 // They're connected together with a 1K resistor. 47 // They're connected together with a 1K resistor.
20 #[cfg(feature = "stm32f103c8")] 48 #[cfg(feature = "stm32f103c8")]
21 let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); 49 let (mut tx, mut rx, mut usart) = (p.PA9, p.PA10, p.USART1);
22 #[cfg(feature = "stm32g491re")] 50 #[cfg(feature = "stm32g491re")]
23 let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); 51 let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1);
24 #[cfg(feature = "stm32g071rb")] 52 #[cfg(feature = "stm32g071rb")]
25 let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); 53 let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1);
26 #[cfg(feature = "stm32f429zi")] 54 #[cfg(feature = "stm32f429zi")]
27 let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6); 55 let (mut tx, mut rx, mut usart) = (p.PG14, p.PG9, p.USART6);
28 #[cfg(feature = "stm32wb55rg")] 56 #[cfg(feature = "stm32wb55rg")]
29 let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1); 57 let (mut tx, mut rx, mut usart) = (p.PA2, p.PA3, p.LPUART1);
30 #[cfg(feature = "stm32h755zi")] 58 #[cfg(feature = "stm32h755zi")]
31 let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); 59 let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1);
32 #[cfg(feature = "stm32u585ai")] 60 #[cfg(feature = "stm32u585ai")]
33 let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3); 61 let (mut tx, mut rx, mut usart) = (p.PD8, p.PD9, p.USART3);
62 #[cfg(feature = "stm32h563zi")]
63 let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.LPUART1);
64 #[cfg(feature = "stm32c031c6")]
65 let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1);
66
67 {
68 let config = Config::default();
69 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config);
70
71 // We can't send too many bytes, they have to fit in the FIFO.
72 // This is because we aren't sending+receiving at the same time.
73
74 let data = [0xC0, 0xDE];
75 usart.blocking_write(&data).unwrap();
76
77 let mut buf = [0; 2];
78 usart.blocking_read(&mut buf).unwrap();
79 assert_eq!(buf, data);
80 }
81
82 // Test error handling with with an overflow error
83 {
84 let config = Config::default();
85 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config);
86
87 // Send enough bytes to fill the RX FIFOs off all USART versions.
88 let data = [0xC0, 0xDE, 0x12, 0x23, 0x34];
89 usart.blocking_write(&data).unwrap();
90 usart.blocking_flush().unwrap();
91
92 // The error should be reported first.
93 let mut buf = [0; 1];
94 let err = usart.blocking_read(&mut buf);
95 assert_eq!(err, Err(Error::Overrun));
96
97 // At least the first data byte should still be available on all USART versions.
98 usart.blocking_read(&mut buf).unwrap();
99 assert_eq!(buf[0], data[0]);
100 }
34 101
35 let config = Config::default(); 102 // Test that baudrate divider is calculated correctly.
36 let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); 103 // Do it by comparing the time it takes to send a known number of bytes.
104 for baudrate in [
105 300,
106 9600,
107 115200,
108 250_000,
109 337_934,
110 #[cfg(not(feature = "stm32f103c8"))]
111 1_000_000,
112 #[cfg(not(feature = "stm32f103c8"))]
113 2_000_000,
114 ] {
115 info!("testing baudrate {}", baudrate);
37 116
38 // We can't send too many bytes, they have to fit in the FIFO. 117 let mut config = Config::default();
39 // This is because we aren't sending+receiving at the same time. 118 config.baudrate = baudrate;
119 let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config);
40 120
41 let data = [0xC0, 0xDE]; 121 let n = (baudrate as usize / 100).max(64);
42 usart.blocking_write(&data).unwrap();
43 122
44 let mut buf = [0; 2]; 123 let start = Instant::now();
45 usart.blocking_read(&mut buf).unwrap(); 124 for _ in 0..n {
46 assert_eq!(buf, data); 125 usart.blocking_write(&[0x00]).unwrap();
126 }
127 let dur = Instant::now() - start;
128 let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64));
129 let fuzz = want_dur / 5;
130 if dur < want_dur - fuzz || dur > want_dur + fuzz {
131 defmt::panic!(
132 "bad duration for baudrate {}: got {:?} want {:?}",
133 baudrate,
134 dur,
135 want_dur
136 );
137 }
138 }
47 139
48 info!("Test OK"); 140 info!("Test OK");
49 cortex_m::asm::bkpt(); 141 cortex_m::asm::bkpt();
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index e0389446f..c34d9574b 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -1,13 +1,41 @@
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"]
5mod common;
4 6
5#[path = "../example_common.rs"] 7use common::*;
6mod example_common;
7use defmt::assert_eq; 8use defmt::assert_eq;
8use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_futures::join::join;
9use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
10use example_common::*; 12use embassy_stm32::{bind_interrupts, peripherals, usart};
13
14#[cfg(any(
15 feature = "stm32f103c8",
16 feature = "stm32g491re",
17 feature = "stm32g071rb",
18 feature = "stm32h755zi",
19 feature = "stm32c031c6",
20))]
21bind_interrupts!(struct Irqs {
22 USART1 => usart::InterruptHandler<peripherals::USART1>;
23});
24
25#[cfg(feature = "stm32u585ai")]
26bind_interrupts!(struct Irqs {
27 USART3 => usart::InterruptHandler<peripherals::USART3>;
28});
29
30#[cfg(feature = "stm32f429zi")]
31bind_interrupts!(struct Irqs {
32 USART6 => usart::InterruptHandler<peripherals::USART6>;
33});
34
35#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))]
36bind_interrupts!(struct Irqs {
37 LPUART1 => usart::InterruptHandler<peripherals::LPUART1>;
38});
11 39
12#[embassy_executor::main] 40#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 41async fn main(_spawner: Spawner) {
@@ -17,33 +45,51 @@ async fn main(_spawner: Spawner) {
17 // Arduino pins D0 and D1 45 // Arduino pins D0 and D1
18 // They're connected together with a 1K resistor. 46 // They're connected together with a 1K resistor.
19 #[cfg(feature = "stm32f103c8")] 47 #[cfg(feature = "stm32f103c8")]
20 let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); 48 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, Irqs, p.DMA1_CH4, p.DMA1_CH5);
21 #[cfg(feature = "stm32g491re")] 49 #[cfg(feature = "stm32g491re")]
22 let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); 50 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2);
23 #[cfg(feature = "stm32g071rb")] 51 #[cfg(feature = "stm32g071rb")]
24 let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); 52 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2);
25 #[cfg(feature = "stm32f429zi")] 53 #[cfg(feature = "stm32f429zi")]
26 let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); 54 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, Irqs, p.DMA2_CH6, p.DMA2_CH1);
27 #[cfg(feature = "stm32wb55rg")] 55 #[cfg(feature = "stm32wb55rg")]
28 let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); 56 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, Irqs, p.DMA1_CH1, p.DMA1_CH2);
29 #[cfg(feature = "stm32h755zi")] 57 #[cfg(feature = "stm32h755zi")]
30 let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); 58 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH0, p.DMA1_CH1);
31 #[cfg(feature = "stm32u585ai")] 59 #[cfg(feature = "stm32u585ai")]
32 let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); 60 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1);
61 #[cfg(feature = "stm32h563zi")]
62 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.LPUART1, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1);
63 #[cfg(feature = "stm32c031c6")]
64 let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2);
33 65
34 let config = Config::default(); 66 let config = Config::default();
35 let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); 67 let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config);
68
69 const LEN: usize = 128;
70 let mut tx_buf = [0; LEN];
71 let mut rx_buf = [0; LEN];
72
73 let (mut tx, mut rx) = usart.split();
74
75 for n in 0..42 {
76 for i in 0..LEN {
77 tx_buf[i] = (i ^ n) as u8;
78 }
36 79
37 // We can't send too many bytes, they have to fit in the FIFO. 80 let tx_fut = async {
38 // This is because we aren't sending+receiving at the same time. 81 tx.write(&tx_buf).await.unwrap();
39 // For whatever reason, blocking works with 2 bytes but DMA only with 1?? 82 };
83 let rx_fut = async {
84 rx.read(&mut rx_buf).await.unwrap();
85 };
40 86
41 let data = [0x42]; 87 // note: rx needs to be polled first, to workaround this bug:
42 usart.write(&data).await.unwrap(); 88 // https://github.com/embassy-rs/embassy/issues/1426
89 join(rx_fut, tx_fut).await;
43 90
44 let mut buf = [0; 1]; 91 assert_eq!(tx_buf, rx_buf);
45 usart.read(&mut buf).await.unwrap(); 92 }
46 assert_eq!(buf, data);
47 93
48 info!("Test OK"); 94 info!("Test OK");
49 cortex_m::asm::bkpt(); 95 cortex_m::asm::bkpt();
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
new file mode 100644
index 000000000..c8dd2643b
--- /dev/null
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -0,0 +1,198 @@
1// required-features: not-gpdma
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use common::*;
10use defmt::{assert_eq, panic};
11use embassy_executor::Spawner;
12use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx};
13use embassy_stm32::{bind_interrupts, peripherals, usart};
14use embassy_time::{Duration, Timer};
15use rand_chacha::ChaCha8Rng;
16use rand_core::{RngCore, SeedableRng};
17
18#[cfg(any(
19 feature = "stm32f103c8",
20 feature = "stm32g491re",
21 feature = "stm32g071rb",
22 feature = "stm32h755zi",
23 feature = "stm32c031c6",
24))]
25bind_interrupts!(struct Irqs {
26 USART1 => usart::InterruptHandler<peripherals::USART1>;
27});
28
29#[cfg(feature = "stm32u585ai")]
30bind_interrupts!(struct Irqs {
31 USART3 => usart::InterruptHandler<peripherals::USART3>;
32});
33
34#[cfg(feature = "stm32f429zi")]
35bind_interrupts!(struct Irqs {
36 USART1 => usart::InterruptHandler<peripherals::USART1>;
37 USART6 => usart::InterruptHandler<peripherals::USART6>;
38});
39
40#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))]
41bind_interrupts!(struct Irqs {
42 LPUART1 => usart::InterruptHandler<peripherals::LPUART1>;
43});
44
45#[cfg(feature = "stm32f103c8")]
46mod board {
47 pub type Uart = embassy_stm32::peripherals::USART1;
48 pub type TxDma = embassy_stm32::peripherals::DMA1_CH4;
49 pub type RxDma = embassy_stm32::peripherals::DMA1_CH5;
50}
51#[cfg(feature = "stm32g491re")]
52mod board {
53 pub type Uart = embassy_stm32::peripherals::USART1;
54 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
55 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
56}
57#[cfg(feature = "stm32g071rb")]
58mod board {
59 pub type Uart = embassy_stm32::peripherals::USART1;
60 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
61 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
62}
63#[cfg(feature = "stm32f429zi")]
64mod board {
65 pub type Uart = embassy_stm32::peripherals::USART6;
66 pub type TxDma = embassy_stm32::peripherals::DMA2_CH6;
67 pub type RxDma = embassy_stm32::peripherals::DMA2_CH1;
68}
69#[cfg(feature = "stm32wb55rg")]
70mod board {
71 pub type Uart = embassy_stm32::peripherals::LPUART1;
72 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
73 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
74}
75#[cfg(feature = "stm32h755zi")]
76mod board {
77 pub type Uart = embassy_stm32::peripherals::USART1;
78 pub type TxDma = embassy_stm32::peripherals::DMA1_CH0;
79 pub type RxDma = embassy_stm32::peripherals::DMA1_CH1;
80}
81#[cfg(feature = "stm32u585ai")]
82mod board {
83 pub type Uart = embassy_stm32::peripherals::USART3;
84 pub type TxDma = embassy_stm32::peripherals::GPDMA1_CH0;
85 pub type RxDma = embassy_stm32::peripherals::GPDMA1_CH1;
86}
87#[cfg(feature = "stm32c031c6")]
88mod board {
89 pub type Uart = embassy_stm32::peripherals::USART1;
90 pub type TxDma = embassy_stm32::peripherals::DMA1_CH1;
91 pub type RxDma = embassy_stm32::peripherals::DMA1_CH2;
92}
93
94const DMA_BUF_SIZE: usize = 256;
95
96#[embassy_executor::main]
97async fn main(spawner: Spawner) {
98 let p = embassy_stm32::init(config());
99 info!("Hello World!");
100
101 // Arduino pins D0 and D1
102 // They're connected together with a 1K resistor.
103 #[cfg(feature = "stm32f103c8")]
104 let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5);
105 #[cfg(feature = "stm32g491re")]
106 let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2);
107 #[cfg(feature = "stm32g071rb")]
108 let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2);
109 #[cfg(feature = "stm32f429zi")]
110 let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1);
111 #[cfg(feature = "stm32wb55rg")]
112 let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2);
113 #[cfg(feature = "stm32h755zi")]
114 let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1);
115 #[cfg(feature = "stm32u585ai")]
116 let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1);
117 #[cfg(feature = "stm32c031c6")]
118 let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH1, p.DMA1_CH2);
119
120 // To run this test, use the saturating_serial test utility to saturate the serial port
121
122 let mut config = Config::default();
123 // this is the fastest we can go without tuning RCC
124 // some chips have default pclk=8mhz, and uart can run at max pclk/16
125 config.baudrate = 500_000;
126 config.data_bits = DataBits::DataBits8;
127 config.stop_bits = StopBits::STOP1;
128 config.parity = Parity::ParityNone;
129
130 let usart = Uart::new(usart, rx, tx, Irqs, tx_dma, rx_dma, config);
131 let (tx, rx) = usart.split();
132 static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE];
133 let dma_buf = unsafe { DMA_BUF.as_mut() };
134 let rx = rx.into_ring_buffered(dma_buf);
135
136 info!("Spawning tasks");
137 spawner.spawn(transmit_task(tx)).unwrap();
138 spawner.spawn(receive_task(rx)).unwrap();
139}
140
141#[embassy_executor::task]
142async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
143 // workaround https://github.com/embassy-rs/embassy/issues/1426
144 Timer::after(Duration::from_millis(100) as _).await;
145
146 let mut rng = ChaCha8Rng::seed_from_u64(1337);
147
148 info!("Starting random transmissions into void...");
149
150 let mut i: u8 = 0;
151 loop {
152 let mut buf = [0; 256];
153 let len = 1 + (rng.next_u32() as usize % buf.len());
154 for b in &mut buf[..len] {
155 *b = i;
156 i = i.wrapping_add(1);
157 }
158
159 tx.write(&buf[..len]).await.unwrap();
160 Timer::after(Duration::from_micros((rng.next_u32() % 1000) as _)).await;
161 }
162}
163
164#[embassy_executor::task]
165async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::RxDma>) {
166 info!("Ready to receive...");
167
168 let mut rng = ChaCha8Rng::seed_from_u64(1337);
169
170 let mut i = 0;
171 let mut expected = 0;
172 loop {
173 let mut buf = [0; 256];
174 let max_len = 1 + (rng.next_u32() as usize % buf.len());
175 let received = match rx.read(&mut buf[..max_len]).await {
176 Ok(r) => r,
177 Err(e) => {
178 panic!("Test fail! read error: {:?}", e);
179 }
180 };
181
182 for byte in &buf[..received] {
183 assert_eq!(*byte, expected);
184 expected = expected.wrapping_add(1);
185 }
186
187 if received < max_len {
188 Timer::after(Duration::from_micros((rng.next_u32() % 1000) as _)).await;
189 }
190
191 i += received;
192
193 if i > 100000 {
194 info!("Test OK!");
195 cortex_m::asm::bkpt();
196 }
197 }
198}
diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs
new file mode 100644
index 000000000..3ad8aca4e
--- /dev/null
+++ b/tests/stm32/src/bin/wpan_ble.rs
@@ -0,0 +1,251 @@
1// required-features: ble
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use core::time::Duration;
10
11use common::*;
12use embassy_executor::Spawner;
13use embassy_stm32::bind_interrupts;
14use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
15use embassy_stm32_wpan::hci::host::uart::UartHci;
16use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
17use embassy_stm32_wpan::hci::types::AdvertisingType;
18use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
19 AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
20};
21use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands;
22use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
23use embassy_stm32_wpan::hci::BdAddr;
24use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
25use embassy_stm32_wpan::sub::mm;
26use embassy_stm32_wpan::TlMbox;
27use {defmt_rtt as _, panic_probe as _};
28
29bind_interrupts!(struct Irqs{
30 IPCC_C1_RX => ReceiveInterruptHandler;
31 IPCC_C1_TX => TransmitInterruptHandler;
32});
33
34const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
35
36#[embassy_executor::task]
37async fn run_mm_queue(memory_manager: mm::MemoryManager) {
38 memory_manager.run_queue().await;
39}
40
41#[embassy_executor::main]
42async fn main(spawner: Spawner) {
43 let p = embassy_stm32::init(config());
44 info!("Hello World!");
45
46 let config = Config::default();
47 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
48
49 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
50
51 let sys_event = mbox.sys_subsystem.read().await;
52 info!("sys event: {}", sys_event.payload());
53
54 let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap();
55 let version_major = fw_info.version_major();
56 let version_minor = fw_info.version_minor();
57 let subversion = fw_info.subversion();
58
59 let sram2a_size = fw_info.sram2a_size();
60 let sram2b_size = fw_info.sram2b_size();
61
62 info!(
63 "version {}.{}.{} - SRAM2a {} - SRAM2b {}",
64 version_major, version_minor, subversion, sram2a_size, sram2b_size
65 );
66
67 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
68
69 info!("resetting BLE...");
70 mbox.ble_subsystem.reset().await;
71 let response = mbox.ble_subsystem.read().await.unwrap();
72 info!("{}", response);
73
74 info!("config public address...");
75 mbox.ble_subsystem
76 .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
77 .await;
78 let response = mbox.ble_subsystem.read().await.unwrap();
79 info!("{}", response);
80
81 info!("config random address...");
82 mbox.ble_subsystem
83 .write_config_data(&ConfigData::random_address(get_random_addr()).build())
84 .await;
85 let response = mbox.ble_subsystem.read().await.unwrap();
86 info!("{}", response);
87
88 info!("config identity root...");
89 mbox.ble_subsystem
90 .write_config_data(&ConfigData::identity_root(&get_irk()).build())
91 .await;
92 let response = mbox.ble_subsystem.read().await.unwrap();
93 info!("{}", response);
94
95 info!("config encryption root...");
96 mbox.ble_subsystem
97 .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
98 .await;
99 let response = mbox.ble_subsystem.read().await.unwrap();
100 info!("{}", response);
101
102 info!("config tx power level...");
103 mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
104 let response = mbox.ble_subsystem.read().await.unwrap();
105 info!("{}", response);
106
107 info!("GATT init...");
108 mbox.ble_subsystem.init_gatt().await;
109 let response = mbox.ble_subsystem.read().await.unwrap();
110 info!("{}", response);
111
112 info!("GAP init...");
113 mbox.ble_subsystem
114 .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
115 .await;
116 let response = mbox.ble_subsystem.read().await.unwrap();
117 info!("{}", response);
118
119 // info!("set scan response...");
120 // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap();
121 // let response = mbox.ble_subsystem.read().await.unwrap();
122 // info!("{}", response);
123
124 info!("set discoverable...");
125 mbox.ble_subsystem
126 .set_discoverable(&DiscoverableParameters {
127 advertising_type: AdvertisingType::NonConnectableUndirected,
128 advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))),
129 address_type: OwnAddressType::Public,
130 filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
131 local_name: None,
132 advertising_data: &[],
133 conn_interval: (None, None),
134 })
135 .await
136 .unwrap();
137
138 let response = mbox.ble_subsystem.read().await;
139 info!("{}", response);
140
141 // remove some advertisement to decrease the packet size
142 info!("delete tx power ad type...");
143 mbox.ble_subsystem
144 .delete_ad_type(AdvertisingDataType::TxPowerLevel)
145 .await;
146 let response = mbox.ble_subsystem.read().await.unwrap();
147 info!("{}", response);
148
149 info!("delete conn interval ad type...");
150 mbox.ble_subsystem
151 .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval)
152 .await;
153 let response = mbox.ble_subsystem.read().await.unwrap();
154 info!("{}", response);
155
156 info!("update advertising data...");
157 mbox.ble_subsystem
158 .update_advertising_data(&eddystone_advertising_data())
159 .await
160 .unwrap();
161 let response = mbox.ble_subsystem.read().await.unwrap();
162 info!("{}", response);
163
164 info!("update advertising data type...");
165 mbox.ble_subsystem
166 .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe])
167 .await
168 .unwrap();
169 let response = mbox.ble_subsystem.read().await.unwrap();
170 info!("{}", response);
171
172 info!("update advertising data flags...");
173 mbox.ble_subsystem
174 .update_advertising_data(&[
175 2,
176 AdvertisingDataType::Flags as u8,
177 (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support
178 ])
179 .await
180 .unwrap();
181 let response = mbox.ble_subsystem.read().await.unwrap();
182 info!("{}", response);
183
184 info!("Test OK");
185 cortex_m::asm::bkpt();
186}
187
188fn get_bd_addr() -> BdAddr {
189 let mut bytes = [0u8; 6];
190
191 let lhci_info = LhciC1DeviceInformationCcrp::new();
192 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
193 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
194 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
195 bytes[3] = lhci_info.device_type_id;
196 bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
197 bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
198
199 BdAddr(bytes)
200}
201
202fn get_random_addr() -> BdAddr {
203 let mut bytes = [0u8; 6];
204
205 let lhci_info = LhciC1DeviceInformationCcrp::new();
206 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
207 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
208 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
209 bytes[3] = 0;
210 bytes[4] = 0x6E;
211 bytes[5] = 0xED;
212
213 BdAddr(bytes)
214}
215
216const BLE_CFG_IRK: [u8; 16] = [
217 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
218];
219const BLE_CFG_ERK: [u8; 16] = [
220 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
221];
222
223fn get_irk() -> EncryptionKey {
224 EncryptionKey(BLE_CFG_IRK)
225}
226
227fn get_erk() -> EncryptionKey {
228 EncryptionKey(BLE_CFG_ERK)
229}
230
231fn eddystone_advertising_data() -> [u8; 24] {
232 const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com";
233
234 let mut service_data = [0u8; 24];
235 let url_len = EDDYSTONE_URL.len();
236
237 service_data[0] = 6 + url_len as u8;
238 service_data[1] = AdvertisingDataType::ServiceData as u8;
239
240 // 16-bit eddystone uuid
241 service_data[2] = 0xaa;
242 service_data[3] = 0xFE;
243
244 service_data[4] = 0x10; // URL frame type
245 service_data[5] = 22_i8 as u8; // calibrated TX power at 0m
246 service_data[6] = 0x03; // eddystone url prefix = https
247
248 service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL);
249
250 service_data
251}
diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs
new file mode 100644
index 000000000..d64a5ef81
--- /dev/null
+++ b/tests/stm32/src/bin/wpan_mac.rs
@@ -0,0 +1,120 @@
1// required-features: mac
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6#[path = "../common.rs"]
7mod common;
8
9use common::*;
10use embassy_executor::Spawner;
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
13use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest};
14use embassy_stm32_wpan::mac::event::MacEvent;
15use embassy_stm32_wpan::mac::typedefs::{
16 AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
17};
18use embassy_stm32_wpan::sub::mm;
19use embassy_stm32_wpan::TlMbox;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs{
23 IPCC_C1_RX => ReceiveInterruptHandler;
24 IPCC_C1_TX => TransmitInterruptHandler;
25});
26
27#[embassy_executor::task]
28async fn run_mm_queue(memory_manager: mm::MemoryManager) {
29 memory_manager.run_queue().await;
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) {
34 let p = embassy_stm32::init(config());
35 info!("Hello World!");
36
37 let config = Config::default();
38 let mbox = TlMbox::init(p.IPCC, Irqs, config);
39
40 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
41
42 let sys_event = mbox.sys_subsystem.read().await;
43 info!("sys event: {}", sys_event.payload());
44
45 core::mem::drop(sys_event);
46
47 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
48 info!("initialized mac: {}", result);
49
50 info!("resetting");
51 mbox.mac_subsystem
52 .send_command(&ResetRequest {
53 set_default_pib: true,
54 ..Default::default()
55 })
56 .await
57 .unwrap();
58 {
59 let evt = mbox.mac_subsystem.read().await;
60 info!("{:#x}", evt.mac_event());
61 }
62
63 info!("setting extended address");
64 let extended_address: u64 = 0xACDE480000000002;
65 mbox.mac_subsystem
66 .send_command(&SetRequest {
67 pib_attribute_ptr: &extended_address as *const _ as *const u8,
68 pib_attribute: PibId::ExtendedAddress,
69 })
70 .await
71 .unwrap();
72 {
73 let evt = mbox.mac_subsystem.read().await;
74 info!("{:#x}", evt.mac_event());
75 }
76
77 info!("getting extended address");
78 mbox.mac_subsystem
79 .send_command(&GetRequest {
80 pib_attribute: PibId::ExtendedAddress,
81 ..Default::default()
82 })
83 .await
84 .unwrap();
85 {
86 let evt = mbox.mac_subsystem.read().await;
87 info!("{:#x}", evt.mac_event());
88
89 if let Ok(MacEvent::MlmeGetCnf(evt)) = evt.mac_event() {
90 if evt.pib_attribute_value_len == 8 {
91 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
92
93 info!("value {:#x}", value)
94 }
95 }
96 }
97
98 info!("assocation request");
99 let a = AssociateRequest {
100 channel_number: MacChannel::Channel16,
101 channel_page: 0,
102 coord_addr_mode: AddressMode::Short,
103 coord_address: MacAddress { short: [34, 17] },
104 capability_information: Capabilities::ALLOCATE_ADDRESS,
105 coord_pan_id: PanId([0x1A, 0xAA]),
106 security_level: SecurityLevel::Unsecure,
107 key_id_mode: KeyIdMode::Implicite,
108 key_source: [0; 8],
109 key_index: 152,
110 };
111 info!("{}", a);
112 mbox.mac_subsystem.send_command(&a).await.unwrap();
113 {
114 let evt = mbox.mac_subsystem.read().await;
115 info!("{:#x}", evt.mac_event());
116 }
117
118 info!("Test OK");
119 cortex_m::asm::bkpt();
120}
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
new file mode 100644
index 000000000..3d2a9b8ef
--- /dev/null
+++ b/tests/stm32/src/common.rs
@@ -0,0 +1,44 @@
1#![macro_use]
2
3pub use defmt::*;
4#[allow(unused)]
5use embassy_stm32::time::Hertz;
6use embassy_stm32::Config;
7use {defmt_rtt as _, panic_probe as _};
8
9#[cfg(feature = "stm32f103c8")]
10teleprobe_meta::target!(b"bluepill-stm32f103c8");
11#[cfg(feature = "stm32g491re")]
12teleprobe_meta::target!(b"nucleo-stm32g491re");
13#[cfg(feature = "stm32g071rb")]
14teleprobe_meta::target!(b"nucleo-stm32g071rb");
15#[cfg(feature = "stm32f429zi")]
16teleprobe_meta::target!(b"nucleo-stm32f429zi");
17#[cfg(feature = "stm32wb55rg")]
18teleprobe_meta::target!(b"nucleo-stm32wb55rg");
19#[cfg(feature = "stm32h755zi")]
20teleprobe_meta::target!(b"nucleo-stm32h755zi");
21#[cfg(feature = "stm32u585ai")]
22teleprobe_meta::target!(b"iot-stm32u585ai");
23#[cfg(feature = "stm32h563zi")]
24teleprobe_meta::target!(b"nucleo-stm32h563zi");
25#[cfg(feature = "stm32c031c6")]
26teleprobe_meta::target!(b"nucleo-stm32c031c6");
27
28pub fn config() -> Config {
29 #[allow(unused_mut)]
30 let mut config = Config::default();
31
32 #[cfg(feature = "stm32h755zi")]
33 {
34 config.rcc.sys_ck = Some(Hertz(400_000_000));
35 config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
36 }
37
38 #[cfg(feature = "stm32u585ai")]
39 {
40 config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz);
41 }
42
43 config
44}
diff --git a/tests/stm32/src/example_common.rs b/tests/stm32/src/example_common.rs
deleted file mode 100644
index c47ed75c4..000000000
--- a/tests/stm32/src/example_common.rs
+++ /dev/null
@@ -1,31 +0,0 @@
1#![macro_use]
2
3use core::sync::atomic::{AtomicUsize, Ordering};
4
5pub use defmt::*;
6#[allow(unused)]
7use embassy_stm32::time::Hertz;
8use embassy_stm32::Config;
9use {defmt_rtt as _, panic_probe as _};
10
11defmt::timestamp! {"{=u64}", {
12 static COUNT: AtomicUsize = AtomicUsize::new(0);
13 // NOTE(no-CAS) `timestamps` runs with interrupts disabled
14 let n = COUNT.load(Ordering::Relaxed);
15 COUNT.store(n + 1, Ordering::Relaxed);
16 n as u64
17 }
18}
19
20pub fn config() -> Config {
21 #[allow(unused_mut)]
22 let mut config = Config::default();
23
24 #[cfg(feature = "stm32h755zi")]
25 {
26 config.rcc.sys_ck = Some(Hertz(400_000_000));
27 config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
28 }
29
30 config
31}
diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml
new file mode 100644
index 000000000..7d66fd586
--- /dev/null
+++ b/tests/utils/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2name = "test-utils"
3version = "0.1.0"
4edition = "2021"
5
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
8[dependencies]
9rand = "0.8"
10serial = "0.4"
diff --git a/tests/utils/src/bin/saturate_serial.rs b/tests/utils/src/bin/saturate_serial.rs
new file mode 100644
index 000000000..18ca12fb7
--- /dev/null
+++ b/tests/utils/src/bin/saturate_serial.rs
@@ -0,0 +1,53 @@
1use std::path::Path;
2use std::time::Duration;
3use std::{env, io, process, thread};
4
5use rand::random;
6use serial::SerialPort;
7
8pub fn main() {
9 if let Some(port_name) = env::args().nth(1) {
10 let idles = env::args().position(|x| x == "--idles").is_some();
11
12 println!("Saturating port {:?} with 115200 8N1", port_name);
13 println!("Idles: {}", idles);
14 println!("Process ID: {}", process::id());
15 let mut port = serial::open(&port_name).unwrap();
16 if saturate(&mut port, idles).is_err() {
17 eprintln!("Unable to saturate port");
18 }
19 } else {
20 let path = env::args().next().unwrap();
21 let basepath = Path::new(&path).with_extension("");
22 let basename = basepath.file_name().unwrap();
23 eprintln!("USAGE: {} <port-name>", basename.to_string_lossy());
24 }
25}
26
27fn saturate<T: SerialPort>(port: &mut T, idles: bool) -> io::Result<()> {
28 port.reconfigure(&|settings| {
29 settings.set_baud_rate(serial::Baud115200)?;
30 settings.set_char_size(serial::Bits8);
31 settings.set_parity(serial::ParityNone);
32 settings.set_stop_bits(serial::Stop1);
33 Ok(())
34 })?;
35
36 let mut written = 0;
37 loop {
38 let len = random::<usize>() % 0x1000;
39 let buf: Vec<u8> = (written..written + len).map(|x| x as u8).collect();
40
41 port.write_all(&buf)?;
42
43 if idles {
44 let micros = (random::<usize>() % 1000) as u64;
45 println!("Sleeping {}us", micros);
46 port.flush().unwrap();
47 thread::sleep(Duration::from_micros(micros));
48 }
49
50 written += len;
51 println!("Written: {}", written);
52 }
53}