diff options
| author | Raul Alimbekov <[email protected]> | 2025-12-16 09:05:22 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-16 09:05:22 +0300 |
| commit | c9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch) | |
| tree | 6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /examples/stm32f4/src | |
| parent | cde24a3ef1117653ba5ed4184102b33f745782fb (diff) | |
| parent | 5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff) | |
Merge branch 'main' into main
Diffstat (limited to 'examples/stm32f4/src')
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 @@ | |||
| 4 | use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; | 4 | use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::adc::{Adc, Temperature, VrefInt}; | 7 | use embassy_stm32::adc::{Adc, SampleTime, Temperature, VrefInt}; |
| 8 | use embassy_time::{Delay, Timer}; | 8 | use embassy_time::{Delay, Timer}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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 @@ | |||
| 3 | use cortex_m::singleton; | 3 | use cortex_m::singleton; |
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; | ||
| 7 | use embassy_stm32::Peripherals; | 6 | use embassy_stm32::Peripherals; |
| 7 | use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, RingBufferedAdc, SampleTime}; | ||
| 8 | use embassy_time::Instant; | 8 | use embassy_time::Instant; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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] |
| 18 | async fn adc_task(mut p: Peripherals) { | 18 | async 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::exti::ExtiInput; | 6 | use embassy_stm32::exti::{self, ExtiInput}; |
| 7 | use embassy_stm32::gpio::Pull; | 7 | use embassy_stm32::gpio::Pull; |
| 8 | use embassy_stm32::{bind_interrupts, interrupt}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| 11 | bind_interrupts!( | ||
| 12 | pub struct Irqs{ | ||
| 13 | EXTI15_10 => exti::InterruptHandler<interrupt::typelevel::EXTI15_10>; | ||
| 14 | }); | ||
| 15 | |||
| 10 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 17 | async 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::*; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | 6 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Ipv4Address, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; | 8 | use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, Sma}; |
| 9 | use embassy_stm32::peripherals::ETH; | 9 | use embassy_stm32::peripherals::{ETH, ETH_SMA}; |
| 10 | use embassy_stm32::rng::Rng; | 10 | use embassy_stm32::rng::Rng; |
| 11 | use embassy_stm32::time::Hertz; | 11 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; | 12 | use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; |
| 13 | use embassy_time::Timer; | 13 | use embassy_time::Timer; |
| 14 | use embedded_io_async::Write; | 14 | use embedded_io_async::Write; |
| 15 | use static_cell::StaticCell; | 15 | use 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 | ||
| 23 | type Device = Ethernet<'static, ETH, GenericPhy>; | 23 | type Device = Ethernet<'static, ETH, GenericPhy<Sma<'static, ETH_SMA>>>; |
| 24 | 24 | ||
| 25 | #[embassy_executor::task] | 25 | #[embassy_executor::task] |
| 26 | async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { | 26 | async 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, StationManagement}; | 6 | use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement}; |
| 7 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 8 | use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; | 8 | use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; |
| 9 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| 10 | use static_cell::StaticCell; | 10 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {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; | |||
| 7 | use embassy_net::{Ipv4Address, StackResources}; | 7 | use embassy_net::{Ipv4Address, StackResources}; |
| 8 | use embassy_net_wiznet::chip::W5500; | 8 | use embassy_net_wiznet::chip::W5500; |
| 9 | use embassy_net_wiznet::{Device, Runner, State}; | 9 | use embassy_net_wiznet::{Device, Runner, State}; |
| 10 | use embassy_stm32::exti::ExtiInput; | 10 | use embassy_stm32::exti::{self, ExtiInput}; |
| 11 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | 11 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; |
| 12 | use embassy_stm32::mode::Async; | 12 | use embassy_stm32::mode::Async; |
| 13 | use embassy_stm32::rng::Rng; | 13 | use embassy_stm32::rng::Rng; |
| 14 | use embassy_stm32::spi::Spi; | 14 | use embassy_stm32::spi::Spi; |
| 15 | use embassy_stm32::spi::mode::Master; | ||
| 15 | use embassy_stm32::time::Hertz; | 16 | use embassy_stm32::time::Hertz; |
| 16 | use embassy_stm32::{bind_interrupts, peripherals, rng, spi, Config}; | 17 | use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, rng, spi}; |
| 17 | use embassy_time::{Delay, Timer}; | 18 | use embassy_time::{Delay, Timer}; |
| 18 | use embedded_hal_bus::spi::ExclusiveDevice; | 19 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 19 | use embedded_io_async::Write; | 20 | use embedded_io_async::Write; |
| @@ -22,9 +23,10 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 22 | 23 | ||
| 23 | bind_interrupts!(struct Irqs { | 24 | bind_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 | ||
| 27 | type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>; | 29 | type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>; |
| 28 | #[embassy_executor::task] | 30 | #[embassy_executor::task] |
| 29 | async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { | 31 | async 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}; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::flash::{Flash, InterruptHandler}; | 6 | use embassy_stm32::flash::{Flash, InterruptHandler}; |
| 7 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; | 7 | use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; |
| 8 | use embassy_stm32::{bind_interrupts, Peri}; | 8 | use embassy_stm32::{Peri, bind_interrupts}; |
| 9 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {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 | |||
| 10 | use defmt::{error, info}; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; | ||
| 13 | use embassy_stm32::time::Hertz; | ||
| 14 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 15 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 16 | use embassy_sync::mutex::Mutex; | ||
| 17 | use embassy_time::{Duration, Timer}; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | pub const I2C_SLAVE_ADDR: u8 = 0x42; | ||
| 21 | pub const BUFFER_SIZE: usize = 8; | ||
| 22 | static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]); | ||
| 23 | |||
| 24 | bind_interrupts!(struct Irqs { | ||
| 25 | I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||
| 26 | I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
| 27 | }); | ||
| 28 | |||
| 29 | #[embassy_executor::main] | ||
| 30 | async 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] | ||
| 56 | pub 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 | |||
| 125 | fn 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 | |||
| 9 | use defmt::{error, info}; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; | ||
| 12 | use embassy_stm32::time::Hertz; | ||
| 13 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 14 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 15 | use embassy_sync::mutex::Mutex; | ||
| 16 | use embassy_time::{Duration, Timer}; | ||
| 17 | use {defmt_rtt as _, panic_probe as _}; | ||
| 18 | |||
| 19 | pub const I2C_SLAVE_ADDR: u8 = 0x42; | ||
| 20 | pub const BUFFER_SIZE: usize = 8; | ||
| 21 | static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]); | ||
| 22 | |||
| 23 | bind_interrupts!(struct Irqs { | ||
| 24 | I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||
| 25 | I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
| 26 | }); | ||
| 27 | |||
| 28 | #[embassy_executor::main] | ||
| 29 | async 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] | ||
| 54 | pub 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 | |||
| 122 | fn 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}; | |||
| 7 | use embassy_stm32::time::khz; | 7 | use embassy_stm32::time::khz; |
| 8 | use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; | 8 | use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; |
| 9 | use embassy_stm32::timer::{self, Channel}; | 9 | use embassy_stm32::timer::{self, Channel}; |
| 10 | use embassy_stm32::{bind_interrupts, peripherals, Peri}; | 10 | use embassy_stm32::{Peri, bind_interrupts, peripherals}; |
| 11 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 7 | use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler}; | 7 | use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoConfig, McoPrescaler}; |
| 8 | use embassy_time::Timer; | 8 | use embassy_time::Timer; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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] |
| 115 | unsafe fn UART4() { | 115 | unsafe fn UART4() { |
| 116 | EXECUTOR_HIGH.on_interrupt() | 116 | unsafe { EXECUTOR_HIGH.on_interrupt() } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | #[interrupt] | 119 | #[interrupt] |
| 120 | unsafe fn UART5() { | 120 | unsafe 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::*; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::gpio::OutputType; | 6 | use embassy_stm32::gpio::OutputType; |
| 7 | use embassy_stm32::time::khz; | 7 | use embassy_stm32::time::khz; |
| 8 | use embassy_stm32::timer::Channel; | ||
| 8 | use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; | 9 | use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; |
| 9 | use embassy_stm32::timer::simple_pwm::PwmPin; | 10 | use embassy_stm32::timer::simple_pwm::PwmPin; |
| 10 | use embassy_stm32::timer::Channel; | ||
| 11 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {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; | |||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; |
| 7 | use embassy_stm32::time::khz; | 7 | use embassy_stm32::time::khz; |
| 8 | use embassy_stm32::timer::pwm_input::PwmInput; | 8 | use embassy_stm32::timer::pwm_input::PwmInput; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; | 9 | use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; |
| 10 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {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 @@ | |||
| 4 | use chrono::{NaiveDate, NaiveDateTime}; | 4 | use chrono::{NaiveDate, NaiveDateTime}; |
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 8 | use embassy_stm32::Config; | 7 | use embassy_stm32::Config; |
| 8 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 9 | use embassy_time::Timer; | 9 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; | 6 | use embassy_stm32::sdmmc::Sdmmc; |
| 7 | use embassy_stm32::time::{mhz, Hertz}; | 7 | use embassy_stm32::sdmmc::sd::{CmdBlock, DataBlock, StorageDevice}; |
| 8 | use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; | 8 | use embassy_stm32::time::{Hertz, mhz}; |
| 9 | use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::tcp::TcpSocket; | ||
| 7 | use embassy_net::StackResources; | 6 | use embassy_net::StackResources; |
| 7 | use embassy_net::tcp::TcpSocket; | ||
| 8 | use embassy_stm32::rng::{self, Rng}; | 8 | use embassy_stm32::rng::{self, Rng}; |
| 9 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 10 | use embassy_stm32::usb::Driver; | 10 | use embassy_stm32::usb::Driver; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 11 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 14 | use embassy_usb::{Builder, UsbDevice}; | 14 | use 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 | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| 9 | use embassy_stm32::exti::ExtiInput; | 9 | use embassy_stm32::exti::{self, ExtiInput}; |
| 10 | use embassy_stm32::gpio::Pull; | 10 | use embassy_stm32::gpio::Pull; |
| 11 | use embassy_stm32::time::Hertz; | 11 | use embassy_stm32::time::Hertz; |
| 12 | use embassy_stm32::usb::Driver; | 12 | use embassy_stm32::usb::Driver; |
| 13 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 13 | use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, usb}; |
| 14 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 14 | use embassy_usb::class::hid::{ |
| 15 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, | ||
| 16 | }; | ||
| 15 | use embassy_usb::control::OutResponse; | 17 | use embassy_usb::control::OutResponse; |
| 16 | use embassy_usb::{Builder, Handler}; | 18 | use embassy_usb::{Builder, Handler}; |
| 17 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 19 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| @@ -19,8 +21,11 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 19 | 21 | ||
| 20 | bind_interrupts!(struct Irqs { | 22 | bind_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 | ||
| 27 | static 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 | ||
| 4 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 5 | |||
| 4 | use defmt::*; | 6 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::time::Hertz; | 9 | use embassy_stm32::time::Hertz; |
| 8 | use embassy_stm32::usb::Driver; | 10 | use embassy_stm32::usb::Driver; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 11 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 10 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 11 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | ||
| 12 | use embassy_usb::control::OutResponse; | ||
| 13 | use embassy_usb::Builder; | 13 | use embassy_usb::Builder; |
| 14 | use embassy_usb::class::hid::{ | ||
| 15 | HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, | ||
| 16 | }; | ||
| 17 | use embassy_usb::control::OutResponse; | ||
| 14 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 18 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {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 | ||
| 25 | static 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::*; | |||
| 53 | use embassy_executor::Spawner; | 53 | use embassy_executor::Spawner; |
| 54 | use embassy_stm32::time::Hertz; | 54 | use embassy_stm32::time::Hertz; |
| 55 | use embassy_stm32::usb::Driver; | 55 | use embassy_stm32::usb::Driver; |
| 56 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 56 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 57 | use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; | 57 | use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; |
| 58 | use embassy_usb::msos::{self, windows_version}; | 58 | use embassy_usb::msos::{self, windows_version}; |
| 59 | use embassy_usb::types::InterfaceNumber; | 59 | use 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; | |||
| 6 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_stm32::time::Hertz; | 7 | use embassy_stm32::time::Hertz; |
| 8 | use embassy_stm32::usb::{Driver, Instance}; | 8 | use embassy_stm32::usb::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 9 | use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; |
| 10 | use embassy_usb::Builder; | ||
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 11 | use embassy_usb::driver::EndpointError; | 12 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::Builder; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_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}; | |||
| 6 | use defmt::{panic, *}; | 6 | use defmt::{panic, *}; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::time::Hertz; | 8 | use embassy_stm32::time::Hertz; |
| 9 | use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; | 9 | use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, timer, usb}; |
| 10 | use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; | ||
| 11 | use embassy_sync::blocking_mutex::Mutex; | 10 | use embassy_sync::blocking_mutex::Mutex; |
| 11 | use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; | ||
| 12 | use embassy_sync::signal::Signal; | 12 | use embassy_sync::signal::Signal; |
| 13 | use embassy_sync::zerocopy_channel; | 13 | use embassy_sync::zerocopy_channel; |
| 14 | use embassy_usb::class::uac1; | 14 | use 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 @@ | |||
| 15 | use embassy_executor::Spawner; | 15 | use embassy_executor::Spawner; |
| 16 | use embassy_stm32::gpio::OutputType; | 16 | use embassy_stm32::gpio::OutputType; |
| 17 | use embassy_stm32::time::khz; | 17 | use embassy_stm32::time::khz; |
| 18 | use embassy_stm32::timer::Channel; | ||
| 18 | use embassy_stm32::timer::low_level::CountingMode; | 19 | use embassy_stm32::timer::low_level::CountingMode; |
| 19 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; | 20 | use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; |
| 20 | use embassy_stm32::timer::Channel; | ||
| 21 | use embassy_time::{Duration, Ticker, Timer}; | 21 | use embassy_time::{Duration, Ticker, Timer}; |
| 22 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {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 | ||
