aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f4/src
diff options
context:
space:
mode:
authorElias Hanelt <[email protected]>2025-11-25 13:18:00 -0800
committerElias Hanelt <[email protected]>2025-11-25 13:18:00 -0800
commit2b219b7cb59ec3e4370edc88538ea3ea996f37b9 (patch)
treec602a4b7c39d50ada628f2d715c6cc59f2e35c3a /examples/stm32f4/src
parent576fb23faabf6df7f2c9ed2039e94d3586a3788f (diff)
parent906eaee53f84381dd10583894edf2de67275f083 (diff)
Merge remote-tracking branch 'origin/main' into feature/spi-bidi
Diffstat (limited to 'examples/stm32f4/src')
-rw-r--r--examples/stm32f4/src/bin/adc.rs2
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs8
-rw-r--r--examples/stm32f4/src/bin/button_exti.rs10
-rw-r--r--examples/stm32f4/src/bin/eth.rs12
-rw-r--r--examples/stm32f4/src/bin/eth_compliance_test.rs12
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs7
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs91
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs56
8 files changed, 139 insertions, 59 deletions
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 5628cb827..694e85657 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let mut delay = Delay; 16 let mut delay = Delay;
17 let mut adc = Adc::new(p.ADC1); 17 let mut adc = Adc::new_with_config(p.ADC1, Default::default());
18 let mut pin = p.PC1; 18 let mut pin = p.PC1;
19 19
20 let mut vrefint = adc.enable_vrefint(); 20 let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs
index 01b881c79..d61b1b2eb 100644
--- a/examples/stm32f4/src/bin/adc_dma.rs
+++ b/examples/stm32f4/src/bin/adc_dma.rs
@@ -4,7 +4,7 @@ use cortex_m::singleton;
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::Peripherals; 6use embassy_stm32::Peripherals;
7use embassy_stm32::adc::{Adc, AdcChannel, RingBufferedAdc, SampleTime}; 7use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, RingBufferedAdc, SampleTime};
8use embassy_time::Instant; 8use embassy_time::Instant;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -20,8 +20,8 @@ async fn adc_task(p: Peripherals) {
20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); 20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); 21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
22 22
23 let adc = Adc::new(p.ADC1); 23 let adc = Adc::new_with_config(p.ADC1, Default::default());
24 let adc2 = Adc::new(p.ADC2); 24 let adc2 = Adc::new_with_config(p.ADC2, Default::default());
25 25
26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered( 26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
27 p.DMA2_CH0, 27 p.DMA2_CH0,
@@ -31,6 +31,7 @@ async fn adc_task(p: Peripherals) {
31 (p.PA2.degrade_adc(), SampleTime::CYCLES112), 31 (p.PA2.degrade_adc(), SampleTime::CYCLES112),
32 ] 32 ]
33 .into_iter(), 33 .into_iter(),
34 RegularConversionMode::Continuous,
34 ); 35 );
35 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered( 36 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(
36 p.DMA2_CH2, 37 p.DMA2_CH2,
@@ -40,6 +41,7 @@ async fn adc_task(p: Peripherals) {
40 (p.PA3.degrade_adc(), SampleTime::CYCLES112), 41 (p.PA3.degrade_adc(), SampleTime::CYCLES112),
41 ] 42 ]
42 .into_iter(), 43 .into_iter(),
44 RegularConversionMode::Continuous,
43 ); 45 );
44 46
45 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around 47 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around
diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs
index 2a546dac5..e7e1549a8 100644
--- a/examples/stm32f4/src/bin/button_exti.rs
+++ b/examples/stm32f4/src/bin/button_exti.rs
@@ -3,16 +3,22 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 6use embassy_stm32::exti::{self, ExtiInput};
7use embassy_stm32::gpio::Pull; 7use embassy_stm32::gpio::Pull;
8use embassy_stm32::{bind_interrupts, interrupt};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
11bind_interrupts!(
12 pub struct Irqs{
13 EXTI15_10 => exti::InterruptHandler<interrupt::typelevel::EXTI15_10>;
14});
15
10#[embassy_executor::main] 16#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 19 info!("Hello World!");
14 20
15 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); 21 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down, Irqs);
16 22
17 info!("Press the USER button..."); 23 info!("Press the USER button...");
18 24
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 2d72b6b0b..8dfa0916d 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -5,8 +5,8 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket; 6use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; 8use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, Sma};
9use embassy_stm32::peripherals::ETH; 9use embassy_stm32::peripherals::{ETH, ETH_SMA};
10use embassy_stm32::rng::Rng; 10use embassy_stm32::rng::Rng;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; 12use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng};
@@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs {
20 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 20 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
21}); 21});
22 22
23type Device = Ethernet<'static, ETH, GenericPhy>; 23type Device = Ethernet<'static, ETH, GenericPhy<Sma<'static, ETH_SMA>>>;
24 24
25#[embassy_executor::task] 25#[embassy_executor::task]
26async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { 26async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
@@ -67,16 +67,16 @@ async fn main(spawner: Spawner) -> ! {
67 p.ETH, 67 p.ETH,
68 Irqs, 68 Irqs,
69 p.PA1, 69 p.PA1,
70 p.PA2,
71 p.PC1,
72 p.PA7, 70 p.PA7,
73 p.PC4, 71 p.PC4,
74 p.PC5, 72 p.PC5,
75 p.PG13, 73 p.PG13,
76 p.PB13, 74 p.PB13,
77 p.PG11, 75 p.PG11,
78 GenericPhy::new_auto(),
79 mac_addr, 76 mac_addr,
77 p.ETH_SMA,
78 p.PA2,
79 p.PC1,
80 ); 80 );
81 81
82 let config = embassy_net::Config::dhcpv4(Default::default()); 82 let config = embassy_net::Config::dhcpv4(Default::default());
diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs
index 734a14c2c..dc5d7dbb6 100644
--- a/examples/stm32f4/src/bin/eth_compliance_test.rs
+++ b/examples/stm32f4/src/bin/eth_compliance_test.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, StationManagement}; 6use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement};
7use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
8use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; 8use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng};
9use embassy_time::Timer; 9use embassy_time::Timer;
@@ -43,27 +43,27 @@ async fn main(_spawner: Spawner) -> ! {
43 43
44 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 44 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
45 45
46 const PHY_ADDR: u8 = 0;
47 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); 46 static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new();
48 let mut device = Ethernet::new( 47 let mut device = Ethernet::new(
49 PACKETS.init(PacketQueue::<4, 4>::new()), 48 PACKETS.init(PacketQueue::<4, 4>::new()),
50 p.ETH, 49 p.ETH,
51 Irqs, 50 Irqs,
52 p.PA1, 51 p.PA1,
53 p.PA2,
54 p.PC1,
55 p.PA7, 52 p.PA7,
56 p.PC4, 53 p.PC4,
57 p.PC5, 54 p.PC5,
58 p.PG13, 55 p.PG13,
59 p.PB13, 56 p.PB13,
60 p.PG11, 57 p.PG11,
61 GenericPhy::new(PHY_ADDR),
62 mac_addr, 58 mac_addr,
59 p.ETH_SMA,
60 p.PA2,
61 p.PC1,
63 ); 62 );
64 63
65 let sm = device.station_management(); 64 let sm = device.phy_mut().station_management();
66 65
66 const PHY_ADDR: u8 = 0;
67 // Just an example. Exact register settings depend on the specific PHY and test. 67 // Just an example. Exact register settings depend on the specific PHY and test.
68 sm.smi_write(PHY_ADDR, 0, 0x2100); 68 sm.smi_write(PHY_ADDR, 0, 0x2100);
69 sm.smi_write(PHY_ADDR, 11, 0xA000); 69 sm.smi_write(PHY_ADDR, 11, 0xA000);
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index 0adcda614..e274d2a66 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -7,14 +7,14 @@ use embassy_net::tcp::TcpSocket;
7use embassy_net::{Ipv4Address, StackResources}; 7use embassy_net::{Ipv4Address, StackResources};
8use embassy_net_wiznet::chip::W5500; 8use embassy_net_wiznet::chip::W5500;
9use embassy_net_wiznet::{Device, Runner, State}; 9use embassy_net_wiznet::{Device, Runner, State};
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::{self, ExtiInput};
11use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 11use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_stm32::mode::Async; 12use embassy_stm32::mode::Async;
13use embassy_stm32::rng::Rng; 13use embassy_stm32::rng::Rng;
14use embassy_stm32::spi::Spi; 14use embassy_stm32::spi::Spi;
15use embassy_stm32::spi::mode::Master; 15use embassy_stm32::spi::mode::Master;
16use embassy_stm32::time::Hertz; 16use embassy_stm32::time::Hertz;
17use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; 17use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, rng, spi};
18use embassy_time::{Delay, Timer}; 18use embassy_time::{Delay, Timer};
19use embedded_hal_bus::spi::ExclusiveDevice; 19use embedded_hal_bus::spi::ExclusiveDevice;
20use embedded_io_async::Write; 20use embedded_io_async::Write;
@@ -23,6 +23,7 @@ use {defmt_rtt as _, panic_probe as _};
23 23
24bind_interrupts!(struct Irqs { 24bind_interrupts!(struct Irqs {
25 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 25 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
26 EXTI0 => exti::InterruptHandler<interrupt::typelevel::EXTI0>;
26}); 27});
27 28
28type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>; 29type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>;
@@ -75,7 +76,7 @@ async fn main(spawner: Spawner) -> ! {
75 let cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); 76 let cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
76 let spi = unwrap!(ExclusiveDevice::new(spi, cs, Delay)); 77 let spi = unwrap!(ExclusiveDevice::new(spi, cs, Delay));
77 78
78 let w5500_int = ExtiInput::new(p.PB0, p.EXTI0, Pull::Up); 79 let w5500_int = ExtiInput::new(p.PB0, p.EXTI0, Pull::Up, Irqs);
79 let w5500_reset = Output::new(p.PB1, Level::High, Speed::VeryHigh); 80 let w5500_reset = Output::new(p.PB1, Level::High, Speed::VeryHigh);
80 81
81 let mac_addr = [0x02, 234, 3, 4, 82, 231]; 82 let mac_addr = [0x02, 234, 3, 4, 82, 231];
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index a3afb887c..2d834dcf7 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -1,17 +1,19 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::{self, ExtiInput};
10use embassy_stm32::gpio::Pull; 10use embassy_stm32::gpio::Pull;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::usb::Driver; 12use embassy_stm32::usb::Driver;
13use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 13use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, usb};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
16};
15use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Handler}; 18use embassy_usb::{Builder, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -19,8 +21,11 @@ use {defmt_rtt as _, panic_probe as _};
19 21
20bind_interrupts!(struct Irqs { 22bind_interrupts!(struct Irqs {
21 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 23 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
24 EXTI15_10 => exti::InterruptHandler<interrupt::typelevel::EXTI15_10>;
22}); 25});
23 26
27static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
28
24// If you are trying this and your USB device doesn't connect, the most 29// If you are trying this and your USB device doesn't connect, the most
25// common issues are the RCC config and vbus_detection 30// common issues are the RCC config and vbus_detection
26// 31//
@@ -70,6 +75,10 @@ async fn main(_spawner: Spawner) {
70 config.serial_number = Some("12345678"); 75 config.serial_number = Some("12345678");
71 config.max_power = 100; 76 config.max_power = 100;
72 config.max_packet_size_0 = 64; 77 config.max_packet_size_0 = 64;
78 config.composite_with_iads = false;
79 config.device_class = 0;
80 config.device_sub_class = 0;
81 config.device_protocol = 0;
73 82
74 // Create embassy-usb DeviceBuilder using the driver and config. 83 // Create embassy-usb DeviceBuilder using the driver and config.
75 // It needs some buffers for building the descriptors. 84 // It needs some buffers for building the descriptors.
@@ -101,6 +110,8 @@ async fn main(_spawner: Spawner) {
101 request_handler: None, 110 request_handler: None,
102 poll_ms: 60, 111 poll_ms: 60,
103 max_packet_size: 8, 112 max_packet_size: 8,
113 hid_subclass: HidSubclass::Boot,
114 hid_boot_protocol: HidBootProtocol::Keyboard,
104 }; 115 };
105 116
106 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 117 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
@@ -113,7 +124,7 @@ async fn main(_spawner: Spawner) {
113 124
114 let (reader, mut writer) = hid.split(); 125 let (reader, mut writer) = hid.split();
115 126
116 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down); 127 let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Down, Irqs);
117 128
118 // Do stuff with the class! 129 // Do stuff with the class!
119 let in_fut = async { 130 let in_fut = async {
@@ -121,32 +132,46 @@ async fn main(_spawner: Spawner) {
121 button.wait_for_rising_edge().await; 132 button.wait_for_rising_edge().await;
122 // signal_pin.wait_for_high().await; 133 // signal_pin.wait_for_high().await;
123 info!("Button pressed!"); 134 info!("Button pressed!");
124 // Create a report with the A key pressed. (no shift modifier) 135 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
125 let report = KeyboardReport { 136 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
126 keycodes: [4, 0, 0, 0, 0, 0], 137 Ok(()) => {}
127 leds: 0, 138 Err(e) => warn!("Failed to send boot report: {:?}", e),
128 modifier: 0, 139 };
129 reserved: 0, 140 } else {
130 }; 141 // Create a report with the A key pressed. (no shift modifier)
131 // Send the report. 142 let report = KeyboardReport {
132 match writer.write_serialize(&report).await { 143 keycodes: [4, 0, 0, 0, 0, 0],
133 Ok(()) => {} 144 leds: 0,
134 Err(e) => warn!("Failed to send report: {:?}", e), 145 modifier: 0,
135 }; 146 reserved: 0,
147 };
148 // Send the report.
149 match writer.write_serialize(&report).await {
150 Ok(()) => {}
151 Err(e) => warn!("Failed to send report: {:?}", e),
152 };
153 }
136 154
137 button.wait_for_falling_edge().await; 155 button.wait_for_falling_edge().await;
138 // signal_pin.wait_for_low().await; 156 // signal_pin.wait_for_low().await;
139 info!("Button released!"); 157 info!("Button released!");
140 let report = KeyboardReport { 158 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
141 keycodes: [0, 0, 0, 0, 0, 0], 159 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
142 leds: 0, 160 Ok(()) => {}
143 modifier: 0, 161 Err(e) => warn!("Failed to send boot report: {:?}", e),
144 reserved: 0, 162 };
145 }; 163 } else {
146 match writer.write_serialize(&report).await { 164 let report = KeyboardReport {
147 Ok(()) => {} 165 keycodes: [0, 0, 0, 0, 0, 0],
148 Err(e) => warn!("Failed to send report: {:?}", e), 166 leds: 0,
149 }; 167 modifier: 0,
168 reserved: 0,
169 };
170 match writer.write_serialize(&report).await {
171 Ok(()) => {}
172 Err(e) => warn!("Failed to send report: {:?}", e),
173 };
174 }
150 } 175 }
151 }; 176 };
152 177
@@ -172,6 +197,18 @@ impl RequestHandler for MyRequestHandler {
172 OutResponse::Accepted 197 OutResponse::Accepted
173 } 198 }
174 199
200 fn get_protocol(&self) -> HidProtocolMode {
201 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
202 info!("The current HID protocol mode is: {}", protocol);
203 protocol
204 }
205
206 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
207 info!("Switching to HID protocol mode: {}", protocol);
208 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
209 OutResponse::Accepted
210 }
211
175 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 212 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
176 info!("Set idle rate for {:?} to {:?}", id, dur); 213 info!("Set idle rate for {:?} to {:?}", id, dur);
177 } 214 }
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index 162a035f2..e83d01f88 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -9,7 +11,9 @@ use embassy_stm32::usb::Driver;
9use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 11use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use embassy_usb::Builder; 13use embassy_usb::Builder;
12use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
16};
13use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
15use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
@@ -18,6 +22,8 @@ bind_interrupts!(struct Irqs {
18 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 22 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
19}); 23});
20 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
21// If you are trying this and your USB device doesn't connect, the most 27// If you are trying this and your USB device doesn't connect, the most
22// common issues are the RCC config and vbus_detection 28// common issues are the RCC config and vbus_detection
23// 29//
@@ -65,6 +71,10 @@ async fn main(_spawner: Spawner) {
65 config.manufacturer = Some("Embassy"); 71 config.manufacturer = Some("Embassy");
66 config.product = Some("HID mouse example"); 72 config.product = Some("HID mouse example");
67 config.serial_number = Some("12345678"); 73 config.serial_number = Some("12345678");
74 config.composite_with_iads = false;
75 config.device_class = 0;
76 config.device_sub_class = 0;
77 config.device_protocol = 0;
68 78
69 // Create embassy-usb DeviceBuilder using the driver and config. 79 // Create embassy-usb DeviceBuilder using the driver and config.
70 // It needs some buffers for building the descriptors. 80 // It needs some buffers for building the descriptors.
@@ -91,6 +101,8 @@ async fn main(_spawner: Spawner) {
91 request_handler: Some(&mut request_handler), 101 request_handler: Some(&mut request_handler),
92 poll_ms: 60, 102 poll_ms: 60,
93 max_packet_size: 8, 103 max_packet_size: 8,
104 hid_subclass: HidSubclass::Boot,
105 hid_boot_protocol: HidBootProtocol::Mouse,
94 }; 106 };
95 107
96 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 108 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -108,16 +120,26 @@ async fn main(_spawner: Spawner) {
108 Timer::after_millis(500).await; 120 Timer::after_millis(500).await;
109 121
110 y = -y; 122 y = -y;
111 let report = MouseReport { 123
112 buttons: 0, 124 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
113 x: 0, 125 let buttons = 0u8;
114 y, 126 let x = 0i8;
115 wheel: 0, 127 match writer.write(&[buttons, x as u8, y as u8]).await {
116 pan: 0, 128 Ok(()) => {}
117 }; 129 Err(e) => warn!("Failed to send boot report: {:?}", e),
118 match writer.write_serialize(&report).await { 130 }
119 Ok(()) => {} 131 } else {
120 Err(e) => warn!("Failed to send report: {:?}", e), 132 let report = MouseReport {
133 buttons: 0,
134 x: 0,
135 y,
136 wheel: 0,
137 pan: 0,
138 };
139 match writer.write_serialize(&report).await {
140 Ok(()) => {}
141 Err(e) => warn!("Failed to send report: {:?}", e),
142 }
121 } 143 }
122 } 144 }
123 }; 145 };
@@ -140,6 +162,18 @@ impl RequestHandler for MyRequestHandler {
140 OutResponse::Accepted 162 OutResponse::Accepted
141 } 163 }
142 164
165 fn get_protocol(&self) -> HidProtocolMode {
166 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
167 info!("The current HID protocol mode is: {}", protocol);
168 protocol
169 }
170
171 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
172 info!("Switching to HID protocol mode: {}", protocol);
173 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
174 OutResponse::Accepted
175 }
176
143 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 177 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
144 info!("Set idle rate for {:?} to {:?}", id, dur); 178 info!("Set idle rate for {:?} to {:?}", id, dur);
145 } 179 }