|
@@ -0,0 +1,105 @@
|
|
|
+//! 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)]
|
|
|
+const APP: () = {
|
|
|
+ static mut USB_DEV: UsbDevice<'static, UsbBusType> = ();
|
|
|
+ static mut SERIAL: SerialPort<'static, UsbBusType> = ();
|
|
|
+
|
|
|
+ #[init]
|
|
|
+ fn init() {
|
|
|
+ static mut USB_BUS: Option<bus::UsbBusAllocator<UsbBusType>> = None;
|
|
|
+
|
|
|
+ let mut flash = device.FLASH.constrain();
|
|
|
+ let mut rcc = 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 = 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.
|
|
|
+ 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: 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();
|
|
|
+
|
|
|
+ USB_DEV = usb_dev;
|
|
|
+ SERIAL = serial;
|
|
|
+ }
|
|
|
+
|
|
|
+ #[interrupt(resources = [USB_DEV, SERIAL])]
|
|
|
+ fn USB_HP_CAN_TX() {
|
|
|
+ usb_poll(&mut resources.USB_DEV, &mut resources.SERIAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[interrupt(resources = [USB_DEV, SERIAL])]
|
|
|
+ fn USB_LP_CAN_RX0() {
|
|
|
+ usb_poll(&mut resources.USB_DEV, &mut resources.SERIAL);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+fn usb_poll<B: bus::UsbBus>(
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+ _ => {}
|
|
|
+ }
|
|
|
+}
|