-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |