Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usb-device impl and example #23

Merged
merged 2 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ log = { version = "0.4", optional = true }
critical-section = "1.2"
cfg-if = "1.0.0"
portable-atomic = { version = "1", features = ["unsafe-assume-single-core", "require-cas"], optional = true }
# musb = { version = "0.1.0", optional = true, features = ["prebuild"] }
# musb = { version = "0.2.0", optional = true, features = ["prebuild"] }
musb = { git = "https://github.com/decaday/musb.git", optional = true, features = ["prebuild"] }
# musb = { path = "../musb", optional = true , features = ["prebuild"] }

embassy-usb-driver = {version = "0.1.0", optional = true }
usb-device = {version = "0.3.2", optional = true }


futures-util = { version = "0.3.30", default-features = false }
embassy-hal-internal = { version = "0.2.0", features = [
"cortex-m",
Expand All @@ -60,7 +64,7 @@ embassy-executor = { version = "0.6", features = [
"arch-cortex-m",
] }
embassy-embedded-hal = { version = "0.2.0", default-features = false }
embassy-usb-driver = {version = "0.1.0" }


[build-dependencies]
# py32-metapac = { path = "../py32-data/build/py32-metapac", default-features = false, features = [
Expand All @@ -77,7 +81,7 @@ default = ["rt", "memory-x", "defmt", "embassy", "time", "exti"]

rt = ["py32-metapac/rt"]

defmt = ["dep:defmt", "dep:defmt-rtt", "embassy-usb-driver/defmt"]
defmt = ["dep:defmt", "dep:defmt-rtt", "embassy-usb-driver/defmt", "musb?/defmt"]

memory-x = ["py32-metapac/memory-x"]

Expand All @@ -87,10 +91,8 @@ time = ["dep:embassy-time", "embassy-embedded-hal/time"]

exti = []

# PY32F07x: the IN and OUT buffers of the same endpoint being shared
# When this feature is enabled, the In and Out of an endpoint will not be used at the same time, except for ep0.
# PY32F403: IN and OUT do not share FIFO, this feature is invalid
allow-ep-shared-fifo = ["musb/allow-ep-shared-fifo"]
embassy-usb-driver-impl = ["dep:musb","dep:embassy-usb-driver", "musb/embassy-usb-driver-impl"]
usb-device-impl = ["dep:musb","dep:usb-device", "musb/usb-device-impl"]

py32f030k28 = ["py32-metapac/py32f030k28"]
py32f030f16 = ["py32-metapac/py32f030f16"]
Expand Down
2 changes: 1 addition & 1 deletion examples/py32f072/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime
embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.6.1" }

py32-hal = { path = "../../", features = [ "time-driver-tim15", "py32f072c1b"]}
py32-hal = { path = "../../", features = [ "time-driver-tim15", "py32f072c1b", "embassy-usb-driver-impl"]}

defmt = "0.3"
defmt-rtt = "0.4"
Expand Down
13 changes: 13 additions & 0 deletions examples/usbd-f072/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -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"
55 changes: 55 additions & 0 deletions examples/usbd-f072/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[package]
name = "py32f072-usbd-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 # <-

13 changes: 13 additions & 0 deletions examples/usbd-f072/README.md
Original file line number Diff line number Diff line change
@@ -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).
10 changes: 10 additions & 0 deletions examples/usbd-f072/build.rs
Original file line number Diff line number Diff line change
@@ -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");
}
111 changes: 111 additions & 0 deletions examples/usbd-f072/src/bin/hid.rs
Original file line number Diff line number Diff line change
@@ -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<py32_hal::peripherals::USB>;
});

#[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));
}
}
}
}
}
89 changes: 89 additions & 0 deletions examples/usbd-f072/src/bin/serial.rs
Original file line number Diff line number Diff line change
@@ -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<py32_hal::peripherals::USB>;
});

#[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
}
}
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ pub mod usart;
pub mod gpio;
#[cfg(feature = "time-driver-systick")]
pub mod systick_time_driver;
#[cfg(feature = "py32f072c1b")]

#[cfg(any(feature = "embassy-usb-driver-impl", feature = "usb-device-impl"))]
pub mod usb;

#[cfg(feature = "exti")]
Expand Down
Loading
Loading