-
Notifications
You must be signed in to change notification settings - Fork 182
/
Copy pathusb_serial_rtic.rs
119 lines (97 loc) · 3.52 KB
/
usb_serial_rtic.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! CDC-ACM serial port example using cortex-m-rtic.
//! Target board: Blue Pill
#![no_main]
#![no_std]
#![allow(non_snake_case)]
#![deny(unsafe_code)]
use panic_semihosting as _;
#[rtic::app(device = stm32f1xx_hal::pac)]
mod app {
use cortex_m::asm::delay;
use stm32f1xx_hal::prelude::*;
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
use usb_device::prelude::*;
#[shared]
struct Shared {
usb_dev: UsbDevice<'static, UsbBusType>,
serial: usbd_serial::SerialPort<'static, UsbBusType>,
}
#[local]
struct Local {}
#[init(local = [usb_bus: Option<usb_device::bus::UsbBusAllocator<UsbBusType>> = None])]
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
let mut flash = cx.device.FLASH.constrain();
let 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();
// 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().raw() / 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,
};
cx.local.usb_bus.replace(UsbBus::new(usb));
let usb_bus = cx.local.usb_bus.as_ref().unwrap();
let serial = usbd_serial::SerialPort::new(usb_bus);
let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd))
.device_class(usbd_serial::USB_CLASS_CDC)
.strings(&[StringDescriptors::default()
.manufacturer("Fake Company")
.product("Serial port")
.serial_number("TEST")])
.unwrap()
.build();
(Shared { usb_dev, serial }, Local {}, init::Monotonics())
}
#[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial])]
fn usb_tx(cx: usb_tx::Context) {
let mut usb_dev = cx.shared.usb_dev;
let mut serial = cx.shared.serial;
(&mut usb_dev, &mut serial).lock(|usb_dev, serial| {
super::usb_poll(usb_dev, serial);
});
}
#[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial])]
fn usb_rx0(cx: usb_rx0::Context) {
let mut usb_dev = cx.shared.usb_dev;
let mut serial = cx.shared.serial;
(&mut usb_dev, &mut serial).lock(|usb_dev, serial| {
super::usb_poll(usb_dev, serial);
});
}
}
fn usb_poll<B: usb_device::bus::UsbBus>(
usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>,
serial: &mut usbd_serial::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();
}
_ => {}
}
}