//! CDC-ACM serial port example using interrupts. //! Target board: Blue Pill #![no_std] #![no_main] extern crate panic_semihosting; use cortex_m::asm::{delay, wfi}; use cortex_m_rt::entry; use embedded_hal::digital::v2::OutputPin; use stm32f1xx_hal::pac::{interrupt, Interrupt}; use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType}; use stm32f1xx_hal::{prelude::*, stm32}; use usb_device::{bus::UsbBusAllocator, prelude::*}; use usbd_serial::{SerialPort, USB_CLASS_CDC}; static mut USB_BUS: Option> = None; static mut USB_SERIAL: Option> = None; static mut USB_DEVICE: Option> = None; #[entry] fn main() -> ! { let p = cortex_m::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); let mut flash = dp.FLASH.constrain(); let mut rcc = dp.RCC.constrain(); let clocks = rcc .cfgr .use_hse(8.mhz()) .sysclk(48.mhz()) .pclk1(24.mhz()) .freeze(&mut flash.acr); assert!(clocks.usbclk_valid()); let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); // BluePill board has a pull-up resistor on the D+ line. // Pull the D+ pin down to send a RESET condition to the USB bus. // This forced reset is needed only for development, without it host // will not reset your device when you upload new firmware. let mut usb_dp = gpioa.pa12.into_push_pull_output(&mut gpioa.crh); usb_dp.set_low(); delay(clocks.sysclk().0 / 100); let usb_dm = gpioa.pa11; let usb_dp = usb_dp.into_floating_input(&mut gpioa.crh); let usb = Peripheral { usb: dp.USB, pin_dm: usb_dm, pin_dp: usb_dp, }; // Unsafe to allow access to static variables unsafe { let bus = UsbBus::new(usb); USB_BUS = Some(bus); USB_SERIAL = Some(SerialPort::new(USB_BUS.as_ref().unwrap())); let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0x16c0, 0x27dd)) .manufacturer("Fake company") .product("Serial port") .serial_number("TEST") .device_class(USB_CLASS_CDC) .build(); USB_DEVICE = Some(usb_dev); } let mut nvic = p.NVIC; nvic.enable(Interrupt::USB_HP_CAN_TX); nvic.enable(Interrupt::USB_LP_CAN_RX0); loop { wfi(); } } #[interrupt] fn USB_HP_CAN_TX() { usb_interrupt(); } #[interrupt] fn USB_LP_CAN_RX0() { usb_interrupt(); } fn usb_interrupt() { let usb_dev = unsafe { USB_DEVICE.as_mut().unwrap() }; let serial = unsafe { USB_SERIAL.as_mut().unwrap() }; if !usb_dev.poll(&mut [serial]) { return; } let mut buf = [0u8; 8]; match serial.read(&mut buf) { Ok(count) if count > 0 => { // Echo back in upper case for c in buf[0..count].iter_mut() { if 0x61 <= *c && *c <= 0x7a { *c &= !0x20; } } serial.write(&buf[0..count]).ok(); } _ => {} } }