aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-04-06 18:53:51 +0200
committerDario Nieuwenhuis <[email protected]>2023-04-06 18:59:37 +0200
commit611d0238290c9f7b3b23d05ec07adf5b48ea3479 (patch)
tree4307153f4ef858b6ed7fea703e9fbfe4eddb673a /examples
parent9f28d8097704f51fb7d7dcc8d459ce86aaf07eff (diff)
stm32: add H5 support.
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32h5/.cargo/config.toml8
-rw-r--r--examples/stm32h5/Cargo.toml71
-rw-r--r--examples/stm32h5/build.rs5
-rw-r--r--examples/stm32h5/memory.x5
-rw-r--r--examples/stm32h5/src/bin/blinky.rs27
-rw-r--r--examples/stm32h5/src/bin/button_exti.rs27
-rw-r--r--examples/stm32h5/src/bin/eth.rs133
-rw-r--r--examples/stm32h5/src/bin/i2c.rs44
-rw-r--r--examples/stm32h5/src/bin/rng.rs20
-rw-r--r--examples/stm32h5/src/bin/usart.rs43
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs46
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs58
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs128
13 files changed, 615 insertions, 0 deletions
diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml
new file mode 100644
index 000000000..c8b864b6c
--- /dev/null
+++ b/examples/stm32h5/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs-cli run --chip STM32H563ZITx'
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
new file mode 100644
index 000000000..70702863f
--- /dev/null
+++ b/examples/stm32h5/Cargo.toml
@@ -0,0 +1,71 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h7-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
13embedded-io = { version = "0.4.0", features = ["async"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15
16defmt = "0.3"
17defmt-rtt = "0.4"
18
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
23embedded-hal-async = { version = "=0.2.0-alpha.0" }
24embedded-nal-async = "0.4.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27heapless = { version = "0.7.5", default-features = false }
28rand_core = "0.6.3"
29critical-section = "1.1"
30micromath = "2.0.0"
31stm32-fmc = "0.2.4"
32embedded-storage = "0.3.0"
33static_cell = "1.0"
34
35# cargo build/run
36[profile.dev]
37codegen-units = 1
38debug = 2
39debug-assertions = true # <-
40incremental = false
41opt-level = 3 # <-
42overflow-checks = true # <-
43
44# cargo test
45[profile.test]
46codegen-units = 1
47debug = 2
48debug-assertions = true # <-
49incremental = false
50opt-level = 3 # <-
51overflow-checks = true # <-
52
53# cargo build/run --release
54[profile.release]
55codegen-units = 1
56debug = 2
57debug-assertions = false # <-
58incremental = false
59lto = 'fat'
60opt-level = 3 # <-
61overflow-checks = false # <-
62
63# cargo test --release
64[profile.bench]
65codegen-units = 1
66debug = 2
67debug-assertions = false # <-
68incremental = false
69lto = 'fat'
70opt-level = 3 # <-
71overflow-checks = false # <-
diff --git a/examples/stm32h5/build.rs b/examples/stm32h5/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32h5/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32h5/memory.x b/examples/stm32h5/memory.x
new file mode 100644
index 000000000..456061509
--- /dev/null
+++ b/examples/stm32h5/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 0x200000
4 RAM : ORIGIN = 0x20000000, LENGTH = 0x50000
5}
diff --git a/examples/stm32h5/src/bin/blinky.rs b/examples/stm32h5/src/bin/blinky.rs
new file mode 100644
index 000000000..f9bf90d2e
--- /dev/null
+++ b/examples/stm32h5/src/bin/blinky.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut led = Output::new(p.PB0, Level::High, Speed::Low);
17
18 loop {
19 info!("high");
20 led.set_high();
21 Timer::after(Duration::from_millis(500)).await;
22
23 info!("low");
24 led.set_low();
25 Timer::after(Duration::from_millis(500)).await;
26 }
27}
diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs
new file mode 100644
index 000000000..dfe587d41
--- /dev/null
+++ b/examples/stm32h5/src/bin/button_exti.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::exti::ExtiInput;
8use embassy_stm32::gpio::{Input, Pull};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let button = Input::new(p.PC13, Pull::Down);
17 let mut button = ExtiInput::new(button, p.EXTI13);
18
19 info!("Press the USER button...");
20
21 loop {
22 button.wait_for_rising_edge().await;
23 info!("Pressed!");
24 button.wait_for_falling_edge().await;
25 info!("Released!");
26 }
27}
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
new file mode 100644
index 000000000..6d650da9e
--- /dev/null
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -0,0 +1,133 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
13use embassy_stm32::rng::Rng;
14use embassy_stm32::time::Hertz;
15use embassy_stm32::{interrupt, Config};
16use embassy_time::{Duration, Timer};
17use embedded_io::asynch::Write;
18use rand_core::RngCore;
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 let (x,) = STATIC_CELL.init(($val,));
27 x
28 }};
29}
30
31type Device = Ethernet<'static, ETH, GenericSMI>;
32
33#[embassy_executor::task]
34async fn net_task(stack: &'static Stack<Device>) -> ! {
35 stack.run().await
36}
37
38#[embassy_executor::main]
39async fn main(spawner: Spawner) -> ! {
40 let mut config = Config::default();
41 config.rcc.hsi = None;
42 config.rcc.hsi48 = true; // needed for rng
43 config.rcc.hse = Some(Hse {
44 freq: Hertz(8_000_000),
45 mode: HseMode::BypassDigital,
46 });
47 config.rcc.pll1 = Some(Pll {
48 source: PllSource::Hse,
49 prediv: 2,
50 mul: 125,
51 divp: Some(2),
52 divq: Some(2),
53 divr: None,
54 });
55 config.rcc.ahb_pre = AHBPrescaler::NotDivided;
56 config.rcc.apb1_pre = APBPrescaler::NotDivided;
57 config.rcc.apb2_pre = APBPrescaler::NotDivided;
58 config.rcc.apb3_pre = APBPrescaler::NotDivided;
59 config.rcc.sys = Sysclk::Pll1P;
60 config.rcc.voltage_scale = VoltageScale::Scale0;
61 let p = embassy_stm32::init(config);
62 info!("Hello World!");
63
64 // Generate random seed.
65 let mut rng = Rng::new(p.RNG);
66 let mut seed = [0; 8];
67 rng.fill_bytes(&mut seed);
68 let seed = u64::from_le_bytes(seed);
69
70 let eth_int = interrupt::take!(ETH);
71 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
72
73 let device = Ethernet::new(
74 singleton!(PacketQueue::<4, 4>::new()),
75 p.ETH,
76 eth_int,
77 p.PA1,
78 p.PA2,
79 p.PC1,
80 p.PA7,
81 p.PC4,
82 p.PC5,
83 p.PG13,
84 p.PB15,
85 p.PG11,
86 GenericSMI,
87 mac_addr,
88 0,
89 );
90
91 let config = embassy_net::Config::Dhcp(Default::default());
92 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
93 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
94 // dns_servers: Vec::new(),
95 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
96 //});
97
98 // Init network stack
99 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
100
101 // Launch network task
102 unwrap!(spawner.spawn(net_task(&stack)));
103
104 info!("Network task initialized");
105
106 // Then we can use it!
107 let mut rx_buffer = [0; 1024];
108 let mut tx_buffer = [0; 1024];
109
110 loop {
111 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
112
113 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
114
115 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
116 info!("connecting...");
117 let r = socket.connect(remote_endpoint).await;
118 if let Err(e) = r {
119 info!("connect error: {:?}", e);
120 Timer::after(Duration::from_secs(3)).await;
121 continue;
122 }
123 info!("connected!");
124 loop {
125 let r = socket.write_all(b"Hello\n").await;
126 if let Err(e) = r {
127 info!("write error: {:?}", e);
128 continue;
129 }
130 Timer::after(Duration::from_secs(1)).await;
131 }
132 }
133}
diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs
new file mode 100644
index 000000000..6cbf58bbc
--- /dev/null
+++ b/examples/stm32h5/src/bin/i2c.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
8use embassy_stm32::interrupt;
9use embassy_stm32::time::Hertz;
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 info!("Hello world!");
19 let p = embassy_stm32::init(Default::default());
20
21 let irq = interrupt::take!(I2C2_EV);
22 let mut i2c = I2c::new(
23 p.I2C2,
24 p.PB10,
25 p.PB11,
26 irq,
27 p.GPDMA1_CH4,
28 p.GPDMA1_CH5,
29 Hertz(100_000),
30 Default::default(),
31 );
32
33 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
34 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
35 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
36
37 let mut data = [0u8; 1];
38
39 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
40 Ok(()) => info!("Whoami: {}", data[0]),
41 Err(Error::Timeout) => error!("Operation timed out"),
42 Err(e) => error!("I2c Error: {:?}", e),
43 }
44}
diff --git a/examples/stm32h5/src/bin/rng.rs b/examples/stm32h5/src/bin/rng.rs
new file mode 100644
index 000000000..af9be0b62
--- /dev/null
+++ b/examples/stm32h5/src/bin/rng.rs
@@ -0,0 +1,20 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rng::Rng;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut rng = Rng::new(p.RNG);
16
17 let mut buf = [0u8; 16];
18 unwrap!(rng.async_fill_bytes(&mut buf).await);
19 info!("random bytes: {:02x}", buf);
20}
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
new file mode 100644
index 000000000..405f18ec7
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use cortex_m_rt::entry;
6use defmt::*;
7use embassy_executor::Executor;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::interrupt;
10use embassy_stm32::usart::{Config, Uart};
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::task]
15async fn main_task() {
16 let p = embassy_stm32::init(Default::default());
17
18 let config = Config::default();
19 let irq = interrupt::take!(UART7);
20 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config);
21
22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
23 info!("wrote Hello, starting echo");
24
25 let mut buf = [0u8; 1];
26 loop {
27 unwrap!(usart.blocking_read(&mut buf));
28 unwrap!(usart.blocking_write(&buf));
29 }
30}
31
32static EXECUTOR: StaticCell<Executor> = StaticCell::new();
33
34#[entry]
35fn main() -> ! {
36 info!("Hello World!");
37
38 let executor = EXECUTOR.init(Executor::new());
39
40 executor.run(|spawner| {
41 unwrap!(spawner.spawn(main_task()));
42 })
43}
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
new file mode 100644
index 000000000..43d791aae
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -0,0 +1,46 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::fmt::Write;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma;
11use embassy_stm32::interrupt;
12use embassy_stm32::usart::{Config, Uart};
13use heapless::String;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::task]
18async fn main_task() {
19 let p = embassy_stm32::init(Default::default());
20
21 let config = Config::default();
22 let irq = interrupt::take!(UART7);
23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, NoDma, config);
24
25 for n in 0u32.. {
26 let mut s: String<128> = String::new();
27 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
28
29 usart.write(s.as_bytes()).await.ok();
30
31 info!("wrote DMA");
32 }
33}
34
35static EXECUTOR: StaticCell<Executor> = StaticCell::new();
36
37#[entry]
38fn main() -> ! {
39 info!("Hello World!");
40
41 let executor = EXECUTOR.init(Executor::new());
42
43 executor.run(|spawner| {
44 unwrap!(spawner.spawn(main_task()));
45 })
46}
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
new file mode 100644
index 000000000..16a499582
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -0,0 +1,58 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::interrupt;
9use embassy_stm32::peripherals::{GPDMA1_CH1, UART7};
10use embassy_stm32::usart::{Config, Uart, UartRx};
11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
12use embassy_sync::channel::Channel;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::task]
16async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
17 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
18 info!("wrote Hello, starting echo");
19
20 let mut buf = [0u8; 1];
21 loop {
22 unwrap!(usart.blocking_read(&mut buf));
23 unwrap!(usart.blocking_write(&buf));
24 }
25}
26
27static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
28
29#[embassy_executor::main]
30async fn main(spawner: Spawner) -> ! {
31 let p = embassy_stm32::init(Default::default());
32 info!("Hello World!");
33
34 let config = Config::default();
35 let irq = interrupt::take!(UART7);
36 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.GPDMA1_CH0, p.GPDMA1_CH1, config);
37 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
38
39 let (mut tx, rx) = usart.split();
40
41 unwrap!(spawner.spawn(reader(rx)));
42
43 loop {
44 let buf = CHANNEL.recv().await;
45 info!("writing...");
46 unwrap!(tx.write(&buf).await);
47 }
48}
49
50#[embassy_executor::task]
51async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) {
52 let mut buf = [0; 8];
53 loop {
54 info!("reading...");
55 unwrap!(rx.read(&mut buf).await);
56 CHANNEL.send(buf).await;
57 }
58}
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
new file mode 100644
index 000000000..6af269c1d
--- /dev/null
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -0,0 +1,128 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, pac, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut config = Config::default();
20 config.rcc.hsi = None;
21 config.rcc.hsi48 = true; // needed for usb
22 config.rcc.hse = Some(Hse {
23 freq: Hertz(8_000_000),
24 mode: HseMode::BypassDigital,
25 });
26 config.rcc.pll1 = Some(Pll {
27 source: PllSource::Hse,
28 prediv: 2,
29 mul: 125,
30 divp: Some(2), // 250mhz
31 divq: None,
32 divr: None,
33 });
34 config.rcc.ahb_pre = AHBPrescaler::Div2;
35 config.rcc.apb1_pre = APBPrescaler::Div4;
36 config.rcc.apb2_pre = APBPrescaler::Div2;
37 config.rcc.apb3_pre = APBPrescaler::Div4;
38 config.rcc.sys = Sysclk::Pll1P;
39 config.rcc.voltage_scale = VoltageScale::Scale0;
40 let p = embassy_stm32::init(config);
41
42 info!("Hello World!");
43
44 unsafe {
45 pac::RCC.ccipr4().write(|w| {
46 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
47 });
48 }
49
50 // Create the driver, from the HAL.
51 let irq = interrupt::take!(USB_DRD_FS);
52 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
53
54 // Create embassy-usb Config
55 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
56 config.manufacturer = Some("Embassy");
57 config.product = Some("USB-serial example");
58 config.serial_number = Some("12345678");
59
60 // Required for windows compatiblity.
61 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
62 config.device_class = 0xEF;
63 config.device_sub_class = 0x02;
64 config.device_protocol = 0x01;
65 config.composite_with_iads = true;
66
67 // Create embassy-usb DeviceBuilder using the driver and config.
68 // It needs some buffers for building the descriptors.
69 let mut device_descriptor = [0; 256];
70 let mut config_descriptor = [0; 256];
71 let mut bos_descriptor = [0; 256];
72 let mut control_buf = [0; 64];
73
74 let mut state = State::new();
75
76 let mut builder = Builder::new(
77 driver,
78 config,
79 &mut device_descriptor,
80 &mut config_descriptor,
81 &mut bos_descriptor,
82 &mut control_buf,
83 );
84
85 // Create classes on the builder.
86 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
87
88 // Build the builder.
89 let mut usb = builder.build();
90
91 // Run the USB device.
92 let usb_fut = usb.run();
93
94 // Do stuff with the class!
95 let echo_fut = async {
96 loop {
97 class.wait_connection().await;
98 info!("Connected");
99 let _ = echo(&mut class).await;
100 info!("Disconnected");
101 }
102 };
103
104 // Run everything concurrently.
105 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
106 join(usb_fut, echo_fut).await;
107}
108
109struct Disconnected {}
110
111impl From<EndpointError> for Disconnected {
112 fn from(val: EndpointError) -> Self {
113 match val {
114 EndpointError::BufferOverflow => panic!("Buffer overflow"),
115 EndpointError::Disabled => Disconnected {},
116 }
117 }
118}
119
120async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
121 let mut buf = [0; 64];
122 loop {
123 let n = class.read_packet(&mut buf).await?;
124 let data = &buf[..n];
125 info!("data: {:x}", data);
126 class.write_packet(data).await?;
127 }
128}