Skip to content

Commit

Permalink
Merge pull request #789 from quartiq/feature/usb-support
Browse files Browse the repository at this point in the history
Adding basic USB implementation
  • Loading branch information
jordens authored Oct 16, 2023
2 parents e8070a7 + 98342bf commit 041d33c
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 11 deletions.
38 changes: 38 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,20 @@ enum-iterator = "1.4.1"
rand_xorshift = "0.3.0"
rand_core = "0.6.4"
minimq = { git = "https://github.com/quartiq/minimq" } # "0.8"
usb-device = "0.2.9"
usbd-serial = "0.1.1"
# Keep this synced with the miniconf version in py/setup.py
miniconf = { git = "https://github.com/quartiq/miniconf.git" } # "0.9"
smoltcp-nal = { version = "0.4.1", features = ["shared-stack"]}
bbqueue = "0.5"

[dependencies.stm32h7xx-hal]
git = "https://github.com/stm32-rs/stm32h7xx-hal"
features = ["stm32h743v", "rt", "ethernet", "xspi"]
features = ["stm32h743v", "rt", "ethernet", "xspi", "usb_hs"]

[patch.crates-io.usb-device]
git = "https://github.com/ryan-summers/usb-device"
branch = "rs/issue-128-v0.2.9"

[features]
nightly = [ ]
Expand Down
25 changes: 23 additions & 2 deletions src/bin/dual-iir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ use stabilizer::{
afe::Gain,
dac::{Dac0Output, Dac1Output, DacCode},
hal,
serial_terminal::SerialTerminal,
signal_generator::{self, SignalGenerator},
timers::SamplingTimer,
DigitalInput0, DigitalInput1, SystemTimer, Systick, AFE0, AFE1,
Expand Down Expand Up @@ -182,6 +183,7 @@ mod app {

#[shared]
struct Shared {
usb_terminal: SerialTerminal,
network: NetworkUsers<Settings, Telemetry, 3>,

settings: Settings,
Expand Down Expand Up @@ -228,6 +230,7 @@ mod app {
let settings = Settings::default();

let shared = Shared {
usb_terminal: stabilizer.usb_serial,
network,
settings,
telemetry: TelemetryBuffer::default(),
Expand Down Expand Up @@ -266,6 +269,7 @@ mod app {
settings_update::spawn().unwrap();
telemetry::spawn().unwrap();
ethernet_link::spawn().unwrap();
usb::spawn().unwrap();
start::spawn_after(100.millis()).unwrap();

(shared, local, init::Monotonics(stabilizer.systick))
Expand Down Expand Up @@ -388,15 +392,23 @@ mod app {
);
}

#[idle(shared=[network])]
#[idle(shared=[network, usb_terminal])]
fn idle(mut c: idle::Context) -> ! {
loop {
match c.shared.network.lock(|net| net.update()) {
NetworkState::SettingsChanged(_path) => {
settings_update::spawn().unwrap()
}
NetworkState::Updated => {}
NetworkState::NoChange => cortex_m::asm::wfi(),
NetworkState::NoChange => {
// We can't sleep if USB is not in suspend.
if c.shared
.usb_terminal
.lock(|terminal| terminal.usb_is_suspended())
{
cortex_m::asm::wfi();
}
}
}
}
}
Expand Down Expand Up @@ -452,6 +464,15 @@ mod app {
.unwrap();
}

#[task(priority = 1, shared=[usb_terminal])]
fn usb(mut c: usb::Context) {
// Handle the USB serial terminal.
c.shared.usb_terminal.lock(|usb| usb.process());

// Schedule to run this task every 10 milliseconds.
usb::spawn_after(10u64.millis()).unwrap();
}

#[task(priority = 1, shared=[network])]
fn ethernet_link(mut c: ethernet_link::Context) {
c.shared.network.lock(|net| net.processor.handle_link());
Expand Down
24 changes: 22 additions & 2 deletions src/bin/lockin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use stabilizer::{
dac::{Dac0Output, Dac1Output, DacCode},
hal,
input_stamper::InputStamper,
serial_terminal::SerialTerminal,
signal_generator,
timers::SamplingTimer,
DigitalInput0, DigitalInput1, SystemTimer, Systick, AFE0, AFE1,
Expand Down Expand Up @@ -221,6 +222,7 @@ mod app {

#[shared]
struct Shared {
usb_terminal: SerialTerminal,
network: NetworkUsers<Settings, Telemetry, 2>,
settings: Settings,
telemetry: TelemetryBuffer,
Expand Down Expand Up @@ -267,6 +269,7 @@ mod app {

let shared = Shared {
network,
usb_terminal: stabilizer.usb_serial,
telemetry: TelemetryBuffer::default(),
settings: Settings::default(),
};
Expand Down Expand Up @@ -451,15 +454,23 @@ mod app {
});
}

#[idle(shared=[network])]
#[idle(shared=[network, usb_terminal])]
fn idle(mut c: idle::Context) -> ! {
loop {
match c.shared.network.lock(|net| net.update()) {
NetworkState::SettingsChanged(_path) => {
settings_update::spawn().unwrap()
}
NetworkState::Updated => {}
NetworkState::NoChange => cortex_m::asm::wfi(),
NetworkState::NoChange => {
// We can't sleep if USB is not in suspend.
if c.shared
.usb_terminal
.lock(|terminal| terminal.usb_is_suspended())
{
cortex_m::asm::wfi();
}
}
}
}
}
Expand Down Expand Up @@ -504,6 +515,15 @@ mod app {
.unwrap();
}

#[task(priority = 1, shared=[usb_terminal])]
fn usb(mut c: usb::Context) {
// Handle the USB serial terminal.
c.shared.usb_terminal.lock(|usb| usb.process());

// Schedule to run this task every 10 milliseconds.
usb::spawn_after(10u64.millis()).unwrap();
}

#[task(priority = 1, shared=[network])]
fn ethernet_link(mut c: ethernet_link::Context) {
c.shared.network.lock(|net| net.processor.handle_link());
Expand Down
3 changes: 3 additions & 0 deletions src/hardware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod delay;
pub mod design_parameters;
pub mod input_stamper;
pub mod pounder;
pub mod serial_terminal;
pub mod setup;
pub mod shared_adc;
pub mod signal_generator;
Expand All @@ -30,6 +31,8 @@ pub type AFE1 = afe::ProgrammableGainAmplifier<
hal::gpio::gpiod::PD15<hal::gpio::Output<hal::gpio::PushPull>>,
>;

pub type UsbBus = stm32h7xx_hal::usb_hs::UsbBus<stm32h7xx_hal::usb_hs::USB2>;

// Type alias for digital input 0 (DI0).
pub type DigitalInput0 = hal::gpio::gpiog::PG9<hal::gpio::Input>;

Expand Down
96 changes: 96 additions & 0 deletions src/hardware/serial_terminal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use super::UsbBus;
use core::fmt::Write;

static OUTPUT_BUFFER: bbqueue::BBBuffer<512> = bbqueue::BBBuffer::new();

pub struct OutputBuffer {
producer: bbqueue::Producer<'static, 512>,
}

impl Write for OutputBuffer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let data = s.as_bytes();

// Write as much data as possible to the output buffer.
let Ok(mut grant) = self.producer.grant_max_remaining(data.len())
else {
// Output buffer is full, silently drop the data.
return Ok(());
};

let len = grant.buf().len();
grant.buf().copy_from_slice(&data[..len]);
grant.commit(len);
Ok(())
}
}

pub struct SerialTerminal {
usb_device: usb_device::device::UsbDevice<'static, UsbBus>,
usb_serial: usbd_serial::SerialPort<'static, UsbBus>,
output: bbqueue::Consumer<'static, 512>,
buffer: OutputBuffer,
}

impl SerialTerminal {
pub fn new(
usb_device: usb_device::device::UsbDevice<'static, UsbBus>,
usb_serial: usbd_serial::SerialPort<'static, UsbBus>,
) -> Self {
let (producer, consumer) = OUTPUT_BUFFER.try_split().unwrap();

Self {
buffer: OutputBuffer { producer },
usb_device,
usb_serial,
output: consumer,
}
}

fn flush(&mut self) {
let read = match self.output.read() {
Ok(grant) => grant,
Err(bbqueue::Error::InsufficientSize) => return,
err => err.unwrap(),
};

match self.usb_serial.write(read.buf()) {
Ok(count) => read.release(count),
Err(usbd_serial::UsbError::WouldBlock) => read.release(0),
Err(_) => {
let len = read.buf().len();
read.release(len);
}
}
}

pub fn usb_is_suspended(&self) -> bool {
self.usb_device.state() == usb_device::device::UsbDeviceState::Suspend
}

pub fn process(&mut self) {
self.flush();

if !self.usb_device.poll(&mut [&mut self.usb_serial]) {
return;
}

let mut buffer = [0u8; 64];
match self.usb_serial.read(&mut buffer) {
Ok(count) => {
for &value in &buffer[..count] {
writeln!(self.buffer, "echo: {}", value as char).unwrap();
}
}

Err(usbd_serial::UsbError::WouldBlock) => {}
Err(_) => {
// Clear the output buffer if USB is not connected.
while let Ok(grant) = self.output.read() {
let len = grant.buf().len();
grant.release(len);
}
}
}
}
}
Loading

0 comments on commit 041d33c

Please sign in to comment.