//! CDC-ACM serial port example using polling in a busy loop. //! Target board: any STM32F4 with a OTG FS peripheral and a 25MHz HSE crystal #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::otg_fs::{UsbBus, USB}; use stm32f4xx_hal::{pac, prelude::*}; use usb_device::prelude::*; static mut EP_MEMORY: [u32; 1024] = [0; 1024]; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let rcc = dp.RCC.constrain(); let clocks = rcc .cfgr .use_hse(25.MHz()) .sysclk(48.MHz()) .require_pll48clk() .freeze(); let gpioa = dp.GPIOA.split(); let usb = USB::new( (dp.OTG_FS_GLOBAL, dp.OTG_FS_DEVICE, dp.OTG_FS_PWRCLK), (gpioa.pa11, gpioa.pa12), &clocks, ); let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY }); let mut serial = usbd_serial::SerialPort::new(&usb_bus); let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) .device_class(usbd_serial::USB_CLASS_CDC) .strings(&[StringDescriptors::default() .manufacturer("Fake Company") .product("Product") .serial_number("TEST")]) .unwrap() .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 => { // 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; } _ => {} } } } _ => {} } } }