Skip to content

Commit

Permalink
Use 2 tasks in usb echo example
Browse files Browse the repository at this point in the history
  • Loading branch information
gdobato committed Jun 4, 2024
1 parent 3f0c2f7 commit 8c24a4e
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 23 deletions.
99 changes: 77 additions & 22 deletions examples/usb_echo.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,48 @@
//! Example USB echo
//!
//! Uses a Usb CDC class to echo the data received by the host
//! Sets up the device to appear as a virtual serial port to the host.
//! When the host sends data to this virtual serial port, the device receives it and then sends (echoes) the same data back to the host.
//! Additionally, on enumeration complete, green LED is on, otherwise red LED is on.
//!
#![no_std]
#![no_main]

use defmt::{error, info};
use portenta_h7::board::{self, Board, LedBlue, UsbBusImpl};
use portenta_h7::board::{self, Board, 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);

#[derive(Clone, Copy, Debug, defmt::Format)]
enum EnumerationState {
Complete,
Lost,
}

const CHANNEL_CAPACITY: usize = 1;
type Msg = EnumerationState;

const USB_MAX_PACKET_SIZE: usize = 64;
const USB_BUS_BUFFER_SIZE: usize = 1024;

#[app(device = portenta_h7::hal::pac, peripherals = false)]
mod app {
use super::*;

// USB buffers
const APP_BUFF_SIZE: usize = 64;
const USB_BUS_BUFFER_SIZE: usize = 1024;
static USB_BUS_BUFFER: StaticCell<[u32; USB_BUS_BUFFER_SIZE]> = StaticCell::new();
static USB_ALLOCATOR: StaticCell<UsbBusAllocator<UsbBusImpl>> = StaticCell::new();

#[shared]
struct Shared {}

#[local]
struct Local {
led_blue: LedBlue,
usb_dev: UsbDevice<'static, UsbBusImpl>,
usb_serial_port: CdcAcmClass<'static, UsbBusImpl>,
sender: Sender<'static, Msg, CHANNEL_CAPACITY>,
}

#[init]
Expand All @@ -43,14 +52,21 @@ mod app {
Mono::start(cx.core.SYST, board::CORE_FREQUENCY.raw());

// Get board resources
let Board { led_blue, usb, .. } = Board::take();
let Board {
led_red,
led_green,
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, APP_BUFF_SIZE as u16);
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)
Expand All @@ -62,25 +78,64 @@ mod app {
.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, receiver);

(
Shared {},
Local {
led_blue,
usb_dev,
usb_serial_port,
sender,
},
)
}

#[task(binds = OTG_HS, local = [led_blue, usb_dev, usb_serial_port])]
#[task(priority = 0)]
async fn led_control(
_cx: led_control::Context,
mut led_red: LedRed,
mut led_green: LedGreen,
mut receiver: Receiver<'static, Msg, CHANNEL_CAPACITY>,
) {
// Initial state
led_red.on();

loop {
let msg = receiver.recv().await;
match msg {
Ok(data) => match data {
EnumerationState::Complete => {
info!("Enumeration complete");
led_red.off();
led_green.on();
}
EnumerationState::Lost => {
info!("Enumeration lost");
led_green.off();
led_red.on();
}
},

Err(_) => {
error!("Error receiving message");
}
}
}
}

#[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) = (cx.local.usb_dev, cx.local.usb_serial_port);
let previous_state = usb_dev.state();

// Trigger internal state machine. It should be called either from ISR on USB event,
// or every 10 ms from normal execution context
if usb_dev.poll(&mut [usb_serial_port]) {
let mut app_buff = [0u8; APP_BUFF_SIZE];
let mut app_buff = [0u8; USB_MAX_PACKET_SIZE];

// Read from reception fifo
match usb_serial_port.read_packet(&mut app_buff) {
Expand All @@ -104,17 +159,17 @@ mod app {

// Signal enumeration status
match usb_dev.state() {
// Transition to enumeration
// Enumeration complete
UsbDeviceState::Configured if previous_state == UsbDeviceState::Addressed => {
info!("Enumeration completed");
cx.local.led_blue.on();
let _ = cx.local.sender.try_send(EnumerationState::Complete);
}
// Already enumerated
UsbDeviceState::Configured => {}

// Enumeration lost
_ if previous_state == UsbDeviceState::Configured => {
info!("Enumeration lost");
cx.local.led_blue.off();
state
if previous_state == UsbDeviceState::Configured
&& state != UsbDeviceState::Configured =>
{
let _ = cx.local.sender.try_send(EnumerationState::Lost);
}
_ => (),
}
Expand Down
4 changes: 3 additions & 1 deletion examples/usb_led_ctrl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ mod app {
}
}
}
_ => error!("Msg receive error"),
Err(_) => {
error!("Error receiving message");
}
}
}
}
Expand Down

0 comments on commit 8c24a4e

Please sign in to comment.