From 3f0c2f753946cc74efbfa9f9d82ca32e3a0c4c54 Mon Sep 17 00:00:00 2001 From: Gabriel Dobato Date: Sat, 1 Jun 2024 19:31:16 +0200 Subject: [PATCH] Add usb led ctrl example --- Cargo.toml | 5 +- examples/usb_led_ctrl.rs | 192 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- 3 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 examples/usb_led_ctrl.rs diff --git a/Cargo.toml b/Cargo.toml index 5bd9a47..ec33e93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,12 +11,13 @@ stm32h7xx-hal = { version = "0.16.0", features = [ "rt", "usb_hs", ] } -defmt = "=0.3.8" -defmt-rtt = "0.4.1" +defmt = { version = "0.3", features = ["encoding-rzcobs"] } +defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] } panic-probe = { version = "0.3", features = ["print-defmt"] } embedded-hal-v1 = { version = "1.0.0", package = "embedded-hal" } embedded-hal-v0 = { version = "0.2.6", package = "embedded-hal", features = ["unproven"] } embedded-hal-async = "1.0.0" +rtic-sync = "1.3.0" [dev-dependencies] rtic = { version = "2.1.1", features = ["thumbv7-backend"] } diff --git a/examples/usb_led_ctrl.rs b/examples/usb_led_ctrl.rs new file mode 100644 index 0000000..b600b85 --- /dev/null +++ b/examples/usb_led_ctrl.rs @@ -0,0 +1,192 @@ +//! Example USB LED Control +//! +//! Controls LEDs over USB using the USB Device Class (CDC) for communication. +//! +//! The `Led` enum represents the different LEDs that can be controlled: Red (`0xAA`), Green (`0xBB`), and Blue (`0xCC`). +//! +//! The `Action` enum represents the actions that can be performed on an LED: turning it on (`0x01`) or off (`0x02`). +//! +//! To control an LED, send the hexadecimal value of the LED followed by the hexadecimal value of the action. For example, to turn the red LED on, send `0xAA 0x01`. + +#![no_std] +#![no_main] + +use core::mem::size_of; +use defmt::{debug, error, info}; +use portenta_h7::board::{self, Board, LedBlue, LedGreen, LedRed, UsbBusImpl}; +use rtic::app; +use rtic_monotonics::systick::prelude::*; +use rtic_sync::{channel::*, make_channel}; +use static_cell::StaticCell; +use usb_device::{class_prelude::UsbBusAllocator, prelude::*}; +use usbd_serial::CdcAcmClass; + +systick_monotonic!(Mono, 1000); + +const CHANNEL_CAPACITY: usize = 3; +const CHUNK_SIZE: usize = 2; +type Msg = [u8; CHUNK_SIZE]; + +const USB_MAX_PACKET_SIZE: usize = 64; +const USB_BUS_BUFFER_SIZE: usize = 1024; + +#[derive(Clone, Copy, Debug, defmt::Format)] +pub enum Led { + Red = 0xAA, + Green = 0xBB, + Blue = 0xCC, +} + +impl Led { + pub const fn as_u8(&self) -> u8 { + *self as u8 + } + + pub fn from_u8(value: u8) -> Option { + match value { + 0xAA => Some(Self::Red), + 0xBB => Some(Self::Green), + 0xCC => Some(Self::Blue), + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug, defmt::Format)] +pub enum Action { + On = 0x01, + Off = 0x02, +} + +impl Action { + pub const fn as_u8(&self) -> u8 { + *self as u8 + } + + pub fn from_u8(value: u8) -> Option { + match value { + 0x01 => Some(Self::On), + 0x02 => Some(Self::Off), + _ => None, + } + } +} + +#[app(device = portenta_h7::hal::pac, peripherals = false, dispatchers = [SPI1])] +mod app { + + use super::*; + + #[shared] + struct Shared {} + + #[local] + struct Local { + usb_dev: UsbDevice<'static, UsbBusImpl>, + usb_serial_port: CdcAcmClass<'static, UsbBusImpl>, + sender: Sender<'static, Msg, CHANNEL_CAPACITY>, + } + + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + info!("Init"); + Mono::start(cx.core.SYST, board::CORE_FREQUENCY.raw()); + // Get board resources + let Board { + led_red, + led_green, + led_blue, + usb, + .. + } = Board::take(); + + // Init USB stack + static USB_BUS_BUFFER: StaticCell<[u32; USB_BUS_BUFFER_SIZE]> = StaticCell::new(); + static USB_ALLOCATOR: StaticCell> = StaticCell::new(); + let usb_bus = USB_ALLOCATOR.init(UsbBusImpl::new( + usb, + USB_BUS_BUFFER.init([0; USB_BUS_BUFFER_SIZE]), + )); + let usb_serial_port = usbd_serial::CdcAcmClass::new(usb_bus, USB_MAX_PACKET_SIZE as u16); + let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x1234, 0xABCD)) + .device_class(usbd_serial::USB_CLASS_CDC) + .max_packet_size_0(64) + .unwrap() + .strings(&[StringDescriptors::default() + .manufacturer("example") + .product("usb-led-ctrl") + .serial_number("0123456789ABCDEF")]) + .unwrap() + .build(); + + // Create a channel to communicate between tasks + let (sender, receiver) = make_channel!(Msg, CHANNEL_CAPACITY); + + info!("Spawning tasks"); + let _ = led_control::spawn(led_red, led_green, led_blue, receiver); + + ( + Shared {}, + Local { + usb_dev, + usb_serial_port, + sender, + }, + ) + } + + #[task(priority = 0)] + async fn led_control( + _cx: led_control::Context, + mut led_red: LedRed, + mut led_green: LedGreen, + mut led_blue: LedBlue, + mut receiver: Receiver<'static, Msg, CHANNEL_CAPACITY>, + ) { + loop { + let msg = receiver.recv().await; + match msg { + Ok(data) => { + if let Some(led) = Led::from_u8(data[0]) { + if let Some(action) = Action::from_u8(data[1]) { + match (led, action) { + (Led::Red, Action::On) => led_red.on(), + (Led::Red, Action::Off) => led_red.off(), + (Led::Green, Action::On) => led_green.on(), + (Led::Green, Action::Off) => led_green.off(), + (Led::Blue, Action::On) => led_blue.on(), + (Led::Blue, Action::Off) => led_blue.off(), + } + debug!("Received: {:?} {:?}", led, action); + } + } + } + _ => error!("Msg receive error"), + } + } + } + + #[task(priority = 1, binds = OTG_HS, local = [usb_dev, usb_serial_port, sender])] + fn usb_process(cx: usb_process::Context) { + let (usb_dev, usb_serial_port, sender) = + (cx.local.usb_dev, cx.local.usb_serial_port, cx.local.sender); + + // Check if there are events to process by CDC class + if usb_dev.poll(&mut [usb_serial_port]) { + let mut app_buff = [0u8; USB_MAX_PACKET_SIZE]; + + // Read packets from reception FIFO + if let Ok(cnt) = usb_serial_port.read_packet(&mut app_buff) { + debug!("Received {} bytes: {:02X}", cnt, &app_buff[..cnt]); + + // Send data to led control task in chunks + let chunks = app_buff[..cnt].chunks_exact(size_of::()); + for chunk in chunks { + if let Ok(msg) = chunk.try_into() { + let _ = sender.try_send(msg); + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index f9cfef6..d9bb640 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,6 @@ pub mod drivers; mod sys; pub use cortex_m_rt::entry; #[allow(unused)] -use defmt_rtt as _; +use defmt_brtt as _; use panic_probe as _; pub use stm32h7xx_hal as hal;