From 948e0e377b633fb474380c35fe5d0a3f25344cd1 Mon Sep 17 00:00:00 2001 From: decaday Date: Thu, 26 Dec 2024 18:06:18 +0800 Subject: [PATCH] examples: add `usbd-f072` example --- examples/usbd-f072/.cargo/config.toml | 13 +++ examples/usbd-f072/Cargo.toml | 55 +++++++++++++ examples/usbd-f072/README.md | 13 +++ examples/usbd-f072/build.rs | 10 +++ examples/usbd-f072/src/bin/hid.rs | 111 ++++++++++++++++++++++++++ examples/usbd-f072/src/bin/serial.rs | 89 +++++++++++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 examples/usbd-f072/.cargo/config.toml create mode 100644 examples/usbd-f072/Cargo.toml create mode 100644 examples/usbd-f072/README.md create mode 100644 examples/usbd-f072/build.rs create mode 100644 examples/usbd-f072/src/bin/hid.rs create mode 100644 examples/usbd-f072/src/bin/serial.rs diff --git a/examples/usbd-f072/.cargo/config.toml b/examples/usbd-f072/.cargo/config.toml new file mode 100644 index 0000000..08ec816 --- /dev/null +++ b/examples/usbd-f072/.cargo/config.toml @@ -0,0 +1,13 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# TODO(2) replace `$CHIP` with your chip's name (see `probe-rs chip list` output) +runner = "probe-rs run --chip PY32F072xB" + +# rustflags = [ +# "-C", "linker=flip-link", +# ] + +[build] +target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ + +[env] +DEFMT_LOG = "trace" \ No newline at end of file diff --git a/examples/usbd-f072/Cargo.toml b/examples/usbd-f072/Cargo.toml new file mode 100644 index 0000000..12bfbc1 --- /dev/null +++ b/examples/usbd-f072/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "py32f072-examples" +version = "0.2.0" +edition = "2021" + +[dependencies] +panic-halt = "1.0.0" +cortex-m = { version = "0.7.7", features = [ + "critical-section-single-core", + "critical-section", +] } +cortex-m-rt = "0.7.3" +cortex-m-semihosting = { version = "0.5" } +panic-probe = { version = "0.3", features = ["print-defmt"] } + +py32-hal = { path = "../../", default-features = false,features = [ "py32f072c1b", + "time-driver-tim15", + "defmt", + "rt", + "memory-x", + "usb-device-impl", + "embassy" +]} + +defmt = "0.3" +defmt-rtt = "0.4" +embassy-futures = "0.1.1" +embassy-usb = { version = "0.3.0", features = [ "defmt"]} +usbd-human-interface-device = { version = "0.5.0", features = [ "defmt"]} + +portable-atomic = { version = "1.5", features = ["critical-section"] } +static_cell = "2.1" +usbd-serial = "0.2.2" +usb-device = "0.3.2" + + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 'z' # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + diff --git a/examples/usbd-f072/README.md b/examples/usbd-f072/README.md new file mode 100644 index 0000000..524bb05 --- /dev/null +++ b/examples/usbd-f072/README.md @@ -0,0 +1,13 @@ +# `usb-device` (`usbd`) Demo + +[!WARNING] + +This demo is intended to showcase the [usb-device](https://crates.io/crates/usb-device) crate, not the [embassy-usb](https://crates.io/crates/embassy-usb) crate. + +If you're looking for examples of USB async drivers, please refer to the [py32f072 examples](https://chatgpt.com/py32f072/src/bin). + +## Usage + +You need to enable the `usb-device-impl` feature and disable the `embassy-usb-driver-impl` feature. + +The PY32 uses a stripped-down version of the MUSB IP. For more information, check out the [musb](https://crates.io/crates/musb) crate. It includes implementations of both [embassy-usb-driver](https://crates.io/crates/embassy-usb-driver) and [usb-device](https://crates.io/crates/usb-device). \ No newline at end of file diff --git a/examples/usbd-f072/build.rs b/examples/usbd-f072/build.rs new file mode 100644 index 0000000..4b3ca97 --- /dev/null +++ b/examples/usbd-f072/build.rs @@ -0,0 +1,10 @@ +fn main() { + // `--nmagic` is required if memory section addresses are not aligned to 0x10000, + // for example the FLASH and RAM sections in your `memory.x`. + // See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + println!("cargo:rustc-link-arg=--nmagic"); + + println!("cargo:rustc-link-arg=-Tlink.x"); + + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/usbd-f072/src/bin/hid.rs b/examples/usbd-f072/src/bin/hid.rs new file mode 100644 index 0000000..57b0940 --- /dev/null +++ b/examples/usbd-f072/src/bin/hid.rs @@ -0,0 +1,111 @@ +#![no_std] +#![no_main] +#![feature(impl_trait_in_assoc_type)] + +use defmt::*; +use py32_hal::bind_interrupts; +use py32_hal::gpio::{Input, Level, Output, Pull, Speed}; +use py32_hal::rcc::{Pll, PllMul, PllSource, Sysclk}; +use py32_hal::time::Hertz; +use py32_hal::usb::{self, InterruptHandler}; +use {defmt_rtt as _, panic_probe as _}; + +use usb_device::{class_prelude::*, prelude::*}; +use usbd_human_interface_device::page::Keyboard; +use usbd_human_interface_device::prelude::*; + +bind_interrupts!(struct Irqs { + USB => InterruptHandler; +}); + +#[cortex_m_rt::entry] +fn main() -> ! { + let mut cfg: py32_hal::Config = Default::default(); + + // PY32 USB uses PLL as the clock source and can only run at 48Mhz. + cfg.rcc.hsi = Some(Hertz::mhz(16)); + cfg.rcc.pll = Some(Pll { + src: PllSource::HSI, + mul: PllMul::MUL3, + }); + cfg.rcc.sys = Sysclk::PLL; + let p = py32_hal::init(cfg); + + let mut led = Output::new(p.PB2, Level::High, Speed::Low); + let button = Input::new(p.PB0, Pull::Up); + + let usb_bus = usb::new_bus(p.USB, Irqs, p.PA12, p.PA11); + + let usb_bus_allocator = UsbBusAllocator::new(usb_bus); + + let mut keyboard = UsbHidClassBuilder::new() + .add_device(usbd_human_interface_device::device::keyboard::BootKeyboardConfig::default()) + .build(&usb_bus_allocator); + + //https://pid.codes + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus_allocator, UsbVidPid(0x1209, 0x0001)) + .strings(&[StringDescriptors::default() + .manufacturer("py32-rs team") + .product("Boot Keyboard") + .serial_number("TEST")]) + .unwrap() + .build(); + + let mut button_pressed = false; + + loop { + if button.is_high() { + if button_pressed { + // Button was just released + button_pressed = false; + // Send release report with no keys pressed + match keyboard.device().write_report([Keyboard::NoEventIndicated]) { + Err(UsbHidError::WouldBlock) => {} + Err(UsbHidError::Duplicate) => {} + Ok(_) => {} + Err(e) => { + core::panic!("Failed to write keyboard report: {:?}", e) + } + }; + } + } else { + if !button_pressed { + // Button was just pressed + button_pressed = true; + info!("Button pressed"); + // Send press report with 'A' key + match keyboard.device().write_report([Keyboard::A]) { + Err(UsbHidError::WouldBlock) => {} + Err(UsbHidError::Duplicate) => {} + Ok(_) => {} + Err(e) => { + core::panic!("Failed to write keyboard report: {:?}", e) + } + }; + } + } + + //Tick once per ms + match keyboard.tick() { + Err(UsbHidError::WouldBlock) => {} + Ok(_) => {} + Err(e) => { + core::panic!("Failed to process keyboard tick: {:?}", e) + } + }; + + if usb_dev.poll(&mut [&mut keyboard]) { + match keyboard.device().read_report() { + Err(UsbError::WouldBlock) => { + //do nothing + } + Err(e) => { + core::panic!("Failed to read keyboard report: {:?}", e) + } + Ok(leds) => { + led.set_level(Level::from(leds.caps_lock)); + } + } + } + } +} \ No newline at end of file diff --git a/examples/usbd-f072/src/bin/serial.rs b/examples/usbd-f072/src/bin/serial.rs new file mode 100644 index 0000000..c992dac --- /dev/null +++ b/examples/usbd-f072/src/bin/serial.rs @@ -0,0 +1,89 @@ +#![no_std] +#![no_main] +#![feature(impl_trait_in_assoc_type)] + +use defmt::*; +use py32_hal::bind_interrupts; +use py32_hal::gpio::{Level, Output, Speed}; +use py32_hal::rcc::{Pll, PllMul, PllSource, Sysclk}; +use py32_hal::time::Hertz; +use py32_hal::usb::{self, InterruptHandler}; +use {defmt_rtt as _, panic_probe as _}; + +use usb_device::{class_prelude::*, prelude::*}; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +bind_interrupts!(struct Irqs { + USB => InterruptHandler; +}); + +#[cortex_m_rt::entry] +fn main() -> ! { + let mut cfg: py32_hal::Config = Default::default(); + + // PY32 USB uses PLL as the clock source and can only run at 48Mhz. + cfg.rcc.hsi = Some(Hertz::mhz(16)); + cfg.rcc.pll = Some(Pll { + src: PllSource::HSI, + mul: PllMul::MUL3, + }); + cfg.rcc.sys = Sysclk::PLL; + let p = py32_hal::init(cfg); + + let mut led = Output::new(p.PB2, Level::High, Speed::Low); + + let usb_bus = usb::new_bus(p.USB, Irqs, p.PA12, p.PA11); + + let usb_bus_allocator = UsbBusAllocator::new(usb_bus); + + let mut serial = SerialPort::new(&usb_bus_allocator); + + let string_descriptors = StringDescriptors::new(LangID::EN_US) + .manufacturer("py32-rs team") + .product("Serial") + .serial_number("TEST"); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus_allocator, UsbVidPid(0x16c0, 0x27dd)) + .strings(&[string_descriptors]) + .unwrap() + .max_packet_size_0(64) + .unwrap() + .device_class(USB_CLASS_CDC) + .build(); + + loop { + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + + match serial.read(&mut buf) { + Ok(count) if count > 0 => { + led.set_high(); // Turn on + + info!("data: {:x}", &buf[0..count]); + + // Echo back in upper case + for c in buf[0..count].iter_mut() { + if 0x61 <= *c && *c <= 0x7a { + *c &= !0x20; + } + } + + let mut write_offset = 0; + while write_offset < count { + match serial.write(&buf[write_offset..count]) { + Ok(len) if len > 0 => { + write_offset += len; + } + _ => {} + } + } + } + _ => {} + } + + led.set_low(); // Turn off + } +}