mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 22:54:52 +00:00
Working example in usb_hs_serial.rs
This commit is contained in:
parent
2cae242f51
commit
726991f2e9
@ -81,7 +81,7 @@ futures-util = { version = "0.3.30", default-features = false }
|
|||||||
sdio-host = "0.9.0"
|
sdio-host = "0.9.0"
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
#stm32-metapac = { version = "16" }
|
#stm32-metapac = { version = "16" }
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-dded8a33a460ae0eb182aee3ccb048beb659982b" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6201a7707ff38ac42ad50d5317dbd9e1e3686de3" }
|
||||||
|
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -110,7 +110,7 @@ proc-macro2 = "1.0.36"
|
|||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
|
|
||||||
#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]}
|
#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]}
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-dded8a33a460ae0eb182aee3ccb048beb659982b", default-features = false, features = ["metadata"] }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6201a7707ff38ac42ad50d5317dbd9e1e3686de3", default-features = false, features = ["metadata"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
runner = "probe-rs run --chip STM32WBA55CGUx"
|
runner = "probe-rs run --chip STM32WBA65RI"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "thumbv8m.main-none-eabihf"
|
target = "thumbv8m.main-none-eabihf"
|
||||||
|
@ -5,11 +5,13 @@ version = "0.1.0"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] }
|
embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba65ri", "time-driver-any", "memory-x", "exti"] }
|
||||||
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
|
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
|
||||||
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
|
embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
|
||||||
|
embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
|
||||||
defmt = "1.0.1"
|
defmt = "1.0.1"
|
||||||
defmt-rtt = "1.0.0"
|
defmt-rtt = "1.0.0"
|
||||||
|
112
examples/stm32wba/src/bin/usb_hs_serial.rs
Normal file
112
examples/stm32wba/src/bin/usb_hs_serial.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use defmt::{panic, *};
|
||||||
|
use defmt_rtt as _; // global logger
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_futures::join::join;
|
||||||
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
|
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
|
||||||
|
use embassy_stm32::rcc::{VoltageScale, Hse, HsePrescaler, Sysclk, mux};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
|
use embassy_usb::driver::EndpointError;
|
||||||
|
use embassy_usb::Builder;
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USB_OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
|
||||||
|
// ── Run off the external 32 MHz crystal directly ──
|
||||||
|
config.rcc.hse = Some(Hse { prescaler: HsePrescaler::DIV1 });
|
||||||
|
config.rcc.sys = Sysclk::HSE;
|
||||||
|
// route HSE into the USB‐OTG‐HS block
|
||||||
|
config.rcc.mux.otghssel = mux::Otghssel::HSE;
|
||||||
|
config.rcc.sys = Sysclk::PLL1_R;
|
||||||
|
config.rcc.voltage_scale = VoltageScale::RANGE1;
|
||||||
|
|
||||||
|
let p = embassy_stm32::init(config);
|
||||||
|
|
||||||
|
// Create the driver, from the HAL.
|
||||||
|
let mut ep_out_buffer = [0u8; 256];
|
||||||
|
let mut config = embassy_stm32::usb::Config::default();
|
||||||
|
// Do not enable vbus_detection. This is a safe default that works in all boards.
|
||||||
|
// However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
|
||||||
|
// to enable vbus_detection to comply with the USB spec. If you enable it, the board
|
||||||
|
// has to support it or USB won't work at all. See docs on `vbus_detection` for details.
|
||||||
|
config.vbus_detection = false;
|
||||||
|
let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PD6, p.PD7, &mut ep_out_buffer, config);
|
||||||
|
|
||||||
|
// Create embassy-usb Config
|
||||||
|
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
|
||||||
|
config.manufacturer = Some("Embassy");
|
||||||
|
config.product = Some("USB-serial example");
|
||||||
|
config.serial_number = Some("12345678");
|
||||||
|
|
||||||
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
|
// It needs some buffers for building the descriptors.
|
||||||
|
let mut config_descriptor = [0; 256];
|
||||||
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut control_buf = [0; 64];
|
||||||
|
|
||||||
|
let mut state = State::new();
|
||||||
|
|
||||||
|
let mut builder = Builder::new(
|
||||||
|
driver,
|
||||||
|
config,
|
||||||
|
&mut config_descriptor,
|
||||||
|
&mut bos_descriptor,
|
||||||
|
&mut [], // no msos descriptors
|
||||||
|
&mut control_buf,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create classes on the builder.
|
||||||
|
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
|
||||||
|
|
||||||
|
// Build the builder.
|
||||||
|
let mut usb = builder.build();
|
||||||
|
|
||||||
|
// Run the USB device.
|
||||||
|
let usb_fut = usb.run();
|
||||||
|
|
||||||
|
// Do stuff with the class!
|
||||||
|
let echo_fut = async {
|
||||||
|
loop {
|
||||||
|
class.wait_connection().await;
|
||||||
|
info!("Connected");
|
||||||
|
let _ = echo(&mut class).await;
|
||||||
|
info!("Disconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run everything concurrently.
|
||||||
|
// If we had made everything `'static` above instead, we could do this using separate tasks instead.
|
||||||
|
join(usb_fut, echo_fut).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Disconnected {}
|
||||||
|
|
||||||
|
impl From<EndpointError> for Disconnected {
|
||||||
|
fn from(val: EndpointError) -> Self {
|
||||||
|
match val {
|
||||||
|
EndpointError::BufferOverflow => panic!("Buffer overflow"),
|
||||||
|
EndpointError::Disabled => Disconnected {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
loop {
|
||||||
|
let n = class.read_packet(&mut buf).await?;
|
||||||
|
let data = &buf[..n];
|
||||||
|
info!("data: {:x}", data);
|
||||||
|
class.write_packet(data).await?;
|
||||||
|
}
|
||||||
|
}
|
119
examples/stm32wba/src/bin/usb_serial.rs
Normal file
119
examples/stm32wba/src/bin/usb_serial.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use defmt::{panic, *};
|
||||||
|
use defmt_rtt as _; // global logger
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_futures::join::join;
|
||||||
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
|
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
|
||||||
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
|
use embassy_usb::driver::EndpointError;
|
||||||
|
use embassy_usb::Builder;
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
{
|
||||||
|
use embassy_stm32::rcc::*;
|
||||||
|
config.rcc.hsi = true;
|
||||||
|
config.rcc.pll1 = Some(Pll {
|
||||||
|
source: PllSource::HSI, // 16 MHz
|
||||||
|
prediv: PllPreDiv::DIV1,
|
||||||
|
mul: PllMul::MUL10,
|
||||||
|
divp: None,
|
||||||
|
divq: None,
|
||||||
|
divr: Some(PllDiv::DIV1), // 160 MHz
|
||||||
|
});
|
||||||
|
config.rcc.sys = Sysclk::PLL1_R;
|
||||||
|
config.rcc.voltage_range = VoltageScale::RANGE1;
|
||||||
|
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
|
||||||
|
config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = embassy_stm32::init(config);
|
||||||
|
|
||||||
|
// Create the driver, from the HAL.
|
||||||
|
let mut ep_out_buffer = [0u8; 256];
|
||||||
|
let mut config = embassy_stm32::usb::Config::default();
|
||||||
|
// Do not enable vbus_detection. This is a safe default that works in all boards.
|
||||||
|
// However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need
|
||||||
|
// to enable vbus_detection to comply with the USB spec. If you enable it, the board
|
||||||
|
// has to support it or USB won't work at all. See docs on `vbus_detection` for details.
|
||||||
|
config.vbus_detection = false;
|
||||||
|
let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PD6, p.PD7, &mut ep_out_buffer, config);
|
||||||
|
|
||||||
|
// Create embassy-usb Config
|
||||||
|
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
|
||||||
|
config.manufacturer = Some("Embassy");
|
||||||
|
config.product = Some("USB-serial example");
|
||||||
|
config.serial_number = Some("12345678");
|
||||||
|
|
||||||
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
|
// It needs some buffers for building the descriptors.
|
||||||
|
let mut config_descriptor = [0; 256];
|
||||||
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut control_buf = [0; 64];
|
||||||
|
|
||||||
|
let mut state = State::new();
|
||||||
|
|
||||||
|
let mut builder = Builder::new(
|
||||||
|
driver,
|
||||||
|
config,
|
||||||
|
&mut config_descriptor,
|
||||||
|
&mut bos_descriptor,
|
||||||
|
&mut [], // no msos descriptors
|
||||||
|
&mut control_buf,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create classes on the builder.
|
||||||
|
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
|
||||||
|
|
||||||
|
// Build the builder.
|
||||||
|
let mut usb = builder.build();
|
||||||
|
|
||||||
|
// Run the USB device.
|
||||||
|
let usb_fut = usb.run();
|
||||||
|
|
||||||
|
// Do stuff with the class!
|
||||||
|
let echo_fut = async {
|
||||||
|
loop {
|
||||||
|
class.wait_connection().await;
|
||||||
|
info!("Connected");
|
||||||
|
let _ = echo(&mut class).await;
|
||||||
|
info!("Disconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run everything concurrently.
|
||||||
|
// If we had made everything `'static` above instead, we could do this using separate tasks instead.
|
||||||
|
join(usb_fut, echo_fut).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Disconnected {}
|
||||||
|
|
||||||
|
impl From<EndpointError> for Disconnected {
|
||||||
|
fn from(val: EndpointError) -> Self {
|
||||||
|
match val {
|
||||||
|
EndpointError::BufferOverflow => panic!("Buffer overflow"),
|
||||||
|
EndpointError::Disabled => Disconnected {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
loop {
|
||||||
|
let n = class.read_packet(&mut buf).await?;
|
||||||
|
let data = &buf[..n];
|
||||||
|
info!("data: {:x}", data);
|
||||||
|
class.write_packet(data).await?;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user