Skip to content

Commit

Permalink
Add usb led ctrl example
Browse files Browse the repository at this point in the history
  • Loading branch information
gdobato committed Jun 4, 2024
1 parent e075d7e commit 677ee5a
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 3 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
192 changes: 192 additions & 0 deletions examples/usb_led_ctrl.rs
Original file line number Diff line number Diff line change
@@ -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<Self> {
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<Self> {
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<UsbBusAllocator<UsbBusImpl>> = 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::<Msg>());
for chunk in chunks {
if let Ok(msg) = chunk.try_into() {
let _ = sender.try_send(msg);
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit 677ee5a

Please sign in to comment.