Skip to content

Commit

Permalink
implement usb peripheral
Browse files Browse the repository at this point in the history
  • Loading branch information
liamkinne committed Aug 30, 2024
1 parent ac40277 commit e0f537b
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 0 deletions.
94 changes: 94 additions & 0 deletions examples/usb_serial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! CDC-ACM serial port example using polling in a busy loop.
#![deny(warnings)]
#![deny(unsafe_code)]
#![no_std]
#![no_main]

use cortex_m_rt::entry;
use hal::prelude::*;
use hal::pwr::PwrExt;
use hal::usb::{Peripheral, UsbBus};
use hal::{rcc, stm32};
use stm32g4xx_hal as hal;
use stm32g4xx_hal::gpio::Speed;
use stm32g4xx_hal::rcc::{PllConfig, PllMDiv, PllNMul, PllRDiv, PllSrc};

use usb_device::prelude::*;
use usbd_serial::{SerialPort, USB_CLASS_CDC};

use utils::logger::info;

use panic_probe as _;

#[macro_use]
mod utils;

#[entry]
fn main() -> ! {
utils::logger::init();

let dp = stm32::Peripherals::take().expect("cannot take peripherals");
let pwr = dp.PWR.constrain().freeze();
let mut rcc = dp.RCC.freeze(rcc::Config::hsi(), pwr);
rcc.enable_hsi48();

let gpioa = dp.GPIOA.split(&mut rcc);

let mut led = gpioa.pa5.into_push_pull_output();
led.set_low().ok();

let usb_dm = gpioa.pa11.into_alternate();
let usb_dp = gpioa.pa12.into_alternate();

let usb = Peripheral {
usb: dp.USB,
pin_dm: usb_dm,
pin_dp: usb_dp,
};
let usb_bus = UsbBus::new(usb);

let mut serial = SerialPort::new(&usb_bus);

let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.strings(&[StringDescriptors::default()
.manufacturer("Fake company")
.product("Serial port")
.serial_number("TEST")])
.unwrap()
.device_class(USB_CLASS_CDC)
.build();

loop {
if !usb_dev.poll(&mut [&mut serial]) {
continue;
}

let mut buf = [0u8; 64];

match serial.read(&mut buf) {
Ok(count) if count > 0 => {
led.set_high().ok();

// Echo back in upper case
for c in buf[0..count].iter_mut() {
if 0x61 <= *c && *c <= 0x7a {
*c &= !0x20;
}
}

let mut write_offset = 0;
while write_offset < count {
match serial.write(&buf[write_offset..count]) {
Ok(len) if len > 0 => {
write_offset += len;
}
_ => {}
}
}
}
_ => {}
}

led.set_low().ok();
}
}
69 changes: 69 additions & 0 deletions src/usb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! USB peripheral.
//!
//! Provides the required implementation for use of the [`stm32-usbd`] crate.
pub use stm32_usbd::UsbBus;

use crate::gpio;
use crate::gpio::gpioa::{PA11, PA12};
use crate::rcc::{Enable, Reset};
use crate::stm32::{RCC, USB};
use core::fmt;
use stm32_usbd::UsbPeripheral;

/// Trait implemented by all pins that can be the "D-" pin for the USB peripheral
pub trait DmPin: crate::Sealed {}

/// Trait implemented by all pins that can be the "D+" pin for the USB peripheral
pub trait DpPin: crate::Sealed {}

impl DmPin for PA11<gpio::Alternate<{ gpio::AF14 }>> {}
impl DpPin for PA12<gpio::Alternate<{ gpio::AF14 }>> {}

pub struct Peripheral<Dm: DmPin, Dp: DpPin> {
/// USB register block
pub usb: USB,
/// Data negative pin
pub pin_dm: Dm,
/// Data positive pin
pub pin_dp: Dp,
}

impl<Dm, Dp> fmt::Debug for Peripheral<Dm, Dp>
where
Dm: DmPin + fmt::Debug,
Dp: DpPin + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Peripheral")
.field("usb", &"USB")
.field("pin_dm", &self.pin_dm)
.field("pin_dp", &self.pin_dp)
.finish()
}
}

// SAFETY: Implementation of Peripheral is thread-safe by using cricitcal sections to ensure
// mutually exclusive access to the USB peripheral
unsafe impl<Dm: DmPin, Dp: DpPin> Sync for Peripheral<Dm, Dp> {}

// SAFETY: The peripheral has the same regiter blockout as the STM32 USBFS
unsafe impl<Dm: DmPin + Send, Dp: DpPin + Send> UsbPeripheral for Peripheral<Dm, Dp> {
const REGISTERS: *const () = USB::ptr().cast::<()>();
const DP_PULL_UP_FEATURE: bool = true;
const EP_MEMORY: *const () = 0x4000_6000 as _;
const EP_MEMORY_SIZE: usize = 1024;
const EP_MEMORY_ACCESS_2X16: bool = true;

fn enable() {
critical_section::with(|_| unsafe {
let rcc_ptr = &(*RCC::ptr());
USB::enable(rcc_ptr);
USB::reset(rcc_ptr);
});
}

fn startup_delay() {
// not required
}
}

0 comments on commit e0f537b

Please sign in to comment.