aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorVo Trung Chi <[email protected]>2024-03-07 00:45:01 +0700
committerVo Trung Chi <[email protected]>2024-03-07 00:46:27 +0700
commit315fb040ee15306158d1c7c24249ee08cd22e36a (patch)
tree62e42516f7e1a4d6fbc13f8ae1f78f0fe6dfecd9 /examples
parent3638df789e4f498b9058bbeb27bdddab4a80bd49 (diff)
stm32: add usb_hid_mouse example
Signed-off-by: Vo Trung Chi <[email protected]>
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32f4/Cargo.toml1
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs148
2 files changed, 149 insertions, 0 deletions
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index cd46fc85b..512158bef 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -27,6 +27,7 @@ heapless = { version = "0.8", default-features = false }
27nb = "1.0.0" 27nb = "1.0.0"
28embedded-storage = "0.3.1" 28embedded-storage = "0.3.1"
29micromath = "2.0.0" 29micromath = "2.0.0"
30usbd-hid = "0.7.0"
30static_cell = "2" 31static_cell = "2"
31chrono = { version = "^0.4", default-features = false} 32chrono = { version = "^0.4", default-features = false}
32 33
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..add1ef306
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,148 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
7use embassy_stm32::usb_otg::Driver;
8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
9use embassy_time::Timer;
10use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
11use embassy_usb::control::OutResponse;
12use embassy_usb::Builder;
13use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = Config::default();
24 {
25 use embassy_stm32::rcc::*;
26 config.rcc.hse = Some(Hse {
27 freq: Hertz(8_000_000),
28 mode: HseMode::Bypass,
29 });
30 config.rcc.pll_src = PllSource::HSE;
31 config.rcc.pll = Some(Pll {
32 prediv: PllPreDiv::DIV4,
33 mul: PllMul::MUL168,
34 divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
35 divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
36 divr: None,
37 });
38 config.rcc.ahb_pre = AHBPrescaler::DIV1;
39 config.rcc.apb1_pre = APBPrescaler::DIV4;
40 config.rcc.apb2_pre = APBPrescaler::DIV2;
41 config.rcc.sys = Sysclk::PLL1_P;
42 }
43 let p = embassy_stm32::init(config);
44
45 // Create the driver, from the HAL.
46 let mut ep_out_buffer = [0u8; 256];
47 let mut config = embassy_stm32::usb_otg::Config::default();
48 config.vbus_detection = true;
49 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
50
51 // Create embassy-usb Config
52 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
53 config.manufacturer = Some("Embassy");
54 config.product = Some("HID mouse example");
55 config.serial_number = Some("12345678");
56
57 // Required for windows compatibility.
58 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
59 config.device_class = 0xEF;
60 config.device_sub_class = 0x02;
61 config.device_protocol = 0x01;
62 config.composite_with_iads = true;
63
64 // Create embassy-usb DeviceBuilder using the driver and config.
65 // It needs some buffers for building the descriptors.
66 let mut device_descriptor = [0; 256];
67 let mut config_descriptor = [0; 256];
68 let mut bos_descriptor = [0; 256];
69 let mut control_buf = [0; 64];
70
71 let request_handler = MyRequestHandler {};
72
73 let mut state = State::new();
74
75 let mut builder = Builder::new(
76 driver,
77 config,
78 &mut device_descriptor,
79 &mut config_descriptor,
80 &mut bos_descriptor,
81 &mut [], // no msos descriptors
82 &mut control_buf,
83 );
84
85 // Create classes on the builder.
86 let config = embassy_usb::class::hid::Config {
87 report_descriptor: MouseReport::desc(),
88 request_handler: Some(&request_handler),
89 poll_ms: 60,
90 max_packet_size: 8,
91 };
92
93 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
94
95 // Build the builder.
96 let mut usb = builder.build();
97
98 // Run the USB device.
99 let usb_fut = usb.run();
100
101 // Do stuff with the class!
102 let hid_fut = async {
103 let mut y: i8 = 5;
104 loop {
105 Timer::after_millis(500).await;
106
107 y = -y;
108 let report = MouseReport {
109 buttons: 0,
110 x: 0,
111 y,
112 wheel: 0,
113 pan: 0,
114 };
115 match writer.write_serialize(&report).await {
116 Ok(()) => {}
117 Err(e) => warn!("Failed to send report: {:?}", e),
118 }
119 }
120 };
121
122// Run everything concurrently.
123// If we had made everything `'static` above instead, we could do this using separate tasks instead.
124join(usb_fut, hid_fut).await;
125}
126
127struct MyRequestHandler {}
128
129impl RequestHandler for MyRequestHandler {
130fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
131 info!("Get report for {:?}", id);
132 None
133}
134
135fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
136 info!("Set report for {:?}: {=[u8]}", id, data);
137 OutResponse::Accepted
138}
139
140fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
141 info!("Set idle rate for {:?} to {:?}", id, dur);
142}
143
144fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
145 info!("Get idle rate for {:?}", id);
146 None
147}
148}