//! CDC-ACM serial port example using cortex-m-rtfm. //! Target board: Blue Pill #![no_main] #![no_std] #![allow(non_snake_case)] extern crate panic_semihosting; use cortex_m::asm::delay; use embedded_hal::digital::v2::OutputPin; use rtfm::app; use stm32f1xx_hal::prelude::*; use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType}; use usb_device::bus; use usb_device::prelude::*; use usbd_serial::{SerialPort, USB_CLASS_CDC}; #[app(device = stm32f1xx_hal::stm32, peripherals = true)] const APP: () = { struct Resources { usb_dev: UsbDevice<'static, UsbBusType>, serial: SerialPort<'static, UsbBusType>, } #[init] fn init(cx: init::Context) -> init::LateResources { static mut USB_BUS: Option> = None; let mut flash = cx.device.FLASH.constrain(); let mut rcc = cx.device.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 = cx.device.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().unwrap(); 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: cx.device.USB, pin_dm: usb_dm, pin_dp: usb_dp, }; *USB_BUS = Some(UsbBus::new(usb)); let serial = 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(); init::LateResources { usb_dev, serial, } } #[task(binds = USB_HP_CAN_TX, resources = [usb_dev, serial])] fn usb_tx(mut cx: usb_tx::Context) { usb_poll(&mut cx.resources.usb_dev, &mut cx.resources.serial); } #[task(binds = USB_LP_CAN_RX0, resources = [usb_dev, serial])] fn usb_rx0(mut cx: usb_rx0::Context) { usb_poll(&mut cx.resources.usb_dev, &mut cx.resources.serial); } }; fn usb_poll( usb_dev: &mut UsbDevice<'static, B>, serial: &mut SerialPort<'static, B>, ) { 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(); } _ => {} } }