You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to create two serial devices over USB and I get an error at initialization of the second serial device.
#![allow(unused_imports)]
#![no_std]
#![no_main]
//Global dependancies
use core::panic::PanicInfo;
use defmt_rtt as _;
use rtic::app;
#[app(device = rp_pico::hal::pac, peripherals = true, dispatchers = [TIMER_IRQ_1])]
mod app {
// Application Dependancies
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
use rp2040_monotonic::{
fugit::Duration,
fugit::RateExtU32, // For .kHz() conversion funcs
Rp2040Monotonic,
};
use rp_pico::hal;
use rp_pico::hal::{
clocks, gpio, gpio::pin::bank0::Gpio25, gpio::pin::PushPullOutput, pac, sio::Sio,
watchdog::Watchdog, I2C,
};
use rp_pico::XOSC_CRYSTAL_FREQ;
// USB Device support
use usb_device::{class_prelude::*, prelude::*};
// USB Communications Class Device support
use usbd_serial::SerialPort;
// Application types
#[monotonic(binds = TIMER_IRQ_0, default = true)]
type Rp2040Mono = Rp2040Monotonic;
// Apllication constants
const MONO_NUM: u32 = 1;
const MONO_DENOM: u32 = 1_000_000;
const POLL_PERIOD_TICKS: u64 = 1_000_000;
// Apllication Data structures
#[shared]
struct Shared {
serial_cmd: SerialPort<'static, hal::usb::UsbBus>,
usb_dev_cmd: usb_device::device::UsbDevice<'static, hal::usb::UsbBus>,
//
serial_log: SerialPort<'static, hal::usb::UsbBus>,
usb_dev_log: usb_device::device::UsbDevice<'static, hal::usb::UsbBus>,
}
#[local]
struct Local {
led: gpio::Pin<Gpio25, PushPullOutput>,
}
// Apllication System level components
#[init(local = [usb_bus: Option<usb_device::bus::UsbBusAllocator<hal::usb::UsbBus>> = None])]
fn init(mut _cx: init::Context) -> (Shared, Local, init::Monotonics) {
defmt::info!("init()");
// Configure the clocks, watchdog - The default is to generate a 125 MHz system clock
let mut watchdog = Watchdog::new(_cx.device.WATCHDOG);
let clocks = clocks::init_clocks_and_plls(
XOSC_CRYSTAL_FREQ,
_cx.device.XOSC,
_cx.device.CLOCKS,
_cx.device.PLL_SYS,
_cx.device.PLL_USB,
&mut _cx.device.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let mono = Rp2040Mono::new(_cx.device.TIMER);
// Init LED pin
let sio = Sio::new(_cx.device.SIO);
let gpioa = rp_pico::Pins::new(
_cx.device.IO_BANK0,
_cx.device.PADS_BANK0,
sio.gpio_bank0,
&mut _cx.device.RESETS,
);
let mut led = gpioa.led.into_push_pull_output();
led.set_low().unwrap();
// USB
//
// Set up the USB driver
// The bus that is used to manage the device and class below.
let usb_bus: &'static _ =
_cx.local
.usb_bus
.insert(UsbBusAllocator::new(hal::usb::UsbBus::new(
_cx.device.USBCTRL_REGS,
_cx.device.USBCTRL_DPRAM,
clocks.usb_clock,
true,
&mut _cx.device.RESETS,
)));
// Set up the USB Communications Class Device driver.
let serial_cmd = SerialPort::new(usb_bus);
// Create a USB device with a fake VID and PID
let usb_dev_cmd = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd))
.manufacturer("Virtual")
.product("Serial port 0")
.serial_number("CMD")
.device_class(2) // from: https://www.usb.org/defined-class-codes
.build();
// Set up the USB Communications Class Device driver.
let serial_log = SerialPort::new(usb_bus);
// Create a USB device with a fake VID and PID
let usb_dev_log = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd))
.manufacturer("Virtual")
.product("Serial port 1")
.serial_number("LOG")
.device_class(2) // from: https://www.usb.org/defined-class-codes
.build();
// Spawn react task
react::spawn().unwrap();
(
Shared {
serial_cmd,
usb_dev_cmd,
//
serial_log,
usb_dev_log,
},
Local { led },
init::Monotonics(mono),
)
}
#[task(local = [led])]
fn react(ctx: react::Context) {
let next_period = monotonics::now()
+ Duration::<u64, MONO_NUM, MONO_DENOM>::from_ticks(POLL_PERIOD_TICKS);
// Flicker the built-in LED
_ = ctx.local.led.toggle();
// Congrats, you can use your i2c and have access to it here,
// now to do something with it!
react::spawn_at(next_period).unwrap();
}
#[task(binds = USBCTRL_IRQ, priority = 1, shared = [serial_cmd, usb_dev_cmd, serial_log,
usb_dev_log])]
fn usb_rx(cx: usb_rx::Context) {
let usb_dev = cx.shared.usb_dev_cmd;
let serial = cx.shared.serial_cmd;
let log = cx.shared.serial_log;
(usb_dev, serial /*, log*/).lock(|usb_dev_a, serial_a /*, serial_b*/| {
// Check for new data
if usb_dev_a.poll(&mut [serial_a]) {
let mut buf = [0u8; 64];
match serial_a.read(&mut buf) {
Err(_e) => {
//defmt::error!("UsbError");
}
Ok(0) => {
//defmt::error!("Usb NoData");
// Do nothing
//let _ = serial_a.write(b"Didn't received data.");
//let _ = serial_a.flush();
}
Ok(_count) => {
// Code to echo the characters in Upper Case.
// Convert to upper case
buf.iter_mut().take(_count).for_each(|b| {
b.make_ascii_uppercase();
});
// Send back to the host
let mut wr_ptr = &buf[.._count];
while !wr_ptr.is_empty() {
match serial_a.write(wr_ptr) {
Ok(len) => {
wr_ptr = &wr_ptr[len..];
let _ = serial_a.flush();
//
let _ = serial_b.write(wr_ptr);
let _ = serial_b.flush();
}
// On error, just drop unwritten data.
// One possible error is Err(WouldBlock), meaning the USB
// write buffer is full.
Err(_) => break,
};
}
}
}
}
});
}
}
#[defmt::panic_handler]
fn defmt_panic() -> ! {
loop {}
}
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
The above code crashes at let serial_log = SerialPort::new(usb_bus);
In that call, lower down, here is where it fails.
The text was updated successfully, but these errors were encountered:
It looks like what you're trying to do is expose two serial port interfaces, but you've implemented it as two usb devices. Unfortunately, your microcontroller is only a single device and it cannot act is two devices simultaneously. What you'd want is to expose two interfaces as an interface association as a single device. This is something the usbd_serial crate would have to support for you to use. Otherwise you'll have to do it yourself.
Just to follow up, this should be supported with the current implementation. You would simply create multiple usbd_serial::SerialPort items and change the device_class to 0 (https://www.usb.org/defined-class-codes).
That being said, I was trying to do this with the usbd_serial crate and am having trouble getting both ports to enumerate. rust-embedded-community/usbd-serial#34 should be the proper issue for tracking this behavior.
I'm trying to create two serial devices over USB and I get an error at initialization of the second serial device.
The above code crashes at
let serial_log = SerialPort::new(usb_bus);
In that call, lower down, here is where it fails.
The text was updated successfully, but these errors were encountered: