From 9d783d3b3521e1c1ff228160ee3ebca653bf06f8 Mon Sep 17 00:00:00 2001 From: Tim Docker <tim@dockerz.net> Date: Sun, 12 May 2024 21:42:17 +1000 Subject: [PATCH] refactor rp usb_serial example to use a task to run the usb --- examples/rp/src/bin/usb_serial.rs | 110 ++++++++++++++++-------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index 3c9bc96dd..4a802994a 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -5,15 +5,15 @@ #![no_std] #![no_main] -use defmt::{info, panic}; +use defmt::{info, panic, unwrap}; use embassy_executor::Spawner; -use embassy_futures::join::join; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::{Builder, Config}; +use embassy_usb::UsbDevice; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::main] -async fn main(_spawner: Spawner) { +async fn main(spawner: Spawner) { info!("Hello there!"); let p = embassy_rp::init(Default::default()); @@ -30,59 +30,69 @@ async fn main(_spawner: Spawner) { let driver = Driver::new(p.USB, Irqs); // Create embassy-usb Config - let mut config = Config::new(0xc0de, 0xcafe); - config.manufacturer = Some("Embassy"); - config.product = Some("USB-serial example"); - config.serial_number = Some("12345678"); - config.max_power = 100; - config.max_packet_size_0 = 64; + let 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"); + config.max_power = 100; + config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + config + }; // 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 builder = { + static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new(); - 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"); - } + let builder = embassy_usb::Builder::new( + driver, + config, + CONFIG_DESCRIPTOR.init([0; 256]), + BOS_DESCRIPTOR.init([0; 256]), + &mut [], // no msos descriptors + CONTROL_BUF.init([0; 64]), + ); + builder }; - // 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; + // Create classes on the builder. + let mut class = { + static STATE: StaticCell<State> = StaticCell::new(); + let state = STATE.init(State::new()); + CdcAcmClass::new(&mut builder, state, 64) + }; + + // Build the builder. + let usb = builder.build(); + + // Run the USB device. + unwrap!(spawner.spawn(usb_task(usb))); + + // Do stuff with the class! + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } +} + +type MyUsbDriver = Driver<'static, USB>; +type MyUsbDevice = UsbDevice<'static, MyUsbDriver>; + +#[embassy_executor::task] +async fn usb_task(mut usb: MyUsbDevice) -> ! { + usb.run().await } struct Disconnected {}