aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f3/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-05-30 00:36:30 +0200
committerDario Nieuwenhuis <[email protected]>2022-06-07 03:29:00 +0200
commit3e4bead32161604c08e2dcae1acea695db851f34 (patch)
tree41b0334cad6fef5a54e28789ec0320f21000b2ac /examples/stm32f3/src
parent0aa73f58e2f71f4578ff23f79f3b1a2c9d6d9098 (diff)
stm32: add USB driver.
Diffstat (limited to 'examples/stm32f3/src')
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs116
1 files changed, 116 insertions, 0 deletions
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
new file mode 100644
index 000000000..fc33d0bc7
--- /dev/null
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -0,0 +1,116 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::panic;
6use defmt::*;
7use defmt_rtt as _; // global logger
8use embassy::executor::Spawner;
9use embassy::time::Duration;
10use embassy::time::Timer;
11use embassy_stm32::gpio::Level;
12use embassy_stm32::gpio::Output;
13use embassy_stm32::gpio::Speed;
14use embassy_stm32::interrupt;
15use embassy_stm32::time::U32Ext;
16use embassy_stm32::usb::{Driver, Instance};
17use embassy_stm32::{Config, Peripherals};
18use embassy_usb::driver::EndpointError;
19use embassy_usb::Builder;
20use embassy_usb_serial::{CdcAcmClass, State};
21use futures::future::join;
22use panic_probe as _;
23
24fn config() -> Config {
25 let mut config = Config::default();
26
27 config.rcc.hse = Some(8.mhz().into());
28 config.rcc.sysclk = Some(48.mhz().into());
29 config.rcc.pclk1 = Some(24.mhz().into());
30 config.rcc.pclk2 = Some(24.mhz().into());
31 config.rcc.pll48 = true;
32
33 config
34}
35
36#[embassy::main(config = "config()")]
37async fn main(_spawner: Spawner, p: Peripherals) {
38 info!("Hello World!");
39
40 // Needed for nucleo-stm32f303ze
41 let mut dp_pullup = Output::new(p.PG6, Level::Low, Speed::Medium);
42 Timer::after(Duration::from_millis(10)).await;
43 dp_pullup.set_high();
44
45 // Create the driver, from the HAL.
46 let irq = interrupt::take!(USB_LP_CAN_RX0);
47 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
48
49 // Create embassy-usb Config
50 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
51
52 // Create embassy-usb DeviceBuilder using the driver and config.
53 // It needs some buffers for building the descriptors.
54 let mut device_descriptor = [0; 256];
55 let mut config_descriptor = [0; 256];
56 let mut bos_descriptor = [0; 256];
57 let mut control_buf = [0; 7];
58
59 let mut state = State::new();
60
61 let mut builder = Builder::new(
62 driver,
63 config,
64 &mut device_descriptor,
65 &mut config_descriptor,
66 &mut bos_descriptor,
67 &mut control_buf,
68 None,
69 );
70
71 // Create classes on the builder.
72 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
73
74 // Build the builder.
75 let mut usb = builder.build();
76
77 // Run the USB device.
78 let usb_fut = usb.run();
79
80 // Do stuff with the class!
81 let echo_fut = async {
82 loop {
83 class.wait_connection().await;
84 info!("Connected");
85 let _ = echo(&mut class).await;
86 info!("Disconnected");
87 }
88 };
89
90 // Run everything concurrently.
91 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
92 join(usb_fut, echo_fut).await;
93}
94
95struct Disconnected {}
96
97impl From<EndpointError> for Disconnected {
98 fn from(val: EndpointError) -> Self {
99 match val {
100 EndpointError::BufferOverflow => panic!("Buffer overflow"),
101 EndpointError::Disabled => Disconnected {},
102 }
103 }
104}
105
106async fn echo<'d, T: Instance + 'd>(
107 class: &mut CdcAcmClass<'d, Driver<'d, T>>,
108) -> Result<(), Disconnected> {
109 let mut buf = [0; 64];
110 loop {
111 let n = class.read_packet(&mut buf).await?;
112 let data = &buf[..n];
113 info!("data: {:x}", data);
114 class.write_packet(data).await?;
115 }
116}