aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f4/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'examples/stm32f4/src/bin')
-rw-r--r--examples/stm32f4/src/bin/adc.rs12
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs35
-rw-r--r--examples/stm32f4/src/bin/button_exti.rs10
-rw-r--r--examples/stm32f4/src/bin/eth.rs14
-rw-r--r--examples/stm32f4/src/bin/eth_compliance_test.rs14
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs10
-rw-r--r--examples/stm32f4/src/bin/flash_async.rs2
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_async.rs135
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_blocking.rs132
-rw-r--r--examples/stm32f4/src/bin/input_capture.rs2
-rw-r--r--examples/stm32f4/src/bin/mco.rs18
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs4
-rw-r--r--examples/stm32f4/src/bin/pwm_complementary.rs4
-rw-r--r--examples/stm32f4/src/bin/pwm_input.rs2
-rw-r--r--examples/stm32f4/src/bin/rtc.rs6
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs42
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs91
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs60
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_uac_speaker.rs4
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs4
23 files changed, 488 insertions, 123 deletions
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 423d29225..694e85657 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -4,7 +4,7 @@
4use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; 4use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs;
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, Temperature, VrefInt}; 7use embassy_stm32::adc::{Adc, SampleTime, Temperature, VrefInt};
8use embassy_time::{Delay, Timer}; 8use embassy_time::{Delay, Timer};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -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();
@@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
23 // Startup delay can be combined to the maximum of either 23 // Startup delay can be combined to the maximum of either
24 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); 24 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
25 25
26 let vrefint_sample = adc.blocking_read(&mut vrefint); 26 let vrefint_sample = adc.blocking_read(&mut vrefint, SampleTime::CYCLES112);
27 27
28 let convert_to_millivolts = |sample| { 28 let convert_to_millivolts = |sample| {
29 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf 29 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
@@ -50,16 +50,16 @@ async fn main(_spawner: Spawner) {
50 50
51 loop { 51 loop {
52 // Read pin 52 // Read pin
53 let v = adc.blocking_read(&mut pin); 53 let v = adc.blocking_read(&mut pin, SampleTime::CYCLES112);
54 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); 54 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
55 55
56 // Read internal temperature 56 // Read internal temperature
57 let v = adc.blocking_read(&mut temp); 57 let v = adc.blocking_read(&mut temp, SampleTime::CYCLES112);
58 let celcius = convert_to_celcius(v); 58 let celcius = convert_to_celcius(v);
59 info!("Internal temp: {} ({} C)", v, celcius); 59 info!("Internal temp: {} ({} C)", v, celcius);
60 60
61 // Read internal voltage reference 61 // Read internal voltage reference
62 let v = adc.blocking_read(&mut vrefint); 62 let v = adc.blocking_read(&mut vrefint, SampleTime::CYCLES112);
63 info!("VrefInt: {}", v); 63 info!("VrefInt: {}", v);
64 64
65 Timer::after_millis(100).await; 65 Timer::after_millis(100).await;
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs
index 2ec48640e..d61b1b2eb 100644
--- a/examples/stm32f4/src/bin/adc_dma.rs
+++ b/examples/stm32f4/src/bin/adc_dma.rs
@@ -3,8 +3,8 @@
3use cortex_m::singleton; 3use cortex_m::singleton;
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence};
7use embassy_stm32::Peripherals; 6use embassy_stm32::Peripherals;
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
@@ -15,21 +15,34 @@ async fn main(spawner: Spawner) {
15} 15}
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn adc_task(mut p: Peripherals) { 18async fn adc_task(p: Peripherals) {
19 const ADC_BUF_SIZE: usize = 1024; 19 const ADC_BUF_SIZE: usize = 1024;
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(p.DMA2_CH0, adc_data); 26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
27 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2); 27 p.DMA2_CH0,
28 28 adc_data,
29 adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); 29 [
30 adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112); 30 (p.PA0.degrade_adc(), SampleTime::CYCLES112),
31 adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112); 31 (p.PA2.degrade_adc(), SampleTime::CYCLES112),
32 adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112); 32 ]
33 .into_iter(),
34 RegularConversionMode::Continuous,
35 );
36 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(
37 p.DMA2_CH2,
38 adc_data2,
39 [
40 (p.PA1.degrade_adc(), SampleTime::CYCLES112),
41 (p.PA3.degrade_adc(), SampleTime::CYCLES112),
42 ]
43 .into_iter(),
44 RegularConversionMode::Continuous,
45 );
33 46
34 // 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
35 // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of 48 // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of
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 f41a60529..8dfa0916d 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -5,11 +5,11 @@ 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::{bind_interrupts, eth, peripherals, rng, Config}; 12use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng};
13use embassy_time::Timer; 13use embassy_time::Timer;
14use embedded_io_async::Write; 14use embedded_io_async::Write;
15use static_cell::StaticCell; 15use static_cell::StaticCell;
@@ -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 52f9d57f6..dc5d7dbb6 100644
--- a/examples/stm32f4/src/bin/eth_compliance_test.rs
+++ b/examples/stm32f4/src/bin/eth_compliance_test.rs
@@ -3,9 +3,9 @@
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::{bind_interrupts, eth, peripherals, rng, Config}; 8use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng};
9use embassy_time::Timer; 9use embassy_time::Timer;
10use static_cell::StaticCell; 10use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -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 7ce3bfe75..e274d2a66 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -7,13 +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::time::Hertz; 16use embassy_stm32::time::Hertz;
16use embassy_stm32::{bind_interrupts, peripherals, rng, spi, Config}; 17use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, rng, spi};
17use embassy_time::{Delay, Timer}; 18use embassy_time::{Delay, Timer};
18use embedded_hal_bus::spi::ExclusiveDevice; 19use embedded_hal_bus::spi::ExclusiveDevice;
19use embedded_io_async::Write; 20use embedded_io_async::Write;
@@ -22,9 +23,10 @@ use {defmt_rtt as _, panic_probe as _};
22 23
23bind_interrupts!(struct Irqs { 24bind_interrupts!(struct Irqs {
24 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 25 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
26 EXTI0 => exti::InterruptHandler<interrupt::typelevel::EXTI0>;
25}); 27});
26 28
27type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>; 29type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>;
28#[embassy_executor::task] 30#[embassy_executor::task]
29async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { 31async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! {
30 runner.run().await 32 runner.run().await
@@ -74,7 +76,7 @@ async fn main(spawner: Spawner) -> ! {
74 let cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); 76 let cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
75 let spi = unwrap!(ExclusiveDevice::new(spi, cs, Delay)); 77 let spi = unwrap!(ExclusiveDevice::new(spi, cs, Delay));
76 78
77 let w5500_int = ExtiInput::new(p.PB0, p.EXTI0, Pull::Up); 79 let w5500_int = ExtiInput::new(p.PB0, p.EXTI0, Pull::Up, Irqs);
78 let w5500_reset = Output::new(p.PB1, Level::High, Speed::VeryHigh); 80 let w5500_reset = Output::new(p.PB1, Level::High, Speed::VeryHigh);
79 81
80 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/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
index 2feb9de09..14f029747 100644
--- a/examples/stm32f4/src/bin/flash_async.rs
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -5,7 +5,7 @@ use defmt::{info, unwrap};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::flash::{Flash, InterruptHandler}; 6use embassy_stm32::flash::{Flash, InterruptHandler};
7use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; 7use embassy_stm32::gpio::{AnyPin, Level, Output, Speed};
8use embassy_stm32::{bind_interrupts, Peri}; 8use embassy_stm32::{Peri, bind_interrupts};
9use embassy_time::Timer; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs
new file mode 100644
index 000000000..5065bcdd8
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_slave_async.rs
@@ -0,0 +1,135 @@
1//! I2C slave example using async operations with DMA
2//!
3//! This example demonstrates DMA-accelerated I2C slave operations,
4//! which provide better performance and lower CPU overhead for
5//! high-frequency I2C transactions.
6
7#![no_std]
8#![no_main]
9
10use defmt::{error, info};
11use embassy_executor::Spawner;
12use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind};
13use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, peripherals};
15use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
16use embassy_sync::mutex::Mutex;
17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _};
19
20pub const I2C_SLAVE_ADDR: u8 = 0x42;
21pub const BUFFER_SIZE: usize = 8;
22static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]);
23
24bind_interrupts!(struct Irqs {
25 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
26 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
27});
28
29#[embassy_executor::main]
30async fn main(spawner: Spawner) {
31 let p = embassy_stm32::init(Default::default());
32
33 // Configure I2C
34 let mut i2c_config = i2c::Config::default();
35 i2c_config.sda_pullup = false;
36 i2c_config.scl_pullup = false;
37 i2c_config.frequency = Hertz(100_000); // 100kHz I2C speed
38
39 // Initialize I2C as master first
40 let i2c_master = I2c::new(
41 p.I2C1, p.PB8, // SCL
42 p.PB9, // SDA
43 Irqs, p.DMA1_CH6, // TX DMA
44 p.DMA1_CH0, // RX DMA
45 i2c_config,
46 );
47
48 // Convert to MultiMaster mode
49 let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR);
50 let i2c_slave = i2c_master.into_slave_multimaster(slave_config);
51
52 spawner.spawn(i2c_slave_task(i2c_slave).unwrap());
53}
54
55#[embassy_executor::task]
56pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Async, i2c::mode::MultiMaster>) {
57 info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR);
58
59 loop {
60 match i2c_slave.listen().await {
61 Ok(SlaveCommand {
62 kind: SlaveCommandKind::Write,
63 address,
64 }) => {
65 let addr_val = match address {
66 Address::SevenBit(addr) => addr,
67 Address::TenBit(addr) => (addr & 0xFF) as u8,
68 };
69
70 info!("I2C: Received write command - Address 0x{:02X}", addr_val);
71
72 let mut data_buffer = I2C_BUFFER.lock().await;
73
74 match i2c_slave.respond_to_write(&mut *data_buffer).await {
75 Ok(_) => {
76 info!(
77 "I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}",
78 data_buffer[0],
79 data_buffer[1],
80 data_buffer[2],
81 data_buffer[3],
82 data_buffer[4],
83 data_buffer[5],
84 data_buffer[6],
85 data_buffer[7]
86 );
87 }
88 Err(e) => {
89 error!("I2C: Write error: {}", format_i2c_error(&e));
90 }
91 }
92 }
93
94 Ok(SlaveCommand {
95 kind: SlaveCommandKind::Read,
96 address,
97 }) => {
98 let addr_val = match address {
99 Address::SevenBit(addr) => addr,
100 Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit
101 };
102
103 info!("I2C: Received read command - Address 0x{:02X}", addr_val);
104
105 let data_buffer = I2C_BUFFER.lock().await;
106
107 match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await {
108 Ok(_) => {
109 info!("I2C: Responded to read command");
110 }
111 Err(e) => {
112 error!("I2C: Read error: {}", format_i2c_error(&e));
113 }
114 }
115 }
116
117 Err(e) => {
118 error!("I2C: Listen error: {}", format_i2c_error(&e));
119 Timer::after(Duration::from_millis(100)).await;
120 }
121 }
122 }
123}
124
125fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str {
126 match e {
127 embassy_stm32::i2c::Error::Bus => "Bus",
128 embassy_stm32::i2c::Error::Arbitration => "Arbitration",
129 embassy_stm32::i2c::Error::Nack => "Nack",
130 embassy_stm32::i2c::Error::Timeout => "Timeout",
131 embassy_stm32::i2c::Error::Crc => "Crc",
132 embassy_stm32::i2c::Error::Overrun => "Overrun",
133 embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer",
134 }
135}
diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs
new file mode 100644
index 000000000..ee06d4ac4
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs
@@ -0,0 +1,132 @@
1//! Complete I2C slave example using blocking operations
2//!
3//! This example shows how to set up an STM32F4 as an I2C slave device
4//! that can handle both read and write transactions from master devices.
5
6#![no_std]
7#![no_main]
8
9use defmt::{error, info};
10use embassy_executor::Spawner;
11use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind};
12use embassy_stm32::time::Hertz;
13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
15use embassy_sync::mutex::Mutex;
16use embassy_time::{Duration, Timer};
17use {defmt_rtt as _, panic_probe as _};
18
19pub const I2C_SLAVE_ADDR: u8 = 0x42;
20pub const BUFFER_SIZE: usize = 8;
21static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]);
22
23bind_interrupts!(struct Irqs {
24 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
25 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
26});
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 let p = embassy_stm32::init(Default::default());
31
32 // Configure I2C
33 let mut i2c_config = i2c::Config::default();
34 i2c_config.sda_pullup = false;
35 i2c_config.scl_pullup = false;
36 i2c_config.frequency = Hertz(100_000);
37 i2c_config.timeout = embassy_time::Duration::from_millis(30000);
38
39 // Initialize I2C as master first
40 let i2c_master = I2c::new_blocking(
41 p.I2C1, p.PB8, // SCL
42 p.PB9, // SDA
43 i2c_config,
44 );
45
46 // Convert to slave+master mode
47 let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR);
48 let i2c_slave = i2c_master.into_slave_multimaster(slave_config);
49
50 spawner.spawn(i2c_slave_task(i2c_slave).unwrap());
51}
52
53#[embassy_executor::task]
54pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) {
55 info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR);
56
57 loop {
58 match i2c_slave.blocking_listen() {
59 Ok(SlaveCommand {
60 kind: SlaveCommandKind::Write,
61 address,
62 }) => {
63 let addr_val = match address {
64 Address::SevenBit(addr) => addr,
65 Address::TenBit(addr) => (addr & 0xFF) as u8,
66 };
67
68 info!("I2C: Received write command - Address 0x{:02X}", addr_val);
69 let mut data_buffer = I2C_BUFFER.lock().await;
70
71 match i2c_slave.blocking_respond_to_write(&mut *data_buffer) {
72 Ok(bytes_received) => {
73 info!(
74 "I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}",
75 bytes_received,
76 data_buffer[0],
77 data_buffer[1],
78 data_buffer[2],
79 data_buffer[3],
80 data_buffer[4],
81 data_buffer[5],
82 data_buffer[6],
83 data_buffer[7]
84 );
85 }
86 Err(e) => {
87 error!("I2C: Write error: {}", format_i2c_error(&e));
88 }
89 }
90 }
91
92 Ok(SlaveCommand {
93 kind: SlaveCommandKind::Read,
94 address,
95 }) => {
96 let addr_val = match address {
97 Address::SevenBit(addr) => addr,
98 Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit
99 };
100
101 info!("I2C: Received read command - Address 0x{:02X}", addr_val);
102 let data_buffer = I2C_BUFFER.lock().await;
103
104 match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) {
105 Ok(bytes_sent) => {
106 info!("I2C: Responded to read - {} bytes sent", bytes_sent);
107 }
108 Err(e) => {
109 error!("I2C: Read error: {}", format_i2c_error(&e));
110 }
111 }
112 }
113
114 Err(e) => {
115 error!("I2C: Listen error: {}", format_i2c_error(&e));
116 Timer::after(Duration::from_millis(100)).await;
117 }
118 }
119 }
120}
121
122fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str {
123 match e {
124 embassy_stm32::i2c::Error::Bus => "Bus",
125 embassy_stm32::i2c::Error::Arbitration => "Arbitration",
126 embassy_stm32::i2c::Error::Nack => "Nack",
127 embassy_stm32::i2c::Error::Timeout => "Timeout",
128 embassy_stm32::i2c::Error::Crc => "Crc",
129 embassy_stm32::i2c::Error::Overrun => "Overrun",
130 embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer",
131 }
132}
diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs
index 9998c4733..3ff96584d 100644
--- a/examples/stm32f4/src/bin/input_capture.rs
+++ b/examples/stm32f4/src/bin/input_capture.rs
@@ -7,7 +7,7 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; 8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel}; 9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals, Peri}; 10use embassy_stm32::{Peri, bind_interrupts, peripherals};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs
index eb7bb6261..a2e229770 100644
--- a/examples/stm32f4/src/bin/mco.rs
+++ b/examples/stm32f4/src/bin/mco.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler}; 7use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoConfig, McoPrescaler};
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -13,8 +13,20 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV1); 16 let config_mco1 = {
17 let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, McoPrescaler::DIV4); 17 let mut config = McoConfig::default();
18 config.prescaler = McoPrescaler::DIV1;
19 config
20 };
21
22 let config_mco2 = {
23 let mut config = McoConfig::default();
24 config.prescaler = McoPrescaler::DIV4;
25 config
26 };
27
28 let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config_mco1);
29 let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, config_mco2);
18 let mut led = Output::new(p.PB7, Level::High, Speed::Low); 30 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
19 31
20 loop { 32 loop {
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 2f2ffdea2..8375e0e8e 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113 113
114#[interrupt] 114#[interrupt]
115unsafe fn UART4() { 115unsafe fn UART4() {
116 EXECUTOR_HIGH.on_interrupt() 116 unsafe { EXECUTOR_HIGH.on_interrupt() }
117} 117}
118 118
119#[interrupt] 119#[interrupt]
120unsafe fn UART5() { 120unsafe fn UART5() {
121 EXECUTOR_MED.on_interrupt() 121 unsafe { EXECUTOR_MED.on_interrupt() }
122} 122}
123 123
124#[entry] 124#[entry]
diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs
index c981f1a76..5e39a06f5 100644
--- a/examples/stm32f4/src/bin/pwm_complementary.rs
+++ b/examples/stm32f4/src/bin/pwm_complementary.rs
@@ -5,9 +5,9 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::OutputType; 6use embassy_stm32::gpio::OutputType;
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::Channel;
8use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; 9use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
9use embassy_stm32::timer::simple_pwm::PwmPin; 10use embassy_stm32::timer::simple_pwm::PwmPin;
10use embassy_stm32::timer::Channel;
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) {
33 ); 33 );
34 34
35 let max = pwm.get_max_duty(); 35 let max = pwm.get_max_duty();
36 pwm.set_dead_time(max / 1024); 36 pwm.set_dead_time((max / 1024) as u16);
37 37
38 pwm.enable(Channel::Ch1); 38 pwm.enable(Channel::Ch1);
39 39
diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs
index e8bfa524f..d8ea56a34 100644
--- a/examples/stm32f4/src/bin/pwm_input.rs
+++ b/examples/stm32f4/src/bin/pwm_input.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz; 7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput; 8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; 9use embassy_stm32::{Peri, bind_interrupts, peripherals, timer};
10use embassy_time::Timer; 10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
index 82d8a37ba..5ff705ca2 100644
--- a/examples/stm32f4/src/bin/rtc.rs
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -4,8 +4,8 @@
4use chrono::{NaiveDate, NaiveDateTime}; 4use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rtc::{Rtc, RtcConfig};
8use embassy_stm32::Config; 7use embassy_stm32::Config;
8use embassy_stm32::rtc::{Rtc, RtcConfig};
9use embassy_time::Timer; 9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -21,12 +21,12 @@ async fn main(_spawner: Spawner) {
21 .and_hms_opt(10, 30, 15) 21 .and_hms_opt(10, 30, 15)
22 .unwrap(); 22 .unwrap();
23 23
24 let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 24 let (mut rtc, time_provider) = Rtc::new(p.RTC, RtcConfig::default());
25 25
26 rtc.set_datetime(now.into()).expect("datetime not set"); 26 rtc.set_datetime(now.into()).expect("datetime not set");
27 27
28 loop { 28 loop {
29 let now: NaiveDateTime = rtc.now().unwrap().into(); 29 let now: NaiveDateTime = time_provider.now().unwrap().into();
30 30
31 info!("{}", now.and_utc().timestamp()); 31 info!("{}", now.and_utc().timestamp());
32 32
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index e97b63925..098fd6986 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -3,9 +3,10 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; 6use embassy_stm32::sdmmc::Sdmmc;
7use embassy_stm32::time::{mhz, Hertz}; 7use embassy_stm32::sdmmc::sd::{CmdBlock, DataBlock, StorageDevice};
8use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; 8use embassy_stm32::time::{Hertz, mhz};
9use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
11/// This is a safeguard to not overwrite any data on the SD card. 12/// This is a safeguard to not overwrite any data on the SD card.
@@ -57,31 +58,24 @@ async fn main(_spawner: Spawner) {
57 // Should print 400kHz for initialization 58 // Should print 400kHz for initialization
58 info!("Configured clock: {}", sdmmc.clock().0); 59 info!("Configured clock: {}", sdmmc.clock().0);
59 60
60 let mut err = None; 61 let mut cmd_block = CmdBlock::new();
61 loop { 62
62 match sdmmc.init_sd_card(mhz(24)).await { 63 let mut storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(24))
63 Ok(_) => break, 64 .await
64 Err(e) => { 65 .unwrap();
65 if err != Some(e) {
66 info!("waiting for card error, retrying: {:?}", e);
67 err = Some(e);
68 }
69 }
70 }
71 }
72 66
73 let card = unwrap!(sdmmc.card()); 67 let card = storage.card();
74 68
75 info!("Card: {:#?}", Debug2Format(card)); 69 info!("Card: {:#?}", Debug2Format(&card));
76 info!("Clock: {}", sdmmc.clock()); 70 info!("Clock: {}", storage.sdmmc.clock());
77 71
78 // Arbitrary block index 72 // Arbitrary block index
79 let block_idx = 16; 73 let block_idx = 16;
80 74
81 // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware. 75 // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware.
82 let mut block = DataBlock([0u8; 512]); 76 let mut block = DataBlock::new();
83 77
84 sdmmc.read_block(block_idx, &mut block).await.unwrap(); 78 storage.read_block(block_idx, &mut block).await.unwrap();
85 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); 79 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
86 80
87 if !ALLOW_WRITES { 81 if !ALLOW_WRITES {
@@ -91,17 +85,17 @@ async fn main(_spawner: Spawner) {
91 85
92 info!("Filling block with 0x55"); 86 info!("Filling block with 0x55");
93 block.fill(0x55); 87 block.fill(0x55);
94 sdmmc.write_block(block_idx, &block).await.unwrap(); 88 storage.write_block(block_idx, &block).await.unwrap();
95 info!("Write done"); 89 info!("Write done");
96 90
97 sdmmc.read_block(block_idx, &mut block).await.unwrap(); 91 storage.read_block(block_idx, &mut block).await.unwrap();
98 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); 92 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
99 93
100 info!("Filling block with 0xAA"); 94 info!("Filling block with 0xAA");
101 block.fill(0xAA); 95 block.fill(0xAA);
102 sdmmc.write_block(block_idx, &block).await.unwrap(); 96 storage.write_block(block_idx, &block).await.unwrap();
103 info!("Write done"); 97 info!("Write done");
104 98
105 sdmmc.read_block(block_idx, &mut block).await.unwrap(); 99 storage.read_block(block_idx, &mut block).await.unwrap();
106 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); 100 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
107} 101}
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 7abbe8719..a5e625edd 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -3,12 +3,12 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::tcp::TcpSocket;
7use embassy_net::StackResources; 6use embassy_net::StackResources;
7use embassy_net::tcp::TcpSocket;
8use embassy_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
9use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
10use embassy_stm32::usb::Driver; 10use embassy_stm32::usb::Driver;
11use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 11use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
14use embassy_usb::{Builder, UsbDevice}; 14use embassy_usb::{Builder, UsbDevice};
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index d6b4a9bc9..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::{bind_interrupts, peripherals, usb, Config}; 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 badb65e98..e83d01f88 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -1,16 +1,20 @@
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;
7use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::Driver; 10use embassy_stm32::usb::Driver;
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 11use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
12use embassy_usb::control::OutResponse;
13use embassy_usb::Builder; 13use embassy_usb::Builder;
14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
16};
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 _};
16 20
@@ -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 }
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index bbbcc082b..511f0b281 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -53,7 +53,7 @@ use defmt::*;
53use embassy_executor::Spawner; 53use embassy_executor::Spawner;
54use embassy_stm32::time::Hertz; 54use embassy_stm32::time::Hertz;
55use embassy_stm32::usb::Driver; 55use embassy_stm32::usb::Driver;
56use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 56use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
57use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; 57use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType};
58use embassy_usb::msos::{self, windows_version}; 58use embassy_usb::msos::{self, windows_version};
59use embassy_usb::types::InterfaceNumber; 59use embassy_usb::types::InterfaceNumber;
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index e62b2d8d6..2e81e0a59 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -6,10 +6,10 @@ use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
8use embassy_stm32::usb::{Driver, Instance}; 8use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 9use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
10use embassy_usb::Builder;
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs
index 79bd2d914..b92f4531e 100644
--- a/examples/stm32f4/src/bin/usb_uac_speaker.rs
+++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs
@@ -6,9 +6,9 @@ use core::cell::{Cell, RefCell};
6use defmt::{panic, *}; 6use defmt::{panic, *};
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; 9use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, timer, usb};
10use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
11use embassy_sync::blocking_mutex::Mutex; 10use embassy_sync::blocking_mutex::Mutex;
11use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
12use embassy_sync::signal::Signal; 12use embassy_sync::signal::Signal;
13use embassy_sync::zerocopy_channel; 13use embassy_sync::zerocopy_channel;
14use embassy_usb::class::uac1; 14use embassy_usb::class::uac1;
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 5153e1cfd..4e556f0d4 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -15,9 +15,9 @@
15use embassy_executor::Spawner; 15use embassy_executor::Spawner;
16use embassy_stm32::gpio::OutputType; 16use embassy_stm32::gpio::OutputType;
17use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
18use embassy_stm32::timer::Channel;
18use embassy_stm32::timer::low_level::CountingMode; 19use embassy_stm32::timer::low_level::CountingMode;
19use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 20use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
20use embassy_stm32::timer::Channel;
21use embassy_time::{Duration, Ticker, Timer}; 21use embassy_time::{Duration, Ticker, Timer};
22use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
23 23
@@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) {
61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit 61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit
62 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low 62 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low
63 63
64 let max_duty = ws2812_pwm.max_duty_cycle(); 64 let max_duty = ws2812_pwm.max_duty_cycle() as u16;
65 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing 65 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing
66 let n1 = 2 * n0; // ws2812 Bit 1 high level timing 66 let n1 = 2 * n0; // ws2812 Bit 1 high level timing
67 67