aboutsummaryrefslogtreecommitdiff
path: root/tests/stm32/src
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/stm32/src
parentd896f80405aa8963877049ed999e4aba25d6e2bb (diff)
parent6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff)
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'tests/stm32/src')
-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
14 files changed, 1141 insertions, 101 deletions
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}