aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorGerzain Mata <[email protected]>2025-07-21 03:07:41 -0700
committerGerzain Mata <[email protected]>2025-07-21 03:07:41 -0700
commit726991f2e9e951569e37552b5560fb06891d99e8 (patch)
tree573b2b6958f6cc466d147e3be8666e167535bfe0 /examples
parent2cae242f51cd1553ca9deb1cfd73daed606c5476 (diff)
Working example in usb_hs_serial.rs
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32wba/.cargo/config.toml2
-rw-r--r--examples/stm32wba/Cargo.toml4
-rw-r--r--examples/stm32wba/src/bin/usb_hs_serial.rs112
-rw-r--r--examples/stm32wba/src/bin/usb_serial.rs119
4 files changed, 235 insertions, 2 deletions
diff --git a/examples/stm32wba/.cargo/config.toml b/examples/stm32wba/.cargo/config.toml
index c96a5cb6c..1896068d8 100644
--- a/examples/stm32wba/.cargo/config.toml
+++ b/examples/stm32wba/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip STM32WBA55CGUx" 2runner = "probe-rs run --chip STM32WBA65RI"
3 3
4[build] 4[build]
5target = "thumbv8m.main-none-eabihf" 5target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
index 2c638f9f4..1ddae5fee 100644
--- a/examples/stm32wba/Cargo.toml
+++ b/examples/stm32wba/Cargo.toml
@@ -5,11 +5,13 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] } 8embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba65ri", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 10embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } 12embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
13embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13 15
14defmt = "1.0.1" 16defmt = "1.0.1"
15defmt-rtt = "1.0.0" 17defmt-rtt = "1.0.0"
diff --git a/examples/stm32wba/src/bin/usb_hs_serial.rs b/examples/stm32wba/src/bin/usb_hs_serial.rs
new file mode 100644
index 000000000..4684e3aa6
--- /dev/null
+++ b/examples/stm32wba/src/bin/usb_hs_serial.rs
@@ -0,0 +1,112 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_stm32::rcc::{VoltageScale, Hse, HsePrescaler, Sysclk, mux};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use panic_probe as _;
15
16bind_interrupts!(struct Irqs {
17 USB_OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Hello World!");
23
24 let mut config = Config::default();
25
26 // ── Run off the external 32 MHz crystal directly ──
27 config.rcc.hse = Some(Hse { prescaler: HsePrescaler::DIV1 });
28 config.rcc.sys = Sysclk::HSE;
29 // route HSE into the USB‐OTG‐HS block
30 config.rcc.mux.otghssel = mux::Otghssel::HSE;
31 config.rcc.sys = Sysclk::PLL1_R;
32 config.rcc.voltage_scale = VoltageScale::RANGE1;
33
34 let p = embassy_stm32::init(config);
35
36 // Create the driver, from the HAL.
37 let mut ep_out_buffer = [0u8; 256];
38 let mut config = embassy_stm32::usb::Config::default();
39 // Do not enable vbus_detection. This is a safe default that works in all boards.
40 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
41 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
42 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
43 config.vbus_detection = false;
44 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PD6, p.PD7, &mut ep_out_buffer, config);
45
46 // Create embassy-usb Config
47 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
48 config.manufacturer = Some("Embassy");
49 config.product = Some("USB-serial example");
50 config.serial_number = Some("12345678");
51
52 // Create embassy-usb DeviceBuilder using the driver and config.
53 // It needs some buffers for building the descriptors.
54 let mut config_descriptor = [0; 256];
55 let mut bos_descriptor = [0; 256];
56 let mut control_buf = [0; 64];
57
58 let mut state = State::new();
59
60 let mut builder = Builder::new(
61 driver,
62 config,
63 &mut config_descriptor,
64 &mut bos_descriptor,
65 &mut [], // no msos descriptors
66 &mut control_buf,
67 );
68
69 // Create classes on the builder.
70 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
71
72 // Build the builder.
73 let mut usb = builder.build();
74
75 // Run the USB device.
76 let usb_fut = usb.run();
77
78 // Do stuff with the class!
79 let echo_fut = async {
80 loop {
81 class.wait_connection().await;
82 info!("Connected");
83 let _ = echo(&mut class).await;
84 info!("Disconnected");
85 }
86 };
87
88 // Run everything concurrently.
89 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
90 join(usb_fut, echo_fut).await;
91}
92
93struct Disconnected {}
94
95impl From<EndpointError> for Disconnected {
96 fn from(val: EndpointError) -> Self {
97 match val {
98 EndpointError::BufferOverflow => panic!("Buffer overflow"),
99 EndpointError::Disabled => Disconnected {},
100 }
101 }
102}
103
104async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
105 let mut buf = [0; 64];
106 loop {
107 let n = class.read_packet(&mut buf).await?;
108 let data = &buf[..n];
109 info!("data: {:x}", data);
110 class.write_packet(data).await?;
111 }
112}
diff --git a/examples/stm32wba/src/bin/usb_serial.rs b/examples/stm32wba/src/bin/usb_serial.rs
new file mode 100644
index 000000000..8d60aed8c
--- /dev/null
+++ b/examples/stm32wba/src/bin/usb_serial.rs
@@ -0,0 +1,119 @@
1#![no_std]
2#![no_main]
3
4use defmt::{panic, *};
5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use panic_probe as _;
14
15bind_interrupts!(struct Irqs {
16 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17});
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 info!("Hello World!");
22
23 let mut config = Config::default();
24 {
25 use embassy_stm32::rcc::*;
26 config.rcc.hsi = true;
27 config.rcc.pll1 = Some(Pll {
28 source: PllSource::HSI, // 16 MHz
29 prediv: PllPreDiv::DIV1,
30 mul: PllMul::MUL10,
31 divp: None,
32 divq: None,
33 divr: Some(PllDiv::DIV1), // 160 MHz
34 });
35 config.rcc.sys = Sysclk::PLL1_R;
36 config.rcc.voltage_range = VoltageScale::RANGE1;
37 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
38 config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK
39 }
40
41 let p = embassy_stm32::init(config);
42
43 // Create the driver, from the HAL.
44 let mut ep_out_buffer = [0u8; 256];
45 let mut config = embassy_stm32::usb::Config::default();
46 // Do not enable vbus_detection. This is a safe default that works in all boards.
47 // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
48 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
49 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
50 config.vbus_detection = false;
51 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PD6, p.PD7, &mut ep_out_buffer, config);
52
53 // Create embassy-usb Config
54 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
55 config.manufacturer = Some("Embassy");
56 config.product = Some("USB-serial example");
57 config.serial_number = Some("12345678");
58
59 // Create embassy-usb DeviceBuilder using the driver and config.
60 // It needs some buffers for building the descriptors.
61 let mut config_descriptor = [0; 256];
62 let mut bos_descriptor = [0; 256];
63 let mut control_buf = [0; 64];
64
65 let mut state = State::new();
66
67 let mut builder = Builder::new(
68 driver,
69 config,
70 &mut config_descriptor,
71 &mut bos_descriptor,
72 &mut [], // no msos descriptors
73 &mut control_buf,
74 );
75
76 // Create classes on the builder.
77 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
78
79 // Build the builder.
80 let mut usb = builder.build();
81
82 // Run the USB device.
83 let usb_fut = usb.run();
84
85 // Do stuff with the class!
86 let echo_fut = async {
87 loop {
88 class.wait_connection().await;
89 info!("Connected");
90 let _ = echo(&mut class).await;
91 info!("Disconnected");
92 }
93 };
94
95 // Run everything concurrently.
96 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
97 join(usb_fut, echo_fut).await;
98}
99
100struct Disconnected {}
101
102impl From<EndpointError> for Disconnected {
103 fn from(val: EndpointError) -> Self {
104 match val {
105 EndpointError::BufferOverflow => panic!("Buffer overflow"),
106 EndpointError::Disabled => Disconnected {},
107 }
108 }
109}
110
111async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
112 let mut buf = [0; 64];
113 loop {
114 let n = class.read_packet(&mut buf).await?;
115 let data = &buf[..n];
116 info!("data: {:x}", data);
117 class.write_packet(data).await?;
118 }
119}