aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorchasingRs <[email protected]>2025-11-10 04:16:05 -0800
committerGitHub <[email protected]>2025-11-10 04:16:05 -0800
commitf5d1c4eed74a9eb74c9903c78c7943c2ad41a3ef (patch)
tree90ab86129479fdd1139eb9a711fe826eecd0384b /embassy-stm32/src
parent944fda48a94c2d6cb6bea56c8c8471858d75da7d (diff)
parent4ef7f91663b51e2cfeb6ef40d907bfff90737de8 (diff)
Merge branch 'embassy-rs:main' into fix/simple-pwm-32bit-timer-support
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/adc/g4.rs359
-rw-r--r--embassy-stm32/src/adc/injected.rs44
-rw-r--r--embassy-stm32/src/adc/mod.rs20
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs182
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs432
-rw-r--r--embassy-stm32/src/adc/v2.rs134
-rw-r--r--embassy-stm32/src/adc/v3.rs173
-rw-r--r--embassy-stm32/src/backup_sram.rs28
-rw-r--r--embassy-stm32/src/can/fd/config.rs13
-rw-r--r--embassy-stm32/src/can/fdcan.rs15
-rw-r--r--embassy-stm32/src/dsihost.rs12
-rw-r--r--embassy-stm32/src/exti.rs2
-rw-r--r--embassy-stm32/src/flash/l.rs12
-rw-r--r--embassy-stm32/src/fmc.rs36
-rw-r--r--embassy-stm32/src/hrtim/mod.rs87
-rw-r--r--embassy-stm32/src/i2c/config.rs8
-rw-r--r--embassy-stm32/src/i2c/mod.rs102
-rw-r--r--embassy-stm32/src/i2c/v1.rs1080
-rw-r--r--embassy-stm32/src/i2c/v2.rs19
-rw-r--r--embassy-stm32/src/i2s.rs3
-rw-r--r--embassy-stm32/src/lib.rs20
-rw-r--r--embassy-stm32/src/low_power.rs141
-rw-r--r--embassy-stm32/src/rcc/bd.rs26
-rw-r--r--embassy-stm32/src/rcc/l.rs43
-rw-r--r--embassy-stm32/src/rcc/mod.rs5
-rw-r--r--embassy-stm32/src/rtc/low_power.rs15
-rw-r--r--embassy-stm32/src/rtc/mod.rs112
-rw-r--r--embassy-stm32/src/rtc/v2.rs2
-rw-r--r--embassy-stm32/src/rtc/v3.rs6
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs10
-rw-r--r--embassy-stm32/src/spi/mod.rs147
-rw-r--r--embassy-stm32/src/time_driver.rs78
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs12
-rw-r--r--embassy-stm32/src/timer/low_level.rs86
-rw-r--r--embassy-stm32/src/timer/mod.rs4
-rw-r--r--embassy-stm32/src/uid.rs4
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs34
-rw-r--r--embassy-stm32/src/vrefbuf/mod.rs8
38 files changed, 2777 insertions, 737 deletions
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 5098aadd8..3767820cf 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,11 +1,14 @@
1use core::mem;
2
1#[allow(unused)] 3#[allow(unused)]
2#[cfg(stm32h7)] 4#[cfg(stm32h7)]
3use pac::adc::vals::{Adcaldif, Difsel, Exten}; 5use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)] 6#[allow(unused)]
5#[cfg(stm32g4)] 7#[cfg(stm32g4)]
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; 8pub use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
7use pac::adccommon::vals::Presc; 9pub use pac::adccommon::vals::Presc;
8use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 10pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
11pub use stm32_metapac::adccommon::vals::Dual;
9 12
10use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us}; 13use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us};
11use crate::adc::SealedAdcChannel; 14use crate::adc::SealedAdcChannel;
@@ -13,11 +16,19 @@ use crate::dma::Transfer;
13use crate::time::Hertz; 16use crate::time::Hertz;
14use crate::{Peri, pac, rcc}; 17use crate::{Peri, pac, rcc};
15 18
19mod ringbuffered;
20pub use ringbuffered::RingBufferedAdc;
21
22mod injected;
23pub use injected::InjectedAdc;
24
16/// Default VREF voltage used for sample conversion to millivolts. 25/// Default VREF voltage used for sample conversion to millivolts.
17pub const VREF_DEFAULT_MV: u32 = 3300; 26pub const VREF_DEFAULT_MV: u32 = 3300;
18/// VREF voltage used for factory calibration of VREFINTCAL register. 27/// VREF voltage used for factory calibration of VREFINTCAL register.
19pub const VREF_CALIB_MV: u32 = 3300; 28pub const VREF_CALIB_MV: u32 = 3300;
20 29
30const NR_INJECTED_RANKS: usize = 4;
31
21/// Max single ADC operation clock frequency 32/// Max single ADC operation clock frequency
22#[cfg(stm32g4)] 33#[cfg(stm32g4)]
23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 34const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
@@ -120,6 +131,24 @@ impl Prescaler {
120 } 131 }
121} 132}
122 133
134// Trigger source for ADC conversions¨
135#[derive(Copy, Clone)]
136pub struct ConversionTrigger {
137 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
138 // Note that Injected and Regular channels uses different mappings
139 pub channel: u8,
140 pub edge: Exten,
141}
142
143// Conversion mode for regular ADC channels
144#[derive(Copy, Clone)]
145pub enum RegularConversionMode {
146 // Samples as fast as possible
147 Continuous,
148 // Sample at rate determined by external trigger
149 Triggered(ConversionTrigger),
150}
151
123impl<'d, T: Instance> Adc<'d, T> { 152impl<'d, T: Instance> Adc<'d, T> {
124 /// Create a new ADC driver. 153 /// Create a new ADC driver.
125 pub fn new(adc: Peri<'d, T>) -> Self { 154 pub fn new(adc: Peri<'d, T>) -> Self {
@@ -357,7 +386,29 @@ impl<'d, T: Instance> Adc<'d, T> {
357 self.read_channel(channel) 386 self.read_channel(channel)
358 } 387 }
359 388
360 /// Read one or multiple ADC channels using DMA. 389 /// Start regular adc conversion
390 pub(super) fn start() {
391 T::regs().cr().modify(|reg| {
392 reg.set_adstart(true);
393 });
394 }
395
396 /// Stop regular conversions
397 pub(super) fn stop() {
398 Self::stop_regular_conversions();
399 }
400
401 /// Teardown method for stopping regular ADC conversions
402 pub(super) fn teardown_adc() {
403 Self::stop_regular_conversions();
404
405 // Disable dma control
406 T::regs().cfgr().modify(|reg| {
407 reg.set_dmaen(Dmaen::DISABLE);
408 });
409 }
410
411 /// Read one or multiple ADC regular channels using DMA.
361 /// 412 ///
362 /// `sequence` iterator and `readings` must have the same length. 413 /// `sequence` iterator and `readings` must have the same length.
363 /// 414 ///
@@ -382,6 +433,9 @@ impl<'d, T: Instance> Adc<'d, T> {
382 /// .await; 433 /// .await;
383 /// defmt::info!("measurements: {}", measurements); 434 /// defmt::info!("measurements: {}", measurements);
384 /// ``` 435 /// ```
436 ///
437 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
438 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
385 pub async fn read( 439 pub async fn read(
386 &mut self, 440 &mut self,
387 rx_dma: Peri<'_, impl RxDma<T>>, 441 rx_dma: Peri<'_, impl RxDma<T>>,
@@ -399,18 +453,16 @@ impl<'d, T: Instance> Adc<'d, T> {
399 ); 453 );
400 454
401 // Ensure no conversions are ongoing and ADC is enabled. 455 // Ensure no conversions are ongoing and ADC is enabled.
402 Self::cancel_conversions(); 456 Self::stop_regular_conversions();
403 self.enable(); 457 self.enable();
404 458
405 // Set sequence length 459 // Set sequence length
406 T::regs().sqr1().modify(|w| { 460 T::regs().sqr1().modify(|w| {
407 w.set_l(sequence.len() as u8 - 1); 461 w.set_l(sequence.len() as u8 - 1);
408 }); 462 });
409
410 // Configure channels and ranks 463 // Configure channels and ranks
411 for (_i, (channel, sample_time)) in sequence.enumerate() { 464 for (_i, (channel, sample_time)) in sequence.enumerate() {
412 Self::configure_channel(channel, sample_time); 465 Self::configure_channel(channel, sample_time);
413
414 match _i { 466 match _i {
415 0..=3 => { 467 0..=3 => {
416 T::regs().sqr1().modify(|w| { 468 T::regs().sqr1().modify(|w| {
@@ -469,7 +521,7 @@ impl<'d, T: Instance> Adc<'d, T> {
469 transfer.await; 521 transfer.await;
470 522
471 // Ensure conversions are finished. 523 // Ensure conversions are finished.
472 Self::cancel_conversions(); 524 Self::stop_regular_conversions();
473 525
474 // Reset configuration. 526 // Reset configuration.
475 T::regs().cfgr().modify(|reg| { 527 T::regs().cfgr().modify(|reg| {
@@ -477,6 +529,277 @@ impl<'d, T: Instance> Adc<'d, T> {
477 }); 529 });
478 } 530 }
479 531
532 /// Set external trigger for regular conversion sequence
533 fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) {
534 T::regs().cfgr().modify(|r| {
535 r.set_extsel(trigger.channel);
536 r.set_exten(trigger.edge);
537 });
538 // Regular conversions uses DMA so no need to generate interrupt
539 T::regs().ier().modify(|r| r.set_eosie(false));
540 }
541
542 // Dual ADC mode selection
543 pub fn configure_dual_mode(&mut self, val: Dual) {
544 T::common_regs().ccr().modify(|reg| {
545 reg.set_dual(val);
546 })
547 }
548
549 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
550 ///
551 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
552 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
553 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
554 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
555 /// defines the period at which the buffer should be read.
556 ///
557 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
558 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
559 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
560 /// the buffer length should be `3 * 40 = 120`.
561 ///
562 /// # Parameters
563 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
564 /// - `dma_buf`: The buffer where DMA stores ADC samples.
565 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
566 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
567 ///
568 /// # Returns
569 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
570 pub fn into_ring_buffered<'a>(
571 mut self,
572 dma: Peri<'a, impl RxDma<T>>,
573 dma_buf: &'a mut [u16],
574 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
575 mode: RegularConversionMode,
576 ) -> RingBufferedAdc<'a, T> {
577 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
578 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
579 assert!(
580 sequence.len() <= 16,
581 "Asynchronous read sequence cannot be more than 16 in length"
582 );
583 // reset conversions and enable the adc
584 Self::stop_regular_conversions();
585 self.enable();
586
587 //adc side setup
588
589 // Set sequence length
590 T::regs().sqr1().modify(|w| {
591 w.set_l(sequence.len() as u8 - 1);
592 });
593
594 // Configure channels and ranks
595 for (_i, (mut channel, sample_time)) in sequence.enumerate() {
596 Self::configure_channel(&mut channel, sample_time);
597
598 match _i {
599 0..=3 => {
600 T::regs().sqr1().modify(|w| {
601 w.set_sq(_i, channel.channel());
602 });
603 }
604 4..=8 => {
605 T::regs().sqr2().modify(|w| {
606 w.set_sq(_i - 4, channel.channel());
607 });
608 }
609 9..=13 => {
610 T::regs().sqr3().modify(|w| {
611 w.set_sq(_i - 9, channel.channel());
612 });
613 }
614 14..=15 => {
615 T::regs().sqr4().modify(|w| {
616 w.set_sq(_i - 14, channel.channel());
617 });
618 }
619 _ => unreachable!(),
620 }
621 }
622
623 // Clear overrun flag before starting transfer.
624 T::regs().isr().modify(|reg| {
625 reg.set_ovr(true);
626 });
627
628 T::regs().cfgr().modify(|reg| {
629 reg.set_discen(false); // Convert all channels for each trigger
630 reg.set_dmacfg(Dmacfg::CIRCULAR);
631 reg.set_dmaen(Dmaen::ENABLE);
632 });
633
634 match mode {
635 RegularConversionMode::Continuous => {
636 T::regs().cfgr().modify(|reg| {
637 reg.set_cont(true);
638 });
639 }
640 RegularConversionMode::Triggered(trigger) => {
641 T::regs().cfgr().modify(|r| {
642 r.set_cont(false); // New trigger is neede for each sample to be read
643 });
644 self.set_regular_conversion_trigger(trigger);
645 }
646 }
647
648 mem::forget(self);
649
650 RingBufferedAdc::new(dma, dma_buf)
651 }
652
653 /// Configures the ADC for injected conversions.
654 ///
655 /// Injected conversions are separate from the regular conversion sequence and are typically
656 /// triggered by software or an external event. This method sets up a fixed-length sequence of
657 /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence
658 /// interrupt should be enabled.
659 ///
660 /// # Parameters
661 /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length
662 /// `N` determines the number of injected ranks to configure (maximum 4 for STM32).
663 /// - `trigger`: The trigger source that starts the injected conversion sequence.
664 /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions.
665 ///
666 /// # Returns
667 /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned
668 /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples.
669 ///
670 /// # Panics
671 /// This function will panic if:
672 /// - `sequence` is empty.
673 /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`).
674 ///
675 /// # Notes
676 /// - Injected conversions can run independently of regular ADC conversions.
677 /// - The order of channels in `sequence` determines the rank order in the injected sequence.
678 /// - Accessing samples beyond `N` will result in a panic; use the returned type
679 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
680 pub fn setup_injected_conversions<'a, const N: usize>(
681 mut self,
682 sequence: [(AnyAdcChannel<T>, SampleTime); N],
683 trigger: ConversionTrigger,
684 interrupt: bool,
685 ) -> InjectedAdc<T, N> {
686 assert!(N != 0, "Read sequence cannot be empty");
687 assert!(
688 N <= NR_INJECTED_RANKS,
689 "Read sequence cannot be more than {} in length",
690 NR_INJECTED_RANKS
691 );
692
693 Self::stop_regular_conversions();
694 self.enable();
695
696 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
697
698 for (n, (mut channel, sample_time)) in sequence.into_iter().enumerate() {
699 Self::configure_channel(&mut channel, sample_time);
700
701 let idx = match n {
702 0..=3 => n,
703 4..=8 => n - 4,
704 9..=13 => n - 9,
705 14..=15 => n - 14,
706 _ => unreachable!(),
707 };
708
709 T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel()));
710 }
711
712 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
713
714 self.set_injected_conversion_trigger(trigger);
715 self.enable_injected_eos_interrupt(interrupt);
716 Self::start_injected_conversions();
717
718 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
719 }
720
721 /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions.
722 ///
723 /// # Parameters
724 /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers.
725 /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions.
726 /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions.
727 /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered).
728 /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`).
729 /// - `injected_trigger`: The trigger source for injected conversions.
730 /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions.
731 ///
732 /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode,
733 /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete.
734 ///
735 /// # Returns
736 /// A tuple containing:
737 /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA.
738 /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions.
739 ///
740 /// # Safety
741 /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the
742 /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently.
743 /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way.
744 pub fn into_ring_buffered_and_injected<'a, const N: usize>(
745 self,
746 dma: Peri<'a, impl RxDma<T>>,
747 dma_buf: &'a mut [u16],
748 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
749 regular_conversion_mode: RegularConversionMode,
750 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
751 injected_trigger: ConversionTrigger,
752 injected_interrupt: bool,
753 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
754 unsafe {
755 (
756 Self {
757 adc: self.adc.clone_unchecked(),
758 sample_time: self.sample_time,
759 }
760 .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode),
761 Self {
762 adc: self.adc.clone_unchecked(),
763 sample_time: self.sample_time,
764 }
765 .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt),
766 )
767 }
768 }
769
770 /// Stop injected conversions
771 pub(super) fn stop_injected_conversions() {
772 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
773 T::regs().cr().modify(|reg| {
774 reg.set_jadstp(Adstp::STOP);
775 });
776 // The software must poll JADSTART until the bit is reset before assuming the
777 // ADC is completely stopped
778 while T::regs().cr().read().jadstart() {}
779 }
780 }
781
782 /// Start injected ADC conversion
783 pub(super) fn start_injected_conversions() {
784 T::regs().cr().modify(|reg| {
785 reg.set_jadstart(true);
786 });
787 }
788
789 /// Set external trigger for injected conversion sequence
790 /// Possible trigger values are seen in Table 167 in RM0440 Rev 9
791 fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) {
792 T::regs().jsqr().modify(|r| {
793 r.set_jextsel(trigger.channel);
794 r.set_jexten(trigger.edge);
795 });
796 }
797
798 /// Enable end of injected sequence interrupt
799 fn enable_injected_eos_interrupt(&mut self, enable: bool) {
800 T::regs().ier().modify(|r| r.set_jeosie(enable));
801 }
802
480 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 803 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
481 // Configure channel 804 // Configure channel
482 Self::set_channel_sample_time(channel.channel(), sample_time); 805 Self::set_channel_sample_time(channel.channel(), sample_time);
@@ -509,16 +832,34 @@ impl<'d, T: Instance> Adc<'d, T> {
509 } 832 }
510 } 833 }
511 834
512 fn cancel_conversions() { 835 // Stop regular conversions
836 fn stop_regular_conversions() {
513 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 837 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
514 T::regs().cr().modify(|reg| { 838 T::regs().cr().modify(|reg| {
515 reg.set_adstp(Adstp::STOP); 839 reg.set_adstp(Adstp::STOP);
516 }); 840 });
841 // The software must poll ADSTART until the bit is reset before assuming the
842 // ADC is completely stopped
517 while T::regs().cr().read().adstart() {} 843 while T::regs().cr().read().adstart() {}
518 } 844 }
519 } 845 }
520} 846}
521 847
848impl<T: Instance, const N: usize> InjectedAdc<T, N> {
849 /// Read sampled data from all injected ADC injected ranks
850 /// Clear the JEOS flag to allow a new injected sequence
851 pub(super) fn read_injected_data() -> [u16; N] {
852 let mut data = [0u16; N];
853 for i in 0..N {
854 data[i] = T::regs().jdr(i).read().jdata();
855 }
856
857 // Clear JEOS by writing 1
858 T::regs().isr().modify(|r| r.set_jeos(true));
859 data
860 }
861}
862
522/// Implemented for ADCs that have a Temperature channel 863/// Implemented for ADCs that have a Temperature channel
523pub trait TemperatureChannel { 864pub trait TemperatureChannel {
524 const CHANNEL: u8; 865 const CHANNEL: u8;
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
new file mode 100644
index 000000000..0e4fe5847
--- /dev/null
+++ b/embassy-stm32/src/adc/injected.rs
@@ -0,0 +1,44 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use super::{AnyAdcChannel, SampleTime};
8use crate::adc::Adc;
9#[allow(unused_imports)]
10use crate::adc::Instance;
11
12/// Injected ADC sequence with owned channels.
13pub struct InjectedAdc<T: Instance, const N: usize> {
14 _channels: [(AnyAdcChannel<T>, SampleTime); N],
15 _phantom: PhantomData<T>,
16}
17
18impl<T: Instance, const N: usize> InjectedAdc<T, N> {
19 pub(crate) fn new(channels: [(AnyAdcChannel<T>, SampleTime); N]) -> Self {
20 Self {
21 _channels: channels,
22 _phantom: PhantomData,
23 }
24 }
25
26 pub fn stop_injected_conversions(&mut self) {
27 Adc::<T>::stop_injected_conversions()
28 }
29
30 pub fn start_injected_conversions(&mut self) {
31 Adc::<T>::start_injected_conversions()
32 }
33
34 pub fn read_injected_samples(&mut self) -> [u16; N] {
35 InjectedAdc::<T, N>::read_injected_data()
36 }
37}
38
39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> {
40 fn drop(&mut self) {
41 Adc::<T>::teardown_adc();
42 compiler_fence(Ordering::SeqCst);
43 }
44}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 22ed8295f..ea7341f75 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -87,14 +87,18 @@ pub(crate) trait SealedAdcChannel<T> {
87/// Performs a busy-wait delay for a specified number of microseconds. 87/// Performs a busy-wait delay for a specified number of microseconds.
88#[allow(unused)] 88#[allow(unused)]
89pub(crate) fn blocking_delay_us(us: u32) { 89pub(crate) fn blocking_delay_us(us: u32) {
90 #[cfg(feature = "time")] 90 cfg_if::cfg_if! {
91 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); 91 // this does strange things on stm32wlx in low power mode depending on exactly when it's called
92 #[cfg(not(feature = "time"))] 92 // as in sometimes 15 us (1 tick) would take > 20 seconds.
93 { 93 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] {
94 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 94 let duration = embassy_time::Duration::from_micros(us as u64);
95 let us = us as u64; 95 embassy_time::block_for(duration);
96 let cycles = freq * us / 1_000_000; 96 } else {
97 cortex_m::asm::delay(cycles as u32); 97 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
98 let us = us as u64;
99 let cycles = freq * us / 1_000_000;
100 cortex_m::asm::delay(cycles as u32);
101 }
98 } 102 }
99} 103}
100 104
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
new file mode 100644
index 000000000..971c8195c
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -0,0 +1,182 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use crate::adc::Adc;
8#[allow(unused_imports)]
9use crate::adc::{Instance, RxDma};
10#[allow(unused_imports)]
11use crate::dma::{ReadableRingBuffer, TransferOptions};
12use crate::rcc;
13
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct OverrunError;
16
17pub struct RingBufferedAdc<'d, T: Instance> {
18 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u16>,
20}
21
22impl<'d, T: Instance> RingBufferedAdc<'d, T> {
23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
24 //dma side setup
25 let opts = TransferOptions {
26 half_transfer_ir: true,
27 circular: true,
28 ..Default::default()
29 };
30
31 // Safety: we forget the struct before this function returns.
32 let request = dma.request();
33
34 let ring_buf =
35 unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) };
36
37 Self {
38 _phantom: PhantomData,
39 ring_buf,
40 }
41 }
42
43 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
44 pub fn start(&mut self) {
45 compiler_fence(Ordering::SeqCst);
46 self.ring_buf.start();
47
48 Adc::<T>::start();
49 }
50
51 pub fn stop(&mut self) {
52 Adc::<T>::stop();
53
54 self.ring_buf.request_pause();
55
56 compiler_fence(Ordering::SeqCst);
57 }
58
59 pub fn clear(&mut self) {
60 self.ring_buf.clear();
61 }
62
63 /// Reads measurements from the DMA ring buffer.
64 ///
65 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
66 /// The length of the `measurements` array should be exactly half of the DMA buffer length.
67 /// Because interrupts are only generated if half or full DMA transfer completes.
68 ///
69 /// Each call to `read` will populate the `measurements` array in the same order as the channels
70 /// defined with `sequence`. There will be many sequences worth of measurements in this array
71 /// because it only returns if at least half of the DMA buffer is filled. For example if 2
72 /// channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
73 ///
74 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly
75 /// running tasks. Otherwise, you'll see constant Overrun errors occurring, this means that
76 /// you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
77 /// Example:
78 /// ```rust,ignore
79 /// const DMA_BUF_LEN: usize = 120;
80 /// use embassy_stm32::adc::{Adc, AdcChannel}
81 ///
82 /// let mut adc = Adc::new(p.ADC1);
83 /// let mut adc_pin0 = p.PA0.degrade_adc();
84 /// let mut adc_pin1 = p.PA1.degrade_adc();
85 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
86 ///
87 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
88 /// p.DMA2_CH0,
89 /// adc_dma_buf, [
90 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
91 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
92 /// ].into_iter());
93 ///
94 ///
95 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
96 /// loop {
97 /// match ring_buffered_adc.read(&mut measurements).await {
98 /// Ok(_) => {
99 /// defmt::info!("adc1: {}", measurements);
100 /// }
101 /// Err(e) => {
102 /// defmt::warn!("Error: {:?}", e);
103 /// }
104 /// }
105 /// }
106 /// ```
107 ///
108 ///
109 /// [`teardown_adc`]: #method.teardown_adc
110 /// [`start_continuous_sampling`]: #method.start_continuous_sampling
111 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
112 assert_eq!(
113 self.ring_buf.capacity() / 2,
114 measurements.len(),
115 "Buffer size must be half the size of the ring buffer"
116 );
117
118 if !self.ring_buf.is_running() {
119 self.start();
120 }
121
122 #[cfg(adc_v2)]
123 {
124 // Clear overrun flag if set.
125 if T::regs().sr().read().ovr() {
126 self.stop();
127
128 return Err(OverrunError);
129 }
130 }
131
132 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
133 }
134
135 /// Read bytes that are readily available in the ring buffer.
136 /// If no bytes are currently available in the buffer the call waits until the some
137 /// bytes are available (at least one byte and at most half the buffer size)
138 ///
139 /// Background receive is started if `start_continuous_sampling()` has not been previously called.
140 ///
141 /// Receive in the background is terminated if an error is returned.
142 /// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`.
143 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
144 if !self.ring_buf.is_running() {
145 self.start();
146 }
147
148 #[cfg(adc_v2)]
149 {
150 // Clear overrun flag if set.
151 if T::regs().sr().read().ovr() {
152 self.stop();
153
154 return Err(OverrunError);
155 }
156 }
157 loop {
158 match self.ring_buf.read(buf) {
159 Ok((0, _)) => {}
160 Ok((len, _)) => {
161 return Ok(len);
162 }
163 Err(_) => {
164 self.stop();
165
166 return Err(OverrunError);
167 }
168 }
169 }
170 }
171}
172
173impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
174 fn drop(&mut self) {
175 Adc::<T>::teardown_adc();
176
177 compiler_fence(Ordering::SeqCst);
178
179 self.ring_buf.request_pause();
180 rcc::disable::<T>();
181 }
182}
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
deleted file mode 100644
index 9b2e5b8fe..000000000
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ /dev/null
@@ -1,432 +0,0 @@
1use core::marker::PhantomData;
2use core::mem;
3use core::sync::atomic::{Ordering, compiler_fence};
4
5use stm32_metapac::adc::vals::SampleTime;
6
7use crate::adc::{Adc, AdcChannel, Instance, RxDma};
8use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
9use crate::pac::adc::vals;
10use crate::{Peri, rcc};
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OverrunError;
14
15fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
16 r.sr().modify(|regs| {
17 regs.set_eoc(false);
18 regs.set_ovr(false);
19 });
20}
21
22#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
23pub enum Sequence {
24 One,
25 Two,
26 Three,
27 Four,
28 Five,
29 Six,
30 Seven,
31 Eight,
32 Nine,
33 Ten,
34 Eleven,
35 Twelve,
36 Thirteen,
37 Fourteen,
38 Fifteen,
39 Sixteen,
40}
41
42impl From<Sequence> for u8 {
43 fn from(s: Sequence) -> u8 {
44 match s {
45 Sequence::One => 0,
46 Sequence::Two => 1,
47 Sequence::Three => 2,
48 Sequence::Four => 3,
49 Sequence::Five => 4,
50 Sequence::Six => 5,
51 Sequence::Seven => 6,
52 Sequence::Eight => 7,
53 Sequence::Nine => 8,
54 Sequence::Ten => 9,
55 Sequence::Eleven => 10,
56 Sequence::Twelve => 11,
57 Sequence::Thirteen => 12,
58 Sequence::Fourteen => 13,
59 Sequence::Fifteen => 14,
60 Sequence::Sixteen => 15,
61 }
62 }
63}
64
65impl From<u8> for Sequence {
66 fn from(val: u8) -> Self {
67 match val {
68 0 => Sequence::One,
69 1 => Sequence::Two,
70 2 => Sequence::Three,
71 3 => Sequence::Four,
72 4 => Sequence::Five,
73 5 => Sequence::Six,
74 6 => Sequence::Seven,
75 7 => Sequence::Eight,
76 8 => Sequence::Nine,
77 9 => Sequence::Ten,
78 10 => Sequence::Eleven,
79 11 => Sequence::Twelve,
80 12 => Sequence::Thirteen,
81 13 => Sequence::Fourteen,
82 14 => Sequence::Fifteen,
83 15 => Sequence::Sixteen,
84 _ => panic!("Invalid sequence number"),
85 }
86 }
87}
88
89pub struct RingBufferedAdc<'d, T: Instance> {
90 _phantom: PhantomData<T>,
91 ring_buf: ReadableRingBuffer<'d, u16>,
92}
93
94impl<'d, T: Instance> Adc<'d, T> {
95 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
96 ///
97 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
98 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
99 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
100 ///
101 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
102 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
103 ///
104 /// [`read`]: #method.read
105 pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> {
106 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
107
108 let opts: crate::dma::TransferOptions = TransferOptions {
109 half_transfer_ir: true,
110 priority: Priority::VeryHigh,
111 ..Default::default()
112 };
113
114 // Safety: we forget the struct before this function returns.
115 let rx_src = T::regs().dr().as_ptr() as *mut u16;
116 let request = dma.request();
117
118 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
119
120 // Don't disable the clock
121 mem::forget(self);
122
123 RingBufferedAdc {
124 _phantom: PhantomData,
125 ring_buf,
126 }
127 }
128}
129
130impl<'d, T: Instance> RingBufferedAdc<'d, T> {
131 fn is_on() -> bool {
132 T::regs().cr2().read().adon()
133 }
134
135 fn stop_adc() {
136 T::regs().cr2().modify(|reg| {
137 reg.set_adon(false);
138 });
139 }
140
141 fn start_adc() {
142 T::regs().cr2().modify(|reg| {
143 reg.set_adon(true);
144 });
145 }
146
147 /// Sets the channel sample time
148 ///
149 /// ## SAFETY:
150 /// - ADON == 0 i.e ADC must not be enabled when this is called.
151 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
152 if ch <= 9 {
153 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
154 } else {
155 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
156 }
157 }
158
159 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
160 let ch_iter = ch.iter();
161 for idx in ch_iter {
162 unsafe {
163 Self::set_channel_sample_time(*idx, sample_time);
164 }
165 }
166 }
167
168 pub fn set_sample_sequence(
169 &mut self,
170 sequence: Sequence,
171 channel: &mut impl AdcChannel<T>,
172 sample_time: SampleTime,
173 ) {
174 let was_on = Self::is_on();
175 if !was_on {
176 Self::start_adc();
177 }
178
179 // Check the sequence is long enough
180 T::regs().sqr1().modify(|r| {
181 let prev: Sequence = r.l().into();
182 if prev < sequence {
183 let new_l: Sequence = sequence;
184 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
185 r.set_l(sequence.into())
186 } else {
187 r.set_l(prev.into())
188 }
189 });
190
191 // Set this GPIO as an analog input.
192 channel.setup();
193
194 // Set the channel in the right sequence field.
195 match sequence {
196 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
197 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
198 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
199 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
200 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
201 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
202 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
203 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
204 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
205 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
206 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
207 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
208 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
209 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
210 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
211 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
212 };
213
214 if !was_on {
215 Self::stop_adc();
216 }
217
218 self.set_channels_sample_time(&[channel.channel()], sample_time);
219
220 Self::start_adc();
221 }
222
223 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
224 pub fn start(&mut self) -> Result<(), OverrunError> {
225 self.setup_adc();
226 self.ring_buf.clear();
227
228 Ok(())
229 }
230
231 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
232 self.teardown_adc();
233 Err(err)
234 }
235
236 /// Stops DMA transfer.
237 /// It does not turn off ADC.
238 /// Calling `start` restarts continuous DMA transfer.
239 ///
240 /// [`start`]: #method.start
241 pub fn teardown_adc(&mut self) {
242 // Stop the DMA transfer
243 self.ring_buf.request_pause();
244
245 let r = T::regs();
246
247 // Stop ADC
248 r.cr2().modify(|reg| {
249 // Stop ADC
250 reg.set_swstart(false);
251 // Stop DMA
252 reg.set_dma(false);
253 });
254
255 r.cr1().modify(|w| {
256 // Disable interrupt for end of conversion
257 w.set_eocie(false);
258 // Disable interrupt for overrun
259 w.set_ovrie(false);
260 });
261
262 clear_interrupt_flags(r);
263
264 compiler_fence(Ordering::SeqCst);
265 }
266
267 fn setup_adc(&mut self) {
268 compiler_fence(Ordering::SeqCst);
269
270 self.ring_buf.start();
271
272 let r = T::regs();
273
274 // Enable ADC
275 let was_on = Self::is_on();
276 if !was_on {
277 r.cr2().modify(|reg| {
278 reg.set_adon(false);
279 reg.set_swstart(false);
280 });
281 }
282
283 // Clear all interrupts
284 r.sr().modify(|regs| {
285 regs.set_eoc(false);
286 regs.set_ovr(false);
287 regs.set_strt(false);
288 });
289
290 r.cr1().modify(|w| {
291 // Enable interrupt for end of conversion
292 w.set_eocie(true);
293 // Enable interrupt for overrun
294 w.set_ovrie(true);
295 // Scanning converisons of multiple channels
296 w.set_scan(true);
297 // Continuous conversion mode
298 w.set_discen(false);
299 });
300
301 r.cr2().modify(|w| {
302 // Enable DMA mode
303 w.set_dma(true);
304 // Enable continuous conversions
305 w.set_cont(true);
306 // DMA requests are issues as long as DMA=1 and data are converted.
307 w.set_dds(vals::Dds::CONTINUOUS);
308 // EOC flag is set at the end of each conversion.
309 w.set_eocs(vals::Eocs::EACH_CONVERSION);
310 });
311
312 // Begin ADC conversions
313 T::regs().cr2().modify(|reg| {
314 reg.set_adon(true);
315 reg.set_swstart(true);
316 });
317
318 super::blocking_delay_us(3);
319 }
320
321 /// Read bytes that are readily available in the ring buffer.
322 /// If no bytes are currently available in the buffer the call waits until the some
323 /// bytes are available (at least one byte and at most half the buffer size)
324 ///
325 /// Background receive is started if `start()` has not been previously called.
326 ///
327 /// Receive in the background is terminated if an error is returned.
328 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
329 pub fn blocking_read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
330 let r = T::regs();
331
332 // Start background receive if it was not already started
333 if !r.cr2().read().dma() {
334 self.start()?;
335 }
336
337 // Clear overrun flag if set.
338 if r.sr().read().ovr() {
339 return self.stop(OverrunError);
340 }
341
342 loop {
343 match self.ring_buf.read(buf) {
344 Ok((0, _)) => {}
345 Ok((len, _)) => {
346 return Ok(len);
347 }
348 Err(_) => {
349 return self.stop(OverrunError);
350 }
351 }
352 }
353 }
354
355 /// Reads measurements from the DMA ring buffer.
356 ///
357 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
358 /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
359 ///
360 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
361 /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
362 /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
363 ///
364 /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` or `read` again.
365 ///
366 /// By default, the ADC fills the DMA buffer as quickly as possible. To control the sample rate, call `teardown_adc` after each readout, and then start the DMA again at the desired interval.
367 /// Note that even if using `teardown_adc` to control the sample rate, with each call to `read`, measurements equivalent to half the size of the DMA buffer are still collected.
368 ///
369 /// Example:
370 /// ```rust,ignore
371 /// const DMA_BUF_LEN: usize = 120;
372 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
373 /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
374 ///
375 /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
376 /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
377 /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
378 ///
379 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
380 /// loop {
381 /// match adc.read(&mut measurements).await {
382 /// Ok(_) => {
383 /// defmt::info!("adc1: {}", measurements);
384 /// // Only needed to manually control sample rate.
385 /// adc.teardown_adc();
386 /// }
387 /// Err(e) => {
388 /// defmt::warn!("Error: {:?}", e);
389 /// // DMA overrun, next call to `read` restarts ADC.
390 /// }
391 /// }
392 ///
393 /// // Manually control sample rate.
394 /// Timer::after_millis(100).await;
395 /// }
396 /// ```
397 ///
398 ///
399 /// [`set_sample_sequence`]: #method.set_sample_sequence
400 /// [`teardown_adc`]: #method.teardown_adc
401 /// [`start`]: #method.start
402 pub async fn read<const N: usize>(&mut self, measurements: &mut [u16; N]) -> Result<usize, OverrunError> {
403 assert_eq!(
404 self.ring_buf.capacity() / 2,
405 N,
406 "Buffer size must be half the size of the ring buffer"
407 );
408
409 let r = T::regs();
410
411 // Start background receive if it was not already started
412 if !r.cr2().read().dma() {
413 self.start()?;
414 }
415
416 // Clear overrun flag if set.
417 if r.sr().read().ovr() {
418 return self.stop(OverrunError);
419 }
420 match self.ring_buf.read_exact(measurements).await {
421 Ok(len) => Ok(len),
422 Err(_) => self.stop(OverrunError),
423 }
424 }
425}
426
427impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
428 fn drop(&mut self) {
429 self.teardown_adc();
430 rcc::disable::<T>();
431 }
432}
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 93ec78548..90c6294d2 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,11 +1,22 @@
1use core::mem;
2use core::sync::atomic::{Ordering, compiler_fence};
3
1use super::blocking_delay_us; 4use super::blocking_delay_us;
2use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 5use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel};
6use crate::pac::adc::vals;
3use crate::peripherals::ADC1; 7use crate::peripherals::ADC1;
4use crate::time::Hertz; 8use crate::time::Hertz;
5use crate::{Peri, rcc}; 9use crate::{Peri, rcc};
6 10
7mod ringbuffered_v2; 11mod ringbuffered;
8pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; 12pub use ringbuffered::RingBufferedAdc;
13
14fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
15 r.sr().modify(|regs| {
16 regs.set_eoc(false);
17 regs.set_ovr(false);
18 });
19}
9 20
10/// Default VREF voltage used for sample conversion to millivolts. 21/// Default VREF voltage used for sample conversion to millivolts.
11pub const VREF_DEFAULT_MV: u32 = 3300; 22pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -112,6 +123,98 @@ where
112 } 123 }
113 } 124 }
114 125
126 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
127 ///
128 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
129 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
130 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
131 ///
132 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
133 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
134 ///
135 /// [`read`]: #method.read
136 pub fn into_ring_buffered<'a>(
137 self,
138 dma: Peri<'d, impl RxDma<T>>,
139 dma_buf: &'d mut [u16],
140 sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>,
141 ) -> RingBufferedAdc<'d, T> {
142 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
143
144 T::regs().cr2().modify(|reg| {
145 reg.set_adon(true);
146 });
147
148 // Check the sequence is long enough
149 T::regs().sqr1().modify(|r| {
150 r.set_l((sequence.len() - 1).try_into().unwrap());
151 });
152
153 for (i, (channel, sample_time)) in sequence.enumerate() {
154 // Set this GPIO as an analog input.
155 channel.setup();
156
157 // Set the channel in the right sequence field.
158 T::regs().sqr3().modify(|w| w.set_sq(i, channel.channel()));
159
160 Self::set_channel_sample_time(channel.channel(), sample_time);
161 }
162
163 compiler_fence(Ordering::SeqCst);
164
165 let r = T::regs();
166
167 // Clear all interrupts
168 r.sr().modify(|regs| {
169 regs.set_eoc(false);
170 regs.set_ovr(false);
171 regs.set_strt(false);
172 });
173
174 r.cr1().modify(|w| {
175 // Enable interrupt for end of conversion
176 w.set_eocie(true);
177 // Enable interrupt for overrun
178 w.set_ovrie(true);
179 // Scanning converisons of multiple channels
180 w.set_scan(true);
181 // Continuous conversion mode
182 w.set_discen(false);
183 });
184
185 r.cr2().modify(|w| {
186 // Enable DMA mode
187 w.set_dma(true);
188 // Enable continuous conversions
189 w.set_cont(true);
190 // DMA requests are issues as long as DMA=1 and data are converted.
191 w.set_dds(vals::Dds::CONTINUOUS);
192 // EOC flag is set at the end of each conversion.
193 w.set_eocs(vals::Eocs::EACH_CONVERSION);
194 });
195
196 // Don't disable the clock
197 mem::forget(self);
198
199 RingBufferedAdc::new(dma, dma_buf)
200 }
201
202 pub(super) fn start() {
203 // Begin ADC conversions
204 T::regs().cr2().modify(|reg| {
205 reg.set_adon(true);
206 reg.set_swstart(true);
207 });
208 }
209
210 pub(super) fn stop() {
211 // Stop ADC
212 T::regs().cr2().modify(|reg| {
213 // Stop ADC
214 reg.set_swstart(false);
215 });
216 }
217
115 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 218 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
116 self.sample_time = sample_time; 219 self.sample_time = sample_time;
117 } 220 }
@@ -198,6 +301,31 @@ where
198 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 301 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
199 } 302 }
200 } 303 }
304
305 pub(super) fn teardown_adc() {
306 let r = T::regs();
307
308 // Stop ADC
309 r.cr2().modify(|reg| {
310 // Stop ADC
311 reg.set_swstart(false);
312 // Stop ADC
313 reg.set_adon(false);
314 // Stop DMA
315 reg.set_dma(false);
316 });
317
318 r.cr1().modify(|w| {
319 // Disable interrupt for end of conversion
320 w.set_eocie(false);
321 // Disable interrupt for overrun
322 w.set_ovrie(false);
323 });
324
325 clear_interrupt_flags(r);
326
327 compiler_fence(Ordering::SeqCst);
328 }
201} 329}
202 330
203impl<'d, T: Instance> Drop for Adc<'d, T> { 331impl<'d, T: Instance> Drop for Adc<'d, T> {
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 47632263b..170b08a25 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -12,6 +12,13 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc};
12use super::{ 12use super::{
13 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, 13 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us,
14}; 14};
15
16#[cfg(any(adc_v3, adc_g0, adc_u0))]
17mod ringbuffered;
18
19#[cfg(any(adc_v3, adc_g0, adc_u0))]
20use ringbuffered::RingBufferedAdc;
21
15use crate::dma::Transfer; 22use crate::dma::Transfer;
16use crate::{Peri, pac, rcc}; 23use crate::{Peri, pac, rcc};
17 24
@@ -174,6 +181,38 @@ impl<'d, T: Instance> Adc<'d, T> {
174 blocking_delay_us(1); 181 blocking_delay_us(1);
175 } 182 }
176 183
184 #[cfg(any(adc_v3, adc_g0, adc_u0))]
185 pub(super) fn start() {
186 // Start adc conversion
187 T::regs().cr().modify(|reg| {
188 reg.set_adstart(true);
189 });
190 }
191
192 #[cfg(any(adc_v3, adc_g0, adc_u0))]
193 pub(super) fn stop() {
194 // Stop adc conversion
195 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
196 T::regs().cr().modify(|reg| {
197 reg.set_adstp(true);
198 });
199 while T::regs().cr().read().adstart() {}
200 }
201 }
202
203 #[cfg(any(adc_v3, adc_g0, adc_u0))]
204 pub(super) fn teardown_adc() {
205 //disable dma control
206 #[cfg(not(any(adc_g0, adc_u0)))]
207 T::regs().cfgr().modify(|reg| {
208 reg.set_dmaen(false);
209 });
210 #[cfg(any(adc_g0, adc_u0))]
211 T::regs().cfgr1().modify(|reg| {
212 reg.set_dmaen(false);
213 });
214 }
215
177 /// Initialize the ADC leaving any analog clock at reset value. 216 /// Initialize the ADC leaving any analog clock at reset value.
178 /// For G0 and WL, this is the async clock without prescaler. 217 /// For G0 and WL, this is the async clock without prescaler.
179 pub fn new(adc: Peri<'d, T>) -> Self { 218 pub fn new(adc: Peri<'d, T>) -> Self {
@@ -423,6 +462,9 @@ impl<'d, T: Instance> Adc<'d, T> {
423 "Asynchronous read sequence cannot be more than 16 in length" 462 "Asynchronous read sequence cannot be more than 16 in length"
424 ); 463 );
425 464
465 #[cfg(all(feature = "low-power", stm32wlex))]
466 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
467
426 // Ensure no conversions are ongoing and ADC is enabled. 468 // Ensure no conversions are ongoing and ADC is enabled.
427 Self::cancel_conversions(); 469 Self::cancel_conversions();
428 self.enable(); 470 self.enable();
@@ -559,6 +601,137 @@ impl<'d, T: Instance> Adc<'d, T> {
559 }); 601 });
560 } 602 }
561 603
604 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
605 ///
606 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
607 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
608 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
609 ///
610 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
611 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
612 ///
613 /// [`read`]: #method.read
614 #[cfg(any(adc_v3, adc_g0, adc_u0))]
615 pub fn into_ring_buffered<'a>(
616 &mut self,
617 dma: Peri<'a, impl RxDma<T>>,
618 dma_buf: &'a mut [u16],
619 sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>,
620 ) -> RingBufferedAdc<'a, T> {
621 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
622 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
623 assert!(
624 sequence.len() <= 16,
625 "Asynchronous read sequence cannot be more than 16 in length"
626 );
627 // reset conversions and enable the adc
628 Self::cancel_conversions();
629 self.enable();
630
631 //adc side setup
632
633 // Set sequence length
634 #[cfg(not(any(adc_g0, adc_u0)))]
635 T::regs().sqr1().modify(|w| {
636 w.set_l(sequence.len() as u8 - 1);
637 });
638
639 #[cfg(adc_g0)]
640 {
641 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new();
642
643 T::regs().chselr().write(|chselr| {
644 T::regs().smpr().write(|smpr| {
645 for (channel, sample_time) in sequence {
646 chselr.set_chsel(channel.channel.into(), true);
647 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
648 smpr.set_smpsel(channel.channel.into(), (i as u8).into());
649 } else {
650 smpr.set_sample_time(sample_times.len(), sample_time);
651 if let Err(_) = sample_times.push(sample_time) {
652 panic!(
653 "Implementation is limited to {} unique sample times among all channels.",
654 SAMPLE_TIMES_CAPACITY
655 );
656 }
657 }
658 }
659 })
660 });
661 }
662 #[cfg(not(adc_g0))]
663 {
664 #[cfg(adc_u0)]
665 let mut channel_mask = 0;
666
667 // Configure channels and ranks
668 for (_i, (channel, sample_time)) in sequence.enumerate() {
669 Self::configure_channel(channel, sample_time);
670
671 // Each channel is sampled according to sequence
672 #[cfg(not(any(adc_g0, adc_u0)))]
673 match _i {
674 0..=3 => {
675 T::regs().sqr1().modify(|w| {
676 w.set_sq(_i, channel.channel());
677 });
678 }
679 4..=8 => {
680 T::regs().sqr2().modify(|w| {
681 w.set_sq(_i - 4, channel.channel());
682 });
683 }
684 9..=13 => {
685 T::regs().sqr3().modify(|w| {
686 w.set_sq(_i - 9, channel.channel());
687 });
688 }
689 14..=15 => {
690 T::regs().sqr4().modify(|w| {
691 w.set_sq(_i - 14, channel.channel());
692 });
693 }
694 _ => unreachable!(),
695 }
696
697 #[cfg(adc_u0)]
698 {
699 channel_mask |= 1 << channel.channel();
700 }
701 }
702
703 // On G0 and U0 enabled channels are sampled from 0 to last channel.
704 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
705 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
706 #[cfg(adc_u0)]
707 T::regs().chselr().modify(|reg| {
708 reg.set_chsel(channel_mask);
709 });
710 }
711 // Set continuous mode with Circular dma.
712 // Clear overrun flag before starting transfer.
713 T::regs().isr().modify(|reg| {
714 reg.set_ovr(true);
715 });
716
717 #[cfg(not(any(adc_g0, adc_u0)))]
718 T::regs().cfgr().modify(|reg| {
719 reg.set_discen(false);
720 reg.set_cont(true);
721 reg.set_dmacfg(Dmacfg::CIRCULAR);
722 reg.set_dmaen(true);
723 });
724 #[cfg(any(adc_g0, adc_u0))]
725 T::regs().cfgr1().modify(|reg| {
726 reg.set_discen(false);
727 reg.set_cont(true);
728 reg.set_dmacfg(Dmacfg::CIRCULAR);
729 reg.set_dmaen(true);
730 });
731
732 RingBufferedAdc::new(dma, dma_buf)
733 }
734
562 #[cfg(not(adc_g0))] 735 #[cfg(not(adc_g0))]
563 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 736 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
564 // RM0492, RM0481, etc. 737 // RM0492, RM0481, etc.
diff --git a/embassy-stm32/src/backup_sram.rs b/embassy-stm32/src/backup_sram.rs
new file mode 100644
index 000000000..31b373c6c
--- /dev/null
+++ b/embassy-stm32/src/backup_sram.rs
@@ -0,0 +1,28 @@
1//! Battary backed SRAM
2
3use core::slice;
4
5use embassy_hal_internal::Peri;
6
7use crate::_generated::{BKPSRAM_BASE, BKPSRAM_SIZE};
8use crate::peripherals::BKPSRAM;
9
10/// Struct used to initilize backup sram
11pub struct BackupMemory {}
12
13impl BackupMemory {
14 /// Setup battery backed sram
15 ///
16 /// Returns slice to sram and whether the sram was retained
17 pub fn new(_backup_sram: Peri<'static, BKPSRAM>) -> (&'static mut [u8], bool) {
18 // Assert bksram has been enabled in rcc
19 assert!(crate::pac::PWR.bdcr().read().bren() == crate::pac::pwr::vals::Retention::PRESERVED);
20
21 unsafe {
22 (
23 slice::from_raw_parts_mut(BKPSRAM_BASE as *mut u8, BKPSRAM_SIZE),
24 critical_section::with(|_| crate::rcc::BKSRAM_RETAINED),
25 )
26 }
27 }
28}
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index e08349f02..4fe634ce4 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -360,6 +360,8 @@ pub struct FdCanConfig {
360 pub global_filter: GlobalFilter, 360 pub global_filter: GlobalFilter,
361 /// TX buffer mode (FIFO or priority queue) 361 /// TX buffer mode (FIFO or priority queue)
362 pub tx_buffer_mode: TxBufferMode, 362 pub tx_buffer_mode: TxBufferMode,
363 /// Automatic recovery from bus off state
364 pub automatic_bus_off_recovery: bool,
363} 365}
364 366
365impl FdCanConfig { 367impl FdCanConfig {
@@ -456,6 +458,16 @@ impl FdCanConfig {
456 self.tx_buffer_mode = txbm; 458 self.tx_buffer_mode = txbm;
457 self 459 self
458 } 460 }
461
462 /// Enables or disables automatic recovery from bus off state
463 ///
464 /// Automatic recovery is performed by clearing the INIT bit in the CCCR register if
465 /// the BO bit is active in the IR register in the IT0 interrupt.
466 #[inline]
467 pub const fn set_automatic_bus_off_recovery(mut self, enabled: bool) -> Self {
468 self.automatic_bus_off_recovery = enabled;
469 self
470 }
459} 471}
460 472
461impl Default for FdCanConfig { 473impl Default for FdCanConfig {
@@ -474,6 +486,7 @@ impl Default for FdCanConfig {
474 timestamp_source: TimestampSource::None, 486 timestamp_source: TimestampSource::None,
475 global_filter: GlobalFilter::default(), 487 global_filter: GlobalFilter::default(),
476 tx_buffer_mode: TxBufferMode::Priority, 488 tx_buffer_mode: TxBufferMode::Priority,
489 automatic_bus_off_recovery: true,
477 } 490 }
478 } 491 }
479} 492}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index a142a6d63..9883aff57 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -53,7 +53,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
53 regs.ir().write(|w| w.set_tefn(true)); 53 regs.ir().write(|w| w.set_tefn(true));
54 } 54 }
55 55
56 T::info().state.lock(|s| { 56 let recover_from_bo = T::info().state.lock(|s| {
57 let state = s.borrow_mut(); 57 let state = s.borrow_mut();
58 match &state.tx_mode { 58 match &state.tx_mode {
59 TxMode::NonBuffered(waker) => waker.wake(), 59 TxMode::NonBuffered(waker) => waker.wake(),
@@ -85,11 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
85 if ir.rfn(1) { 85 if ir.rfn(1) {
86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick); 86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
87 } 87 }
88
89 state.automatic_bus_off_recovery
88 }); 90 });
89 91
90 if ir.bo() { 92 if ir.bo() {
91 regs.ir().write(|w| w.set_bo(true)); 93 regs.ir().write(|w| w.set_bo(true));
92 if regs.psr().read().bo() { 94 if let Some(true) = recover_from_bo
95 && regs.psr().read().bo()
96 {
93 // Initiate bus-off recovery sequence by resetting CCCR.INIT 97 // Initiate bus-off recovery sequence by resetting CCCR.INIT
94 regs.cccr().modify(|w| w.set_init(false)); 98 regs.cccr().modify(|w| w.set_init(false));
95 } 99 }
@@ -263,7 +267,9 @@ impl<'d> CanConfigurator<'d> {
263 pub fn start(self, mode: OperatingMode) -> Can<'d> { 267 pub fn start(self, mode: OperatingMode) -> Can<'d> {
264 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); 268 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit);
265 self.info.state.lock(|s| { 269 self.info.state.lock(|s| {
266 s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; 270 let mut state = s.borrow_mut();
271 state.ns_per_timer_tick = ns_per_timer_tick;
272 state.automatic_bus_off_recovery = Some(self.config.automatic_bus_off_recovery);
267 }); 273 });
268 self.info.regs.into_mode(self.config, mode); 274 self.info.regs.into_mode(self.config, mode);
269 Can { 275 Can {
@@ -861,7 +867,7 @@ struct State {
861 sender_instance_count: usize, 867 sender_instance_count: usize,
862 tx_pin_port: Option<u8>, 868 tx_pin_port: Option<u8>,
863 rx_pin_port: Option<u8>, 869 rx_pin_port: Option<u8>,
864 870 automatic_bus_off_recovery: Option<bool>, // controlled by CanConfigurator::start()
865 pub err_waker: AtomicWaker, 871 pub err_waker: AtomicWaker,
866} 872}
867 873
@@ -876,6 +882,7 @@ impl State {
876 sender_instance_count: 0, 882 sender_instance_count: 0,
877 tx_pin_port: None, 883 tx_pin_port: None,
878 rx_pin_port: None, 884 rx_pin_port: None,
885 automatic_bus_off_recovery: None,
879 } 886 }
880 } 887 }
881} 888}
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index fd1682d2b..59a2cbcdb 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -121,17 +121,15 @@ impl<'d, T: Instance> DsiHost<'d, T> {
121 121
122 /// DCS or Generic short/long write command 122 /// DCS or Generic short/long write command
123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> { 123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
124 assert!(data.len() > 0); 124 match data.len() {
125 125 0 => self.short_write(channel_id, PacketType::DcsShortPktWriteP0, address, 0),
126 if data.len() == 1 { 126 1 => self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]),
127 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]) 127 _ => self.long_write(
128 } else {
129 self.long_write(
130 channel_id, 128 channel_id,
131 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well... 129 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
132 address, 130 address,
133 data, 131 data,
134 ) 132 ),
135 } 133 }
136 } 134 }
137 135
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 12600d4eb..2f5c3406a 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -71,7 +71,7 @@ unsafe fn on_irq() {
71 } 71 }
72 72
73 #[cfg(feature = "low-power")] 73 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq(); 74 crate::low_power::Executor::on_wakeup_irq();
75} 75}
76 76
77struct BitIter(u32); 77struct BitIter(u32);
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index cd23cda5c..b3281f2d5 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] 96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))]
97 { 97 {
98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; 98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
99 #[cfg(any(flash_l4, flash_l5))]
100 let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32;
99 101
100 #[cfg(flash_l4)] 102 #[cfg(flash_l4)]
101 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; 103 let (idx, bank) = if idx > (pgn - 1) {
104 (idx - pgn, true)
105 } else {
106 (idx, false)
107 };
102 108
103 #[cfg(flash_l5)] 109 #[cfg(flash_l5)]
104 let (idx, bank) = if pac::FLASH.optr().read().dbank() { 110 let (idx, bank) = if pac::FLASH.optr().read().dbank() {
105 if idx > 255 { 111 if idx > (pgn - 1) {
106 (idx - 256, Some(true)) 112 (idx - pgn, Some(true))
107 } else { 113 } else {
108 (idx, Some(false)) 114 (idx, Some(false))
109 } 115 }
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index 8ecfbc522..a7c6c90bb 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -236,6 +236,42 @@ impl<'d, T: Instance> Fmc<'d, T> {
236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) 236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
237 ] 237 ]
238 )); 238 ));
239
240 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank1: (
241 bank: stm32_fmc::SdramTargetBank::Bank1,
242 addr: [
243 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
244 ],
245 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
246 d: [
247 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
248 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
249 ],
250 nbl: [
251 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
252 ],
253 ctrl: [
254 (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
255 ]
256 ));
257
258 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank2: (
259 bank: stm32_fmc::SdramTargetBank::Bank2,
260 addr: [
261 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
262 ],
263 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
264 d: [
265 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
266 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
267 ],
268 nbl: [
269 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
270 ],
271 ctrl: [
272 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
273 ]
274 ));
239} 275}
240 276
241trait SealedInstance: crate::rcc::RccPeripheral { 277trait SealedInstance: crate::rcc::RccPeripheral {
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 6fece5eb2..6c6807479 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,6 +10,7 @@ pub use traits::Instance;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::rcc; 11use crate::rcc;
12use crate::time::Hertz; 12use crate::time::Hertz;
13pub use crate::timer::simple_pwm::PwmPinConfig;
13 14
14/// HRTIM burst controller instance. 15/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 16pub struct BurstController<T: Instance> {
@@ -73,7 +74,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
73} 74}
74 75
75macro_rules! advanced_channel_impl { 76macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 77 ($new_chx:ident, $new_chx_with_config:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { 78 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 79 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 80 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
@@ -86,6 +87,21 @@ macro_rules! advanced_channel_impl {
86 phantom: PhantomData, 87 phantom: PhantomData,
87 } 88 }
88 } 89 }
90
91 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with a specific configuration.")]
92 pub fn $new_chx_with_config(
93 pin: Peri<'d, impl $pin_trait<T>>,
94 pin_config: PwmPinConfig,
95 ) -> Self {
96 critical_section::with(|_| {
97 pin.set_low();
98 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
99 });
100 PwmPin {
101 _pin: pin.into(),
102 phantom: PhantomData,
103 }
104 }
89 } 105 }
90 106
91 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { 107 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
@@ -100,6 +116,21 @@ macro_rules! advanced_channel_impl {
100 phantom: PhantomData, 116 phantom: PhantomData,
101 } 117 }
102 } 118 }
119
120 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance with a specific configuration.")]
121 pub fn $new_chx_with_config(
122 pin: Peri<'d, impl $complementary_pin_trait<T>>,
123 pin_config: PwmPinConfig,
124 ) -> Self {
125 critical_section::with(|_| {
126 pin.set_low();
127 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
128 });
129 ComplementaryPwmPin {
130 _pin: pin.into(),
131 phantom: PhantomData,
132 }
133 }
103 } 134 }
104 135
105 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> { 136 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> {
@@ -111,13 +142,55 @@ macro_rules! advanced_channel_impl {
111 }; 142 };
112} 143}
113 144
114advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); 145advanced_channel_impl!(
115advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); 146 new_cha,
116advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); 147 new_cha_with_config,
117advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); 148 ChA,
118advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); 149 0,
150 ChannelAPin,
151 ChannelAComplementaryPin
152);
153advanced_channel_impl!(
154 new_chb,
155 new_chb_with_config,
156 ChB,
157 1,
158 ChannelBPin,
159 ChannelBComplementaryPin
160);
161advanced_channel_impl!(
162 new_chc,
163 new_chc_with_config,
164 ChC,
165 2,
166 ChannelCPin,
167 ChannelCComplementaryPin
168);
169advanced_channel_impl!(
170 new_chd,
171 new_chd_with_config,
172 ChD,
173 3,
174 ChannelDPin,
175 ChannelDComplementaryPin
176);
177advanced_channel_impl!(
178 new_che,
179 new_che_with_config,
180 ChE,
181 4,
182 ChannelEPin,
183 ChannelEComplementaryPin
184);
119#[cfg(hrtim_v2)] 185#[cfg(hrtim_v2)]
120advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); 186advanced_channel_impl!(
187 new_chf,
188 new_chf_with_config,
189 ChF,
190 5,
191 ChannelFPin,
192 ChannelFComplementaryPin
193);
121 194
122/// Struct used to divide a high resolution timer into multiple channels 195/// Struct used to divide a high resolution timer into multiple channels
123pub struct AdvancedPwm<'d, T: Instance> { 196pub struct AdvancedPwm<'d, T: Instance> {
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs
index 4e3b736c7..74fac14b2 100644
--- a/embassy-stm32/src/i2c/config.rs
+++ b/embassy-stm32/src/i2c/config.rs
@@ -4,7 +4,7 @@ use crate::gpio::{AfType, OutputType, Speed};
4use crate::time::Hertz; 4use crate::time::Hertz;
5 5
6#[repr(u8)] 6#[repr(u8)]
7#[derive(Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Bits of the I2C OA2 register to mask out. 9/// Bits of the I2C OA2 register to mask out.
10pub enum AddrMask { 10pub enum AddrMask {
@@ -60,7 +60,7 @@ impl Address {
60 } 60 }
61} 61}
62 62
63#[derive(Copy, Clone)] 63#[derive(Debug, Copy, Clone)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65/// The second Own Address register. 65/// The second Own Address register.
66pub struct OA2 { 66pub struct OA2 {
@@ -70,7 +70,7 @@ pub struct OA2 {
70 pub mask: AddrMask, 70 pub mask: AddrMask,
71} 71}
72 72
73#[derive(Copy, Clone)] 73#[derive(Debug, Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// The Own Address(es) of the I2C peripheral. 75/// The Own Address(es) of the I2C peripheral.
76pub enum OwnAddresses { 76pub enum OwnAddresses {
@@ -88,7 +88,7 @@ pub enum OwnAddresses {
88} 88}
89 89
90/// Slave Configuration 90/// Slave Configuration
91#[derive(Copy, Clone)] 91#[derive(Debug, Copy, Clone)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))] 92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct SlaveAddrConfig { 93pub struct SlaveAddrConfig {
94 /// Target Address(es) 94 /// Target Address(es)
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index f4bf55d34..ee60c3f44 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -219,6 +219,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
219 sda, 219 sda,
220 }, 220 },
221 }; 221 };
222
222 this.enable_and_init(config); 223 this.enable_and_init(config);
223 224
224 this 225 this
@@ -437,15 +438,15 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
437 438
438/// Frame type in I2C transaction. 439/// Frame type in I2C transaction.
439/// 440///
440/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST 441/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST
441/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an 442/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
442/// ACK or NACK after the last byte received. 443/// ACK or NACK after the last byte received.
443/// 444///
444/// For write operations, the following options are identical because they differ only in the (N)ACK 445/// For write operations, the following options are identical because they differ only in the (N)ACK
445/// treatment relevant for read operations: 446/// treatment relevant for read operations:
446/// 447///
447/// - `FirstFrame` and `FirstAndNextFrame` 448/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes
448/// - `NextFrame` and `LastFrameNoStop` 449/// - `NextFrame` and `LastFrameNoStop` behave identically for writes
449/// 450///
450/// Abbreviations used below: 451/// Abbreviations used below:
451/// 452///
@@ -474,7 +475,7 @@ enum FrameOptions {
474 475
475#[allow(dead_code)] 476#[allow(dead_code)]
476impl FrameOptions { 477impl FrameOptions {
477 /// Sends start or repeated start condition before transfer. 478 /// Returns true if a start or repeated start condition should be generated before this operation.
478 fn send_start(self) -> bool { 479 fn send_start(self) -> bool {
479 match self { 480 match self {
480 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, 481 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
@@ -482,7 +483,7 @@ impl FrameOptions {
482 } 483 }
483 } 484 }
484 485
485 /// Sends stop condition after transfer. 486 /// Returns true if a stop condition should be generated after this operation.
486 fn send_stop(self) -> bool { 487 fn send_stop(self) -> bool {
487 match self { 488 match self {
488 Self::FirstAndLastFrame | Self::LastFrame => true, 489 Self::FirstAndLastFrame | Self::LastFrame => true,
@@ -490,7 +491,10 @@ impl FrameOptions {
490 } 491 }
491 } 492 }
492 493
493 /// Sends NACK after last byte received, indicating end of read operation. 494 /// Returns true if NACK should be sent after the last byte received in a read operation.
495 ///
496 /// This signals the end of a read sequence and releases the bus for the master's
497 /// next transmission (or stop condition).
494 fn send_nack(self) -> bool { 498 fn send_nack(self) -> bool {
495 match self { 499 match self {
496 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, 500 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
@@ -499,24 +503,44 @@ impl FrameOptions {
499 } 503 }
500} 504}
501 505
502/// Iterates over operations in transaction. 506/// Analyzes I2C transaction operations and assigns appropriate frame to each.
507///
508/// This function processes a sequence of I2C operations and determines the correct
509/// frame configuration for each operation to ensure proper I2C protocol compliance.
510/// It handles the complex logic of:
511///
512/// - Generating start conditions for the first operation of each type (read/write)
513/// - Generating stop conditions for the final operation in the entire transaction
514/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads
515/// - Ensuring proper bus handoff between different operation types
516///
517/// **Transaction Contract Compliance:**
518/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract,
519/// where consecutive operations of the same type are logically merged while maintaining
520/// proper protocol boundaries.
503/// 521///
504/// Returns necessary frame options for each operation to uphold the [transaction contract] and have 522/// **Error Handling:**
505/// the right start/stop/(N)ACK conditions on the wire. 523/// Returns an error if any read operation has an empty buffer, as this would create
524/// an invalid I2C transaction that could halt mid-execution.
525///
526/// # Arguments
527/// * `operations` - Mutable slice of I2C operations from embedded-hal
528///
529/// # Returns
530/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid
506/// 531///
507/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
508#[allow(dead_code)] 532#[allow(dead_code)]
509fn operation_frames<'a, 'b: 'a>( 533fn operation_frames<'a, 'b: 'a>(
510 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 534 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
511) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { 535) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
512 use embedded_hal_1::i2c::Operation::{Read, Write}; 536 use embedded_hal_1::i2c::Operation::{Read, Write};
513 537
514 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an 538 // Validate that no read operations have empty buffers before starting the transaction.
515 // error in the middle of the transaction. 539 // Empty read operations would risk halting with an error mid-transaction.
516 // 540 //
517 // In principle, we could allow empty read frames within consecutive read operations, as long as 541 // Note: We could theoretically allow empty read operations within consecutive read
518 // at least one byte remains in the final (merged) read operation, but that makes the logic more 542 // sequences as long as the final merged read has at least one byte, but this would
519 // complicated and error-prone. 543 // complicate the logic significantly and create error-prone edge cases.
520 if operations.iter().any(|op| match op { 544 if operations.iter().any(|op| match op {
521 Read(read) => read.is_empty(), 545 Read(read) => read.is_empty(),
522 Write(_) => false, 546 Write(_) => false,
@@ -525,46 +549,52 @@ fn operation_frames<'a, 'b: 'a>(
525 } 549 }
526 550
527 let mut operations = operations.iter_mut().peekable(); 551 let mut operations = operations.iter_mut().peekable();
528 552 let mut next_first_operation = true;
529 let mut next_first_frame = true;
530 553
531 Ok(iter::from_fn(move || { 554 Ok(iter::from_fn(move || {
532 let op = operations.next()?; 555 let current_op = operations.next()?;
533 556
534 // Is `op` first frame of its type? 557 // Determine if this is the first operation of its type (read or write)
535 let first_frame = next_first_frame; 558 let is_first_of_type = next_first_operation;
536 let next_op = operations.peek(); 559 let next_op = operations.peek();
537 560
538 // Get appropriate frame options as combination of the following properties: 561 // Compute the appropriate frame based on three key properties:
539 // 562 //
540 // - For each first operation of its type, generate a (repeated) start condition. 563 // 1. **Start Condition**: Generate (repeated) start for first operation of each type
541 // - For the last operation overall in the entire transaction, generate a stop condition. 564 // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction
542 // - For read operations, check the next operation: if it is also a read operation, we merge 565 // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the
543 // these and send ACK for all bytes in the current operation; send NACK only for the final 566 // sequence, or NACK for the final read in a sequence (before write or transaction end)
544 // read operation's last byte (before write or end of entire transaction) to indicate last
545 // byte read and release the bus for transmission of the bus master's next byte (or stop).
546 // 567 //
547 // We check the third property unconditionally, i.e. even for write opeartions. This is okay 568 // The third property is checked for all operations since the resulting frame
548 // because the resulting frame options are identical for write operations. 569 // configurations are identical for write operations regardless of ACK/NACK treatment.
549 let frame = match (first_frame, next_op) { 570 let frame = match (is_first_of_type, next_op) {
571 // First operation of type, and it's also the final operation overall
550 (true, None) => FrameOptions::FirstAndLastFrame, 572 (true, None) => FrameOptions::FirstAndLastFrame,
573 // First operation of type, next operation is also a read (continue read sequence)
551 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, 574 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
575 // First operation of type, next operation is write (end current sequence)
552 (true, Some(Write(_))) => FrameOptions::FirstFrame, 576 (true, Some(Write(_))) => FrameOptions::FirstFrame,
553 // 577
578 // Continuation operation, and it's the final operation overall
554 (false, None) => FrameOptions::LastFrame, 579 (false, None) => FrameOptions::LastFrame,
580 // Continuation operation, next operation is also a read (continue read sequence)
555 (false, Some(Read(_))) => FrameOptions::NextFrame, 581 (false, Some(Read(_))) => FrameOptions::NextFrame,
582 // Continuation operation, next operation is write (end current sequence, no stop)
556 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, 583 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
557 }; 584 };
558 585
559 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at 586 // Pre-calculate whether the next operation will be the first of its type.
560 // the beginning of the loop because we hand out `op` as iterator value and cannot access it 587 // This is done here because we consume `current_op` as the iterator value
561 // anymore in the next iteration. 588 // and cannot access it in the next iteration.
562 next_first_frame = match (&op, next_op) { 589 next_first_operation = match (&current_op, next_op) {
590 // No next operation
563 (_, None) => false, 591 (_, None) => false,
592 // Operation type changes: next will be first of its type
564 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, 593 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
594 // Operation type continues: next will not be first of its type
565 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, 595 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
566 }; 596 };
567 597
568 Some((op, frame)) 598 Some((current_op, frame))
569 })) 599 }))
570} 600}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index e6b6c7c42..128a58db7 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -30,6 +30,7 @@ use crate::pac::i2c;
30// hit a case like this! 30// hit a case like this!
31pub unsafe fn on_interrupt<T: Instance>() { 31pub unsafe fn on_interrupt<T: Instance>() {
32 let regs = T::info().regs; 32 let regs = T::info().regs;
33 trace!("I2C interrupt triggered");
33 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 34 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
34 // other stuff, so we wake the task on every interrupt. 35 // other stuff, so we wake the task on every interrupt.
35 T::state().waker.wake(); 36 T::state().waker.wake();
@@ -92,6 +93,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
92 self.info.regs.cr1().modify(|reg| { 93 self.info.regs.cr1().modify(|reg| {
93 reg.set_pe(true); 94 reg.set_pe(true);
94 }); 95 });
96 trace!("i2c v1 init complete");
95 } 97 }
96 98
97 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> { 99 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
@@ -151,7 +153,13 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
151 Ok(sr1) 153 Ok(sr1)
152 } 154 }
153 155
154 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { 156 fn write_bytes(
157 &mut self,
158 address: u8,
159 write_buffer: &[u8],
160 timeout: Timeout,
161 frame: FrameOptions,
162 ) -> Result<(), Error> {
155 if frame.send_start() { 163 if frame.send_start() {
156 // Send a START condition 164 // Send a START condition
157 165
@@ -170,7 +178,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
170 } 178 }
171 179
172 // Set up current address we're trying to talk to 180 // Set up current address we're trying to talk to
173 self.info.regs.dr().write(|reg| reg.set_dr(addr << 1)); 181 self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
174 182
175 // Wait until address was sent 183 // Wait until address was sent
176 // Wait for the address to be acknowledged 184 // Wait for the address to be acknowledged
@@ -184,7 +192,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
184 } 192 }
185 193
186 // Send bytes 194 // Send bytes
187 for c in bytes { 195 for c in write_buffer {
188 self.send_byte(*c, timeout)?; 196 self.send_byte(*c, timeout)?;
189 } 197 }
190 198
@@ -236,12 +244,12 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
236 244
237 fn blocking_read_timeout( 245 fn blocking_read_timeout(
238 &mut self, 246 &mut self,
239 addr: u8, 247 address: u8,
240 buffer: &mut [u8], 248 read_buffer: &mut [u8],
241 timeout: Timeout, 249 timeout: Timeout,
242 frame: FrameOptions, 250 frame: FrameOptions,
243 ) -> Result<(), Error> { 251 ) -> Result<(), Error> {
244 let Some((last, buffer)) = buffer.split_last_mut() else { 252 let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else {
245 return Err(Error::Overrun); 253 return Err(Error::Overrun);
246 }; 254 };
247 255
@@ -263,7 +271,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
263 } 271 }
264 272
265 // Set up current address we're trying to talk to 273 // Set up current address we're trying to talk to
266 self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1)); 274 self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1));
267 275
268 // Wait until address was sent 276 // Wait until address was sent
269 // Wait for the address to be acknowledged 277 // Wait for the address to be acknowledged
@@ -276,7 +284,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
276 } 284 }
277 285
278 // Receive bytes into buffer 286 // Receive bytes into buffer
279 for c in buffer { 287 for c in read_buffer {
280 *c = self.recv_byte(timeout)?; 288 *c = self.recv_byte(timeout)?;
281 } 289 }
282 290
@@ -291,37 +299,42 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
291 }); 299 });
292 300
293 // Receive last byte 301 // Receive last byte
294 *last = self.recv_byte(timeout)?; 302 *last_byte = self.recv_byte(timeout)?;
295 303
296 // Fallthrough is success 304 // Fallthrough is success
297 Ok(()) 305 Ok(())
298 } 306 }
299 307
300 /// Blocking read. 308 /// Blocking read.
301 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 309 pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
302 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) 310 self.blocking_read_timeout(address, read_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)
303 } 311 }
304 312
305 /// Blocking write. 313 /// Blocking write.
306 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 314 pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
307 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; 315 self.write_bytes(address, write_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)?;
308 316
309 // Fallthrough is success 317 // Fallthrough is success
310 Ok(()) 318 Ok(())
311 } 319 }
312 320
313 /// Blocking write, restart, read. 321 /// Blocking write, restart, read.
314 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 322 pub fn blocking_write_read(
323 &mut self,
324 address: u8,
325 write_buffer: &[u8],
326 read_buffer: &mut [u8],
327 ) -> Result<(), Error> {
315 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 328 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
316 // stop condition below. 329 // stop condition below.
317 if read.is_empty() { 330 if read_buffer.is_empty() {
318 return Err(Error::Overrun); 331 return Err(Error::Overrun);
319 } 332 }
320 333
321 let timeout = self.timeout(); 334 let timeout = self.timeout();
322 335
323 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; 336 self.write_bytes(address, write_buffer, timeout, FrameOptions::FirstFrame)?;
324 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; 337 self.blocking_read_timeout(address, read_buffer, timeout, FrameOptions::FirstAndLastFrame)?;
325 338
326 Ok(()) 339 Ok(())
327 } 340 }
@@ -331,32 +344,43 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
331 /// Consecutive operations of same type are merged. See [transaction contract] for details. 344 /// Consecutive operations of same type are merged. See [transaction contract] for details.
332 /// 345 ///
333 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 346 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
334 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 347 pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
335 let timeout = self.timeout(); 348 let timeout = self.timeout();
336 349
337 for (op, frame) in operation_frames(operations)? { 350 for (op, frame) in operation_frames(operations)? {
338 match op { 351 match op {
339 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, 352 Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, frame)?,
340 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, 353 Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, frame)?,
341 } 354 }
342 } 355 }
343 356
344 Ok(()) 357 Ok(())
345 } 358 }
346 359
347 // Async 360 /// Can be used by both blocking and async implementations
348
349 #[inline] // pretty sure this should always be inlined 361 #[inline] // pretty sure this should always be inlined
350 fn enable_interrupts(info: &'static Info) -> () { 362 fn enable_interrupts(info: &'static Info) {
351 info.regs.cr2().modify(|w| { 363 // The interrupt handler disables interrupts globally, so we need to re-enable them
352 w.set_iterren(true); 364 // This must be done in a critical section to avoid races
353 w.set_itevten(true); 365 critical_section::with(|_| {
366 info.regs.cr2().modify(|w| {
367 w.set_iterren(true);
368 w.set_itevten(true);
369 });
354 }); 370 });
355 } 371 }
372
373 /// Can be used by both blocking and async implementations
374 fn clear_stop_flag(info: &'static Info) {
375 trace!("I2C slave: clearing STOPF flag (v1 sequence)");
376 // v1 requires: READ SR1 then WRITE CR1 to clear STOPF
377 let _ = info.regs.sr1().read();
378 info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF
379 }
356} 380}
357 381
358impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 382impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
359 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { 383 async fn write_frame(&mut self, address: u8, write_buffer: &[u8], frame: FrameOptions) -> Result<(), Error> {
360 self.info.regs.cr2().modify(|w| { 384 self.info.regs.cr2().modify(|w| {
361 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 385 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
362 // reception. 386 // reception.
@@ -439,7 +463,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
439 // this address from the memory after each TxE event. 463 // this address from the memory after each TxE event.
440 let dst = self.info.regs.dr().as_ptr() as *mut u8; 464 let dst = self.info.regs.dr().as_ptr() as *mut u8;
441 465
442 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 466 self.tx_dma
467 .as_mut()
468 .unwrap()
469 .write(write_buffer, dst, Default::default())
443 }; 470 };
444 471
445 // Wait for bytes to be sent, or an error to occur. 472 // Wait for bytes to be sent, or an error to occur.
@@ -501,28 +528,28 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
501 } 528 }
502 529
503 /// Write. 530 /// Write.
504 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 531 pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
505 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 532 self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame)
506 .await?; 533 .await?;
507 534
508 Ok(()) 535 Ok(())
509 } 536 }
510 537
511 /// Read. 538 /// Read.
512 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 539 pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
513 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 540 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
514 .await?; 541 .await?;
515 542
516 Ok(()) 543 Ok(())
517 } 544 }
518 545
519 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { 546 async fn read_frame(&mut self, address: u8, read_buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
520 if buffer.is_empty() { 547 if read_buffer.is_empty() {
521 return Err(Error::Overrun); 548 return Err(Error::Overrun);
522 } 549 }
523 550
524 // Some branches below depend on whether the buffer contains only a single byte. 551 // Some branches below depend on whether the buffer contains only a single byte.
525 let single_byte = buffer.len() == 1; 552 let single_byte = read_buffer.len() == 1;
526 553
527 self.info.regs.cr2().modify(|w| { 554 self.info.regs.cr2().modify(|w| {
528 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 555 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
@@ -612,7 +639,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
612 self.info.regs.sr2().read(); 639 self.info.regs.sr2().read();
613 } else { 640 } else {
614 // Before starting reception of single byte (but without START condition, i.e. in case 641 // Before starting reception of single byte (but without START condition, i.e. in case
615 // of continued frame), program NACK to emit at end of this byte. 642 // of merged operations), program NACK to emit at end of this byte.
616 if frame.send_nack() && single_byte { 643 if frame.send_nack() && single_byte {
617 self.info.regs.cr1().modify(|w| { 644 self.info.regs.cr1().modify(|w| {
618 w.set_ack(false); 645 w.set_ack(false);
@@ -634,7 +661,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
634 // from this address from the memory after each RxE event. 661 // from this address from the memory after each RxE event.
635 let src = self.info.regs.dr().as_ptr() as *mut u8; 662 let src = self.info.regs.dr().as_ptr() as *mut u8;
636 663
637 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 664 self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default())
638 }; 665 };
639 666
640 // Wait for bytes to be received, or an error to occur. 667 // Wait for bytes to be received, or an error to occur.
@@ -673,15 +700,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
673 } 700 }
674 701
675 /// Write, restart, read. 702 /// Write, restart, read.
676 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 703 pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> {
677 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 704 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
678 // stop condition below. 705 // stop condition below.
679 if read.is_empty() { 706 if read_buffer.is_empty() {
680 return Err(Error::Overrun); 707 return Err(Error::Overrun);
681 } 708 }
682 709
683 self.write_frame(address, write, FrameOptions::FirstFrame).await?; 710 self.write_frame(address, write_buffer, FrameOptions::FirstFrame)
684 self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await 711 .await?;
712 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
713 .await
685 } 714 }
686 715
687 /// Transaction with operations. 716 /// Transaction with operations.
@@ -689,11 +718,11 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
689 /// Consecutive operations of same type are merged. See [transaction contract] for details. 718 /// Consecutive operations of same type are merged. See [transaction contract] for details.
690 /// 719 ///
691 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 720 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
692 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 721 pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
693 for (op, frame) in operation_frames(operations)? { 722 for (op, frame) in operation_frames(operations)? {
694 match op { 723 match op {
695 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 724 Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?,
696 Operation::Write(write) => self.write_frame(addr, write, frame).await?, 725 Operation::Write(write_buffer) => self.write_frame(address, write_buffer, frame).await?,
697 } 726 }
698 } 727 }
699 728
@@ -729,12 +758,956 @@ impl Duty {
729 } 758 }
730} 759}
731 760
761/// Result of attempting to send a byte in slave transmitter mode
762#[derive(Debug, PartialEq)]
763enum TransmitResult {
764 /// Byte sent and ACKed by master - continue transmission
765 Acknowledged,
766 /// Byte sent but NACKed by master - normal end of read transaction
767 NotAcknowledged,
768 /// STOP condition detected - master terminated transaction
769 Stopped,
770 /// RESTART condition detected - master starting new transaction
771 Restarted,
772}
773
774/// Result of attempting to receive a byte in slave receiver mode
775#[derive(Debug, PartialEq)]
776enum ReceiveResult {
777 /// Data byte successfully received
778 Data(u8),
779 /// STOP condition detected - end of write transaction
780 Stopped,
781 /// RESTART condition detected - master starting new transaction
782 Restarted,
783}
784
785/// Enumeration of slave transaction termination conditions
786#[derive(Debug, Clone, Copy, PartialEq)]
787#[cfg_attr(feature = "defmt", derive(defmt::Format))]
788enum SlaveTermination {
789 /// STOP condition received - normal end of transaction
790 Stop,
791 /// RESTART condition received - master starting new transaction
792 Restart,
793 /// NACK received - normal end of read transaction
794 Nack,
795}
796
797impl<'d, M: PeriMode> I2c<'d, M, Master> {
798 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
799 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
800 let mut slave = I2c {
801 info: self.info,
802 state: self.state,
803 kernel_clock: self.kernel_clock,
804 tx_dma: self.tx_dma.take(), // Use take() to move ownership
805 rx_dma: self.rx_dma.take(), // Use take() to move ownership
806 #[cfg(feature = "time")]
807 timeout: self.timeout,
808 _phantom: PhantomData,
809 _phantom2: PhantomData,
810 _drop_guard: self._drop_guard, // Move the drop guard
811 };
812 slave.init_slave(slave_addr_config);
813 slave
814 }
815}
816
817// Address configuration methods
818impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
819 /// Initialize slave mode with address configuration
820 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
821 trace!("I2C slave: initializing with config={:?}", config);
822
823 // Disable peripheral for configuration
824 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
825
826 // Configure slave addresses
827 self.apply_address_configuration(config);
828
829 // Enable peripheral with slave settings
830 self.info.regs.cr1().modify(|reg| {
831 reg.set_pe(true);
832 reg.set_ack(true); // Enable acknowledgment for slave mode
833 reg.set_nostretch(false); // Allow clock stretching for processing time
834 });
835
836 trace!("I2C slave: initialization complete");
837 }
838
839 /// Apply the complete address configuration for slave mode
840 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
841 match config.addr {
842 OwnAddresses::OA1(addr) => {
843 self.configure_primary_address(addr);
844 self.disable_secondary_address();
845 }
846 OwnAddresses::OA2(oa2) => {
847 self.configure_default_primary_address();
848 self.configure_secondary_address(oa2.addr); // v1 ignores mask
849 }
850 OwnAddresses::Both { oa1, oa2 } => {
851 self.configure_primary_address(oa1);
852 self.configure_secondary_address(oa2.addr); // v1 ignores mask
853 }
854 }
855
856 // Configure general call detection
857 if config.general_call {
858 self.info.regs.cr1().modify(|w| w.set_engc(true));
859 }
860 }
861
862 /// Configure the primary address (OA1) register
863 fn configure_primary_address(&mut self, addr: Address) {
864 match addr {
865 Address::SevenBit(addr) => {
866 self.info.regs.oar1().write(|reg| {
867 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
868 reg.set_add(hw_addr);
869 reg.set_addmode(i2c::vals::Addmode::BIT7);
870 });
871 }
872 Address::TenBit(addr) => {
873 self.info.regs.oar1().write(|reg| {
874 reg.set_add(addr);
875 reg.set_addmode(i2c::vals::Addmode::BIT10);
876 });
877 }
878 }
879
880 // Set required bit 14 as per reference manual
881 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
882 }
883
884 /// Configure the secondary address (OA2) register
885 fn configure_secondary_address(&mut self, addr: u8) {
886 self.info.regs.oar2().write(|reg| {
887 reg.set_add2(addr);
888 reg.set_endual(i2c::vals::Endual::DUAL);
889 });
890 }
891
892 /// Set a default primary address when using OA2-only mode
893 fn configure_default_primary_address(&mut self) {
894 self.info.regs.oar1().write(|reg| {
895 reg.set_add(0); // Reserved address, safe to use
896 reg.set_addmode(i2c::vals::Addmode::BIT7);
897 });
898 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
899 }
900
901 /// Disable secondary address when not needed
902 fn disable_secondary_address(&mut self) {
903 self.info.regs.oar2().write(|reg| {
904 reg.set_endual(i2c::vals::Endual::SINGLE);
905 });
906 }
907}
908
909impl<'d, M: PeriMode> I2c<'d, M, MultiMaster> {
910 /// Listen for incoming I2C address match and return the command type
911 ///
912 /// This method blocks until the slave address is matched by a master.
913 /// Returns the command type (Read/Write) and the matched address.
914 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
915 trace!("I2C slave: starting blocking listen for address match");
916 let result = self.blocking_listen_with_timeout(self.timeout());
917 trace!("I2C slave: blocking listen complete, result={:?}", result);
918 result
919 }
920
921 /// Respond to a master read request by transmitting data
922 ///
923 /// Sends the provided data to the master. If the master requests more bytes
924 /// than available, padding bytes (0x00) are sent until the master terminates
925 /// the transaction with NACK.
926 ///
927 /// Returns the total number of bytes transmitted (including padding).
928 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
929 trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len());
930
931 if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? {
932 trace!("I2C slave: zero-length read detected");
933 return Ok(zero_length_result);
934 }
935
936 let result = self.transmit_to_master(data, self.timeout());
937 trace!("I2C slave: blocking respond_to_read complete, result={:?}", result);
938 result
939 }
940
941 /// Respond to a master write request by receiving data
942 ///
943 /// Receives data from the master into the provided buffer. If the master
944 /// sends more bytes than the buffer can hold, excess bytes are acknowledged
945 /// but discarded.
946 ///
947 /// Returns the number of bytes stored in the buffer (not total received).
948 pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
949 trace!(
950 "I2C slave: starting blocking respond_to_write, buffer_len={}",
951 buffer.len()
952 );
953 let result = self.receive_from_master(buffer, self.timeout());
954 trace!("I2C slave: blocking respond_to_write complete, result={:?}", result);
955 result
956 }
957
958 // Private implementation methods
959
960 /// Wait for address match and determine transaction type
961 fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result<SlaveCommand, Error> {
962 // Ensure interrupts are disabled for blocking operation
963 self.disable_i2c_interrupts();
964
965 // Wait for address match (ADDR flag)
966 loop {
967 let sr1 = Self::read_status_and_handle_errors(self.info)?;
968
969 if sr1.addr() {
970 // Address matched - read SR2 to get direction and clear ADDR flag
971 let sr2 = self.info.regs.sr2().read();
972 let direction = if sr2.tra() {
973 SlaveCommandKind::Read
974 } else {
975 SlaveCommandKind::Write
976 };
977
978 // Use the static method instead of the instance method
979 let matched_address = Self::decode_matched_address(sr2, self.info)?;
980 trace!(
981 "I2C slave: address matched, direction={:?}, addr={:?}",
982 direction, matched_address
983 );
984
985 return Ok(SlaveCommand {
986 kind: direction,
987 address: matched_address,
988 });
989 }
990
991 timeout.check()?;
992 }
993 }
994
995 /// Transmit data to master in response to read request
996 fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> {
997 let mut bytes_transmitted = 0;
998 let mut padding_count = 0;
999
1000 loop {
1001 let byte_to_send = if bytes_transmitted < data.len() {
1002 data[bytes_transmitted]
1003 } else {
1004 padding_count += 1;
1005 0x00 // Send padding bytes when data is exhausted
1006 };
1007
1008 match self.transmit_byte(byte_to_send, timeout)? {
1009 TransmitResult::Acknowledged => {
1010 bytes_transmitted += 1;
1011 }
1012 TransmitResult::NotAcknowledged => {
1013 bytes_transmitted += 1; // Count the NACKed byte
1014 break;
1015 }
1016 TransmitResult::Stopped | TransmitResult::Restarted => {
1017 break;
1018 }
1019 }
1020 }
1021
1022 if padding_count > 0 {
1023 trace!(
1024 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1025 data.len(),
1026 padding_count,
1027 bytes_transmitted
1028 );
1029 }
1030
1031 Ok(bytes_transmitted)
1032 }
1033
1034 /// Receive data from master during write request
1035 fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
1036 let mut bytes_stored = 0;
1037
1038 // Receive bytes that fit in buffer
1039 while bytes_stored < buffer.len() {
1040 match self.receive_byte(timeout)? {
1041 ReceiveResult::Data(byte) => {
1042 buffer[bytes_stored] = byte;
1043 bytes_stored += 1;
1044 }
1045 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1046 return Ok(bytes_stored);
1047 }
1048 }
1049 }
1050
1051 // Handle buffer overflow by discarding excess bytes
1052 if bytes_stored == buffer.len() {
1053 trace!("I2C slave: buffer full, discarding excess bytes");
1054 self.discard_excess_bytes(timeout)?;
1055 }
1056
1057 Ok(bytes_stored)
1058 }
1059
1060 /// Detect zero-length read pattern early
1061 ///
1062 /// Zero-length reads occur when a master sends START+ADDR+R followed immediately
1063 /// by NACK+STOP without wanting any data. This must be detected before attempting
1064 /// to transmit any bytes to avoid SDA line issues.
1065 fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result<Option<usize>, Error> {
1066 // Quick check for immediate termination signals
1067 let sr1 = self.info.regs.sr1().read();
1068
1069 // Check for immediate NACK (fastest zero-length pattern)
1070 if sr1.af() {
1071 self.clear_acknowledge_failure();
1072 return Ok(Some(0));
1073 }
1074
1075 // Check for immediate STOP (alternative zero-length pattern)
1076 if sr1.stopf() {
1077 Self::clear_stop_flag(self.info);
1078 return Ok(Some(0));
1079 }
1080
1081 // Give a brief window for master to send termination signals
1082 // This handles masters that have slight delays between address ACK and NACK
1083 const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window
1084
1085 for _ in 0..ZERO_LENGTH_DETECTION_CYCLES {
1086 let sr1 = self.info.regs.sr1().read();
1087
1088 // Immediate NACK indicates zero-length read
1089 if sr1.af() {
1090 self.clear_acknowledge_failure();
1091 return Ok(Some(0));
1092 }
1093
1094 // Immediate STOP indicates zero-length read
1095 if sr1.stopf() {
1096 Self::clear_stop_flag(self.info);
1097 return Ok(Some(0));
1098 }
1099
1100 // If TXE becomes ready, master is waiting for data - not zero-length
1101 if sr1.txe() {
1102 return Ok(None); // Proceed with normal transmission
1103 }
1104
1105 // If RESTART detected, handle as zero-length
1106 if sr1.addr() {
1107 return Ok(Some(0));
1108 }
1109 }
1110
1111 // No zero-length pattern detected within the window
1112 Ok(None)
1113 }
1114
1115 /// Discard excess bytes when buffer is full
1116 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> {
1117 let mut discarded_count = 0;
1118
1119 loop {
1120 match self.receive_byte(timeout)? {
1121 ReceiveResult::Data(_) => {
1122 discarded_count += 1;
1123 continue;
1124 }
1125 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1126 if discarded_count > 0 {
1127 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1128 }
1129 break;
1130 }
1131 }
1132 }
1133 Ok(())
1134 }
1135
1136 /// Send a single byte and wait for master's response
1137 fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result<TransmitResult, Error> {
1138 // Wait for transmit buffer ready
1139 self.wait_for_transmit_ready(timeout)?;
1140
1141 // Send the byte
1142 self.info.regs.dr().write(|w| w.set_dr(byte));
1143
1144 // Wait for transmission completion or master response
1145 self.wait_for_transmit_completion(timeout)
1146 }
1147
1148 /// Wait until transmit buffer is ready (TXE flag set)
1149 fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> {
1150 loop {
1151 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1152
1153 // Check for early termination conditions
1154 if let Some(result) = Self::check_early_termination(sr1) {
1155 return Err(self.handle_early_termination(result));
1156 }
1157
1158 if sr1.txe() {
1159 return Ok(()); // Ready to transmit
1160 }
1161
1162 timeout.check()?;
1163 }
1164 }
1165
1166 /// Wait for byte transmission completion or master response
1167 fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result<TransmitResult, Error> {
1168 loop {
1169 let sr1 = self.info.regs.sr1().read();
1170
1171 // Check flags in priority order
1172 if sr1.af() {
1173 self.clear_acknowledge_failure();
1174 return Ok(TransmitResult::NotAcknowledged);
1175 }
1176
1177 if sr1.btf() {
1178 return Ok(TransmitResult::Acknowledged);
1179 }
1180
1181 if sr1.stopf() {
1182 Self::clear_stop_flag(self.info);
1183 return Ok(TransmitResult::Stopped);
1184 }
1185
1186 if sr1.addr() {
1187 return Ok(TransmitResult::Restarted);
1188 }
1189
1190 // Check for other error conditions
1191 self.check_for_hardware_errors(sr1)?;
1192
1193 timeout.check()?;
1194 }
1195 }
1196
1197 /// Receive a single byte or detect transaction termination
1198 fn receive_byte(&mut self, timeout: Timeout) -> Result<ReceiveResult, Error> {
1199 loop {
1200 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1201
1202 // Check for received data first (prioritize data over control signals)
1203 if sr1.rxne() {
1204 let byte = self.info.regs.dr().read().dr();
1205 return Ok(ReceiveResult::Data(byte));
1206 }
1207
1208 // Check for transaction termination
1209 if sr1.addr() {
1210 return Ok(ReceiveResult::Restarted);
1211 }
1212
1213 if sr1.stopf() {
1214 Self::clear_stop_flag(self.info);
1215 return Ok(ReceiveResult::Stopped);
1216 }
1217
1218 timeout.check()?;
1219 }
1220 }
1221
1222 /// Determine which slave address was matched based on SR2 flags
1223 fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result<Address, Error> {
1224 if sr2.gencall() {
1225 Ok(Address::SevenBit(0x00)) // General call address
1226 } else if sr2.dualf() {
1227 // OA2 (secondary address) was matched
1228 let oar2 = info.regs.oar2().read();
1229 if oar2.endual() != i2c::vals::Endual::DUAL {
1230 return Err(Error::Bus); // Hardware inconsistency
1231 }
1232 Ok(Address::SevenBit(oar2.add2()))
1233 } else {
1234 // OA1 (primary address) was matched
1235 let oar1 = info.regs.oar1().read();
1236 match oar1.addmode() {
1237 i2c::vals::Addmode::BIT7 => {
1238 let addr = (oar1.add() >> 1) as u8;
1239 Ok(Address::SevenBit(addr))
1240 }
1241 i2c::vals::Addmode::BIT10 => Ok(Address::TenBit(oar1.add())),
1242 }
1243 }
1244 }
1245
1246 // Helper methods for hardware interaction
1247
1248 /// Read status register and handle I2C errors (except NACK in slave mode)
1249 fn read_status_and_handle_errors(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
1250 match Self::check_and_clear_error_flags(info) {
1251 Ok(sr1) => Ok(sr1),
1252 Err(Error::Nack) => {
1253 // In slave mode, NACK is normal protocol behavior, not an error
1254 Ok(info.regs.sr1().read())
1255 }
1256 Err(other_error) => Err(other_error),
1257 }
1258 }
1259
1260 /// Check for conditions that cause early termination of operations
1261 fn check_early_termination(sr1: i2c::regs::Sr1) -> Option<TransmitResult> {
1262 if sr1.stopf() {
1263 Some(TransmitResult::Stopped)
1264 } else if sr1.addr() {
1265 Some(TransmitResult::Restarted)
1266 } else if sr1.af() {
1267 Some(TransmitResult::NotAcknowledged)
1268 } else {
1269 None
1270 }
1271 }
1272
1273 /// Convert early termination to appropriate error
1274 fn handle_early_termination(&mut self, result: TransmitResult) -> Error {
1275 match result {
1276 TransmitResult::Stopped => {
1277 Self::clear_stop_flag(self.info);
1278 Error::Bus // Unexpected STOP during setup
1279 }
1280 TransmitResult::Restarted => {
1281 Error::Bus // Unexpected RESTART during setup
1282 }
1283 TransmitResult::NotAcknowledged => {
1284 self.clear_acknowledge_failure();
1285 Error::Bus // Unexpected NACK during setup
1286 }
1287 TransmitResult::Acknowledged => {
1288 unreachable!() // This should never be passed to this function
1289 }
1290 }
1291 }
1292
1293 /// Check for hardware-level I2C errors during transmission
1294 fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> {
1295 if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() {
1296 // Delegate to existing error handling
1297 Self::check_and_clear_error_flags(self.info)?;
1298 }
1299 Ok(())
1300 }
1301
1302 /// Disable I2C event and error interrupts for blocking operations
1303 fn disable_i2c_interrupts(&mut self) {
1304 self.info.regs.cr2().modify(|w| {
1305 w.set_itevten(false);
1306 w.set_iterren(false);
1307 });
1308 }
1309
1310 /// Clear the acknowledge failure flag
1311 fn clear_acknowledge_failure(&mut self) {
1312 self.info.regs.sr1().write(|reg| {
1313 reg.0 = !0;
1314 reg.set_af(false);
1315 });
1316 }
1317
1318 /// Configure DMA settings for slave operations (shared between read/write)
1319 fn setup_slave_dma_base(&mut self) {
1320 self.info.regs.cr2().modify(|w| {
1321 w.set_itbufen(false); // Always disable buffer interrupts when using DMA
1322 w.set_dmaen(true); // Enable DMA requests
1323 w.set_last(false); // LAST bit not used in slave mode for v1 hardware
1324 });
1325 }
1326
1327 /// Disable DMA and interrupts in a critical section
1328 fn disable_dma_and_interrupts(info: &'static Info) {
1329 critical_section::with(|_| {
1330 info.regs.cr2().modify(|w| {
1331 w.set_dmaen(false);
1332 w.set_iterren(false);
1333 w.set_itevten(false);
1334 });
1335 });
1336 }
1337
1338 /// Check for early termination conditions during slave operations
1339 /// Returns Some(result) if termination detected, None to continue
1340 fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option<SlaveTermination> {
1341 if sr1.stopf() {
1342 Some(SlaveTermination::Stop)
1343 } else if sr1.addr() {
1344 Some(SlaveTermination::Restart)
1345 } else if sr1.af() {
1346 Some(SlaveTermination::Nack)
1347 } else {
1348 None
1349 }
1350 }
1351}
1352
1353impl<'d> I2c<'d, Async, MultiMaster> {
1354 /// Async listen for incoming I2C messages using interrupts
1355 ///
1356 /// Waits for a master to address this slave and returns the command type
1357 /// (Read/Write) and the matched address. This method will suspend until
1358 /// an address match occurs.
1359 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1360 trace!("I2C slave: starting async listen for address match");
1361 let state = self.state;
1362 let info = self.info;
1363
1364 Self::enable_interrupts(info);
1365
1366 let on_drop = OnDrop::new(|| {
1367 Self::disable_dma_and_interrupts(info);
1368 });
1369
1370 let result = poll_fn(|cx| {
1371 state.waker.register(cx.waker());
1372
1373 match Self::check_and_clear_error_flags(info) {
1374 Err(e) => {
1375 error!("I2C slave: error during listen: {:?}", e);
1376 Poll::Ready(Err(e))
1377 }
1378 Ok(sr1) => {
1379 if sr1.addr() {
1380 let sr2 = info.regs.sr2().read();
1381 let direction = if sr2.tra() {
1382 SlaveCommandKind::Read
1383 } else {
1384 SlaveCommandKind::Write
1385 };
1386
1387 let matched_address = match Self::decode_matched_address(sr2, info) {
1388 Ok(addr) => {
1389 trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr);
1390 addr
1391 }
1392 Err(e) => {
1393 error!("I2C slave: failed to decode matched address: {:?}", e);
1394 return Poll::Ready(Err(e));
1395 }
1396 };
1397
1398 Poll::Ready(Ok(SlaveCommand {
1399 kind: direction,
1400 address: matched_address,
1401 }))
1402 } else {
1403 Self::enable_interrupts(info);
1404 Poll::Pending
1405 }
1406 }
1407 }
1408 })
1409 .await;
1410
1411 drop(on_drop);
1412 trace!("I2C slave: listen complete, result={:?}", result);
1413 result
1414 }
1415
1416 /// Async respond to write command using RX DMA
1417 ///
1418 /// Receives data from the master into the provided buffer using DMA.
1419 /// If the master sends more bytes than the buffer can hold, excess bytes
1420 /// are acknowledged but discarded to prevent interrupt flooding.
1421 ///
1422 /// Returns the number of bytes stored in the buffer (not total received).
1423 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1424 trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len());
1425
1426 if buffer.is_empty() {
1427 warn!("I2C slave: respond_to_write called with empty buffer");
1428 return Err(Error::Overrun);
1429 }
1430
1431 let state = self.state;
1432 let info = self.info;
1433
1434 self.setup_slave_dma_base();
1435
1436 let on_drop = OnDrop::new(|| {
1437 Self::disable_dma_and_interrupts(info);
1438 });
1439
1440 info.regs.sr2().read();
1441
1442 let result = self.execute_slave_receive_transfer(buffer, state, info).await;
1443
1444 drop(on_drop);
1445 trace!("I2C slave: respond_to_write complete, result={:?}", result);
1446 result
1447 }
1448
1449 /// Async respond to read command using TX DMA
1450 ///
1451 /// Transmits data to the master using DMA. If the master requests more bytes
1452 /// than available in the data buffer, padding bytes (0x00) are sent until
1453 /// the master terminates the transaction with NACK, STOP, or RESTART.
1454 ///
1455 /// Returns the total number of bytes transmitted (data + padding).
1456 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
1457 trace!("I2C slave: starting respond_to_read, data_len={}", data.len());
1458
1459 if data.is_empty() {
1460 warn!("I2C slave: respond_to_read called with empty data");
1461 return Err(Error::Overrun);
1462 }
1463
1464 let state = self.state;
1465 let info = self.info;
1466
1467 self.setup_slave_dma_base();
1468
1469 let on_drop = OnDrop::new(|| {
1470 Self::disable_dma_and_interrupts(info);
1471 });
1472
1473 info.regs.sr2().read();
1474
1475 let result = self.execute_slave_transmit_transfer(data, state, info).await;
1476
1477 drop(on_drop);
1478 trace!("I2C slave: respond_to_read complete, result={:?}", result);
1479 result
1480 }
1481
1482 // === Private Transfer Execution Methods ===
1483
1484 /// Execute complete slave receive transfer with excess byte handling
1485 async fn execute_slave_receive_transfer(
1486 &mut self,
1487 buffer: &mut [u8],
1488 state: &'static State,
1489 info: &'static Info,
1490 ) -> Result<usize, Error> {
1491 let dma_transfer = unsafe {
1492 let src = info.regs.dr().as_ptr() as *mut u8;
1493 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1494 };
1495
1496 let i2c_monitor =
1497 Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]);
1498
1499 match select(dma_transfer, i2c_monitor).await {
1500 Either::Second(Err(e)) => {
1501 error!("I2C slave: error during receive transfer: {:?}", e);
1502 Self::disable_dma_and_interrupts(info);
1503 Err(e)
1504 }
1505 Either::First(_) => {
1506 trace!("I2C slave: DMA receive completed, handling excess bytes");
1507 Self::disable_dma_and_interrupts(info);
1508 self.handle_excess_bytes(state, info).await?;
1509 Ok(buffer.len())
1510 }
1511 Either::Second(Ok(termination)) => {
1512 trace!("I2C slave: receive terminated by I2C event: {:?}", termination);
1513 Self::disable_dma_and_interrupts(info);
1514 Ok(buffer.len())
1515 }
1516 }
1517 }
1518
1519 /// Execute complete slave transmit transfer with padding byte handling
1520 async fn execute_slave_transmit_transfer(
1521 &mut self,
1522 data: &[u8],
1523 state: &'static State,
1524 info: &'static Info,
1525 ) -> Result<usize, Error> {
1526 let dma_transfer = unsafe {
1527 let dst = info.regs.dr().as_ptr() as *mut u8;
1528 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default())
1529 };
1530
1531 let i2c_monitor = Self::create_termination_monitor(
1532 state,
1533 info,
1534 &[
1535 SlaveTermination::Stop,
1536 SlaveTermination::Restart,
1537 SlaveTermination::Nack,
1538 ],
1539 );
1540
1541 match select(dma_transfer, i2c_monitor).await {
1542 Either::Second(Err(e)) => {
1543 error!("I2C slave: error during transmit transfer: {:?}", e);
1544 Self::disable_dma_and_interrupts(info);
1545 Err(e)
1546 }
1547 Either::First(_) => {
1548 trace!("I2C slave: DMA transmit completed, handling padding bytes");
1549 Self::disable_dma_and_interrupts(info);
1550 let padding_count = self.handle_padding_bytes(state, info).await?;
1551 let total_bytes = data.len() + padding_count;
1552 trace!(
1553 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1554 data.len(),
1555 padding_count,
1556 total_bytes
1557 );
1558 Ok(total_bytes)
1559 }
1560 Either::Second(Ok(termination)) => {
1561 trace!("I2C slave: transmit terminated by I2C event: {:?}", termination);
1562 Self::disable_dma_and_interrupts(info);
1563 Ok(data.len())
1564 }
1565 }
1566 }
1567
1568 /// Create a future that monitors for specific slave termination conditions
1569 fn create_termination_monitor(
1570 state: &'static State,
1571 info: &'static Info,
1572 allowed_terminations: &'static [SlaveTermination],
1573 ) -> impl Future<Output = Result<SlaveTermination, Error>> {
1574 poll_fn(move |cx| {
1575 state.waker.register(cx.waker());
1576
1577 match Self::check_and_clear_error_flags(info) {
1578 Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => {
1579 Poll::Ready(Ok(SlaveTermination::Nack))
1580 }
1581 Err(e) => Poll::Ready(Err(e)),
1582 Ok(sr1) => {
1583 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1584 if allowed_terminations.contains(&termination) {
1585 // Handle the specific termination condition
1586 match termination {
1587 SlaveTermination::Stop => Self::clear_stop_flag(info),
1588 SlaveTermination::Nack => {
1589 info.regs.sr1().write(|reg| {
1590 reg.0 = !0;
1591 reg.set_af(false);
1592 });
1593 }
1594 SlaveTermination::Restart => {
1595 // ADDR flag will be handled by next listen() call
1596 }
1597 }
1598 Poll::Ready(Ok(termination))
1599 } else {
1600 // Unexpected termination condition
1601 Poll::Ready(Err(Error::Bus))
1602 }
1603 } else {
1604 Self::enable_interrupts(info);
1605 Poll::Pending
1606 }
1607 }
1608 }
1609 })
1610 }
1611
1612 /// Handle excess bytes after DMA buffer is full
1613 ///
1614 /// Reads and discards bytes until transaction termination to prevent interrupt flooding
1615 async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> {
1616 let mut discarded_count = 0;
1617
1618 poll_fn(|cx| {
1619 state.waker.register(cx.waker());
1620
1621 match Self::check_and_clear_error_flags(info) {
1622 Err(e) => {
1623 error!("I2C slave: error while discarding excess bytes: {:?}", e);
1624 Poll::Ready(Err(e))
1625 }
1626 Ok(sr1) => {
1627 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1628 match termination {
1629 SlaveTermination::Stop => Self::clear_stop_flag(info),
1630 SlaveTermination::Restart => {}
1631 SlaveTermination::Nack => unreachable!("NACK not expected during receive"),
1632 }
1633 if discarded_count > 0 {
1634 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1635 }
1636 return Poll::Ready(Ok(()));
1637 }
1638
1639 if sr1.rxne() {
1640 let _discarded_byte = info.regs.dr().read().dr();
1641 discarded_count += 1;
1642 Self::enable_interrupts(info);
1643 return Poll::Pending;
1644 }
1645
1646 Self::enable_interrupts(info);
1647 Poll::Pending
1648 }
1649 }
1650 })
1651 .await
1652 }
1653
1654 /// Handle padding bytes after DMA data is exhausted
1655 ///
1656 /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding
1657 async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<usize, Error> {
1658 let mut padding_count = 0;
1659
1660 poll_fn(|cx| {
1661 state.waker.register(cx.waker());
1662
1663 match Self::check_and_clear_error_flags(info) {
1664 Err(Error::Nack) => Poll::Ready(Ok(padding_count)),
1665 Err(e) => {
1666 error!("I2C slave: error while sending padding bytes: {:?}", e);
1667 Poll::Ready(Err(e))
1668 }
1669 Ok(sr1) => {
1670 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1671 match termination {
1672 SlaveTermination::Stop => Self::clear_stop_flag(info),
1673 SlaveTermination::Restart => {}
1674 SlaveTermination::Nack => {
1675 info.regs.sr1().write(|reg| {
1676 reg.0 = !0;
1677 reg.set_af(false);
1678 });
1679 }
1680 }
1681 return Poll::Ready(Ok(padding_count));
1682 }
1683
1684 if sr1.txe() {
1685 info.regs.dr().write(|w| w.set_dr(0x00));
1686 padding_count += 1;
1687 Self::enable_interrupts(info);
1688 return Poll::Pending;
1689 }
1690
1691 Self::enable_interrupts(info);
1692 Poll::Pending
1693 }
1694 }
1695 })
1696 .await
1697 }
1698}
1699
1700/// Timing configuration for I2C v1 hardware
1701///
1702/// This struct encapsulates the complex timing calculations required for STM32 I2C v1
1703/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of
1704/// the unified TIMINGR register found in v2 hardware.
732struct Timings { 1705struct Timings {
733 freq: u8, 1706 freq: u8, // APB frequency in MHz for CR2.FREQ register
734 mode: Mode, 1707 mode: Mode, // Standard or Fast mode selection
735 trise: u8, 1708 trise: u8, // Rise time compensation value
736 ccr: u16, 1709 ccr: u16, // Clock control register value
737 duty: Duty, 1710 duty: Duty, // Fast mode duty cycle selection
738} 1711}
739 1712
740impl Timings { 1713impl Timings {
@@ -771,14 +1744,10 @@ impl Timings {
771 duty = Duty::Duty2_1; 1744 duty = Duty::Duty2_1;
772 ccr = clock / (frequency * 3); 1745 ccr = clock / (frequency * 3);
773 ccr = if ccr < 1 { 1 } else { ccr }; 1746 ccr = if ccr < 1 { 1 } else { ccr };
774
775 // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
776 } else { 1747 } else {
777 duty = Duty::Duty16_9; 1748 duty = Duty::Duty16_9;
778 ccr = clock / (frequency * 25); 1749 ccr = clock / (frequency * 25);
779 ccr = if ccr < 1 { 1 } else { ccr }; 1750 ccr = if ccr < 1 { 1 } else { ccr };
780
781 // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
782 } 1751 }
783 } 1752 }
784 1753
@@ -788,11 +1757,6 @@ impl Timings {
788 ccr: ccr as u16, 1757 ccr: ccr as u16,
789 duty, 1758 duty,
790 mode, 1759 mode,
791 //prescale: presc_reg,
792 //scll,
793 //sclh,
794 //sdadel,
795 //scldel,
796 } 1760 }
797 } 1761 }
798} 1762}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 01b6b8800..57a7acee7 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -70,6 +70,11 @@ fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) {
70} 70}
71 71
72pub(crate) unsafe fn on_interrupt<T: Instance>() { 72pub(crate) unsafe fn on_interrupt<T: Instance>() {
73 // restore the clocks to their last configured state as
74 // much is lost in STOP modes
75 #[cfg(all(feature = "low-power", stm32wlex))]
76 crate::low_power::Executor::on_wakeup_irq();
77
73 let regs = T::info().regs; 78 let regs = T::info().regs;
74 let isr = regs.isr().read(); 79 let isr = regs.isr().read();
75 80
@@ -814,6 +819,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
814 819
815 /// Write. 820 /// Write.
816 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 821 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
822 #[cfg(all(feature = "low-power", stm32wlex))]
823 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
817 let timeout = self.timeout(); 824 let timeout = self.timeout();
818 if write.is_empty() { 825 if write.is_empty() {
819 self.write_internal(address.into(), write, true, timeout) 826 self.write_internal(address.into(), write, true, timeout)
@@ -828,6 +835,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
828 /// 835 ///
829 /// The buffers are concatenated in a single write transaction. 836 /// The buffers are concatenated in a single write transaction.
830 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { 837 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> {
838 #[cfg(all(feature = "low-power", stm32wlex))]
839 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
831 let timeout = self.timeout(); 840 let timeout = self.timeout();
832 841
833 if write.is_empty() { 842 if write.is_empty() {
@@ -851,6 +860,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
851 860
852 /// Read. 861 /// Read.
853 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 862 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
863 #[cfg(all(feature = "low-power", stm32wlex))]
864 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
854 let timeout = self.timeout(); 865 let timeout = self.timeout();
855 866
856 if buffer.is_empty() { 867 if buffer.is_empty() {
@@ -863,6 +874,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
863 874
864 /// Write, restart, read. 875 /// Write, restart, read.
865 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 876 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
877 #[cfg(all(feature = "low-power", stm32wlex))]
878 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
866 let timeout = self.timeout(); 879 let timeout = self.timeout();
867 880
868 if write.is_empty() { 881 if write.is_empty() {
@@ -888,6 +901,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
888 /// 901 ///
889 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 902 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
890 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
904 #[cfg(all(feature = "low-power", stm32wlex))]
905 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
891 let _ = addr; 906 let _ = addr;
892 let _ = operations; 907 let _ = operations;
893 todo!() 908 todo!()
@@ -1181,7 +1196,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1181 1196
1182 let regs = self.info.regs; 1197 let regs = self.info.regs;
1183 1198
1184 let dma_transfer = unsafe { 1199 let mut dma_transfer = unsafe {
1185 regs.cr1().modify(|w| { 1200 regs.cr1().modify(|w| {
1186 w.set_rxdmaen(true); 1201 w.set_rxdmaen(true);
1187 w.set_stopie(true); 1202 w.set_stopie(true);
@@ -1229,6 +1244,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1229 }) 1244 })
1230 .await?; 1245 .await?;
1231 1246
1247 dma_transfer.request_pause();
1232 dma_transfer.await; 1248 dma_transfer.await;
1233 1249
1234 drop(on_drop); 1250 drop(on_drop);
@@ -1294,6 +1310,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1294 }) 1310 })
1295 .await?; 1311 .await?;
1296 1312
1313 dma_transfer.request_pause();
1297 dma_transfer.await; 1314 dma_transfer.await;
1298 1315
1299 drop(on_drop); 1316 drop(on_drop);
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index db22cfa11..df077a3ae 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -7,6 +7,7 @@ use crate::Peri;
7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; 7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer};
8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
9use crate::mode::Async; 9use crate::mode::Async;
10use crate::spi::mode::Master;
10use crate::spi::{Config as SpiConfig, RegsExt as _, *}; 11use crate::spi::{Config as SpiConfig, RegsExt as _, *};
11use crate::time::Hertz; 12use crate::time::Hertz;
12 13
@@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
225pub struct I2S<'d, W: Word> { 226pub struct I2S<'d, W: Word> {
226 #[allow(dead_code)] 227 #[allow(dead_code)]
227 mode: Mode, 228 mode: Mode,
228 spi: Spi<'d, Async>, 229 spi: Spi<'d, Async, Master>,
229 txsd: Option<Peri<'d, AnyPin>>, 230 txsd: Option<Peri<'d, AnyPin>>,
230 rxsd: Option<Peri<'d, AnyPin>>, 231 rxsd: Option<Peri<'d, AnyPin>>,
231 ws: Option<Peri<'d, AnyPin>>, 232 ws: Option<Peri<'d, AnyPin>>,
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index dbf0fe620..e08ab30e6 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -54,6 +54,8 @@ pub mod timer;
54 54
55#[cfg(adc)] 55#[cfg(adc)]
56pub mod adc; 56pub mod adc;
57#[cfg(backup_sram)]
58pub mod backup_sram;
57#[cfg(can)] 59#[cfg(can)]
58pub mod can; 60pub mod can;
59// FIXME: Cordic driver cause stm32u5a5zj crash 61// FIXME: Cordic driver cause stm32u5a5zj crash
@@ -241,6 +243,14 @@ pub struct Config {
241 /// RCC config. 243 /// RCC config.
242 pub rcc: rcc::Config, 244 pub rcc: rcc::Config,
243 245
246 #[cfg(feature = "low-power")]
247 /// RTC config
248 pub rtc: rtc::RtcConfig,
249
250 #[cfg(feature = "low-power")]
251 /// Minimum time to stop
252 pub min_stop_pause: embassy_time::Duration,
253
244 /// Enable debug during sleep and stop. 254 /// Enable debug during sleep and stop.
245 /// 255 ///
246 /// May increase power consumption. Defaults to true. 256 /// May increase power consumption. Defaults to true.
@@ -294,6 +304,10 @@ impl Default for Config {
294 fn default() -> Self { 304 fn default() -> Self {
295 Self { 305 Self {
296 rcc: Default::default(), 306 rcc: Default::default(),
307 #[cfg(feature = "low-power")]
308 rtc: Default::default(),
309 #[cfg(feature = "low-power")]
310 min_stop_pause: embassy_time::Duration::from_millis(250),
297 #[cfg(dbgmcu)] 311 #[cfg(dbgmcu)]
298 enable_debug_during_sleep: true, 312 enable_debug_during_sleep: true,
299 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] 313 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
@@ -623,6 +637,12 @@ fn init_hw(config: Config) -> Peripherals {
623 exti::init(cs); 637 exti::init(cs);
624 638
625 rcc::init_rcc(cs, config.rcc); 639 rcc::init_rcc(cs, config.rcc);
640
641 #[cfg(feature = "low-power")]
642 crate::rtc::init_rtc(cs, config.rtc);
643
644 #[cfg(feature = "low-power")]
645 crate::time_driver::get_driver().set_min_stop_pause(cs, config.min_stop_pause);
626 } 646 }
627 647
628 p 648 p
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 1b66ca680..696dfe83f 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -41,12 +41,6 @@
41//! config.enable_debug_during_sleep = false; 41//! config.enable_debug_during_sleep = false;
42//! let p = embassy_stm32::init(config); 42//! let p = embassy_stm32::init(config);
43//! 43//!
44//! // give the RTC to the executor...
45//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
46//! static RTC: StaticCell<Rtc> = StaticCell::new();
47//! let rtc = RTC.init(rtc);
48//! embassy_stm32::low_power::stop_with_rtc(rtc);
49//!
50//! // your application here... 44//! // your application here...
51//! } 45//! }
52//! ``` 46//! ```
@@ -59,24 +53,69 @@ use core::marker::PhantomData;
59use core::sync::atomic::{Ordering, compiler_fence}; 53use core::sync::atomic::{Ordering, compiler_fence};
60 54
61use cortex_m::peripheral::SCB; 55use cortex_m::peripheral::SCB;
56use critical_section::CriticalSection;
62use embassy_executor::*; 57use embassy_executor::*;
63 58
64use crate::interrupt; 59use crate::interrupt;
65use crate::time_driver::{RtcDriver, get_driver}; 60use crate::time_driver::get_driver;
66 61
67const THREAD_PENDER: usize = usize::MAX; 62const THREAD_PENDER: usize = usize::MAX;
68 63
69use crate::rtc::Rtc;
70
71static mut EXECUTOR: Option<Executor> = None; 64static mut EXECUTOR: Option<Executor> = None;
72 65
66/// Prevent the device from going into the stop mode if held
67pub struct DeviceBusy(StopMode);
68
69impl DeviceBusy {
70 /// Create a new DeviceBusy with stop1.
71 pub fn new_stop1() -> Self {
72 Self::new(StopMode::Stop1)
73 }
74
75 /// Create a new DeviceBusy with stop2.
76 pub fn new_stop2() -> Self {
77 Self::new(StopMode::Stop2)
78 }
79
80 /// Create a new DeviceBusy.
81 pub fn new(stop_mode: StopMode) -> Self {
82 critical_section::with(|_| unsafe {
83 match stop_mode {
84 StopMode::Stop1 => {
85 crate::rcc::REFCOUNT_STOP1 += 1;
86 }
87 StopMode::Stop2 => {
88 crate::rcc::REFCOUNT_STOP2 += 1;
89 }
90 }
91 });
92
93 Self(stop_mode)
94 }
95}
96
97impl Drop for DeviceBusy {
98 fn drop(&mut self) {
99 critical_section::with(|_| unsafe {
100 match self.0 {
101 StopMode::Stop1 => {
102 crate::rcc::REFCOUNT_STOP1 -= 1;
103 }
104 StopMode::Stop2 => {
105 crate::rcc::REFCOUNT_STOP2 -= 1;
106 }
107 }
108 });
109 }
110}
111
73#[cfg(not(stm32u0))] 112#[cfg(not(stm32u0))]
74foreach_interrupt! { 113foreach_interrupt! {
75 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 114 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
76 #[interrupt] 115 #[interrupt]
77 #[allow(non_snake_case)] 116 #[allow(non_snake_case)]
78 unsafe fn $irq() { 117 unsafe fn $irq() {
79 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 118 Executor::on_wakeup_irq();
80 } 119 }
81 }; 120 };
82} 121}
@@ -87,31 +126,21 @@ foreach_interrupt! {
87 #[interrupt] 126 #[interrupt]
88 #[allow(non_snake_case)] 127 #[allow(non_snake_case)]
89 unsafe fn $irq() { 128 unsafe fn $irq() {
90 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 129 Executor::on_wakeup_irq();
91 } 130 }
92 }; 131 };
93} 132}
94 133
95#[allow(dead_code)]
96pub(crate) unsafe fn on_wakeup_irq() {
97 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
98}
99
100/// Configure STOP mode with RTC.
101pub fn stop_with_rtc(rtc: &'static Rtc) {
102 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
103}
104
105/// Get whether the core is ready to enter the given stop mode. 134/// Get whether the core is ready to enter the given stop mode.
106/// 135///
107/// This will return false if some peripheral driver is in use that 136/// This will return false if some peripheral driver is in use that
108/// prevents entering the given stop mode. 137/// prevents entering the given stop mode.
109pub fn stop_ready(stop_mode: StopMode) -> bool { 138pub fn stop_ready(stop_mode: StopMode) -> bool {
110 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 139 critical_section::with(|cs| match Executor::stop_mode(cs) {
111 Some(StopMode::Stop2) => true, 140 Some(StopMode::Stop2) => true,
112 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 141 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
113 None => false, 142 None => false,
114 } 143 })
115} 144}
116 145
117/// Available Stop modes. 146/// Available Stop modes.
@@ -124,10 +153,10 @@ pub enum StopMode {
124 Stop2, 153 Stop2,
125} 154}
126 155
127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 156#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
128use stm32_metapac::pwr::vals::Lpms; 157use stm32_metapac::pwr::vals::Lpms;
129 158
130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 159#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wlex, stm32u0))]
131impl Into<Lpms> for StopMode { 160impl Into<Lpms> for StopMode {
132 fn into(self) -> Lpms { 161 fn into(self) -> Lpms {
133 match self { 162 match self {
@@ -154,7 +183,6 @@ pub struct Executor {
154 inner: raw::Executor, 183 inner: raw::Executor,
155 not_send: PhantomData<*mut ()>, 184 not_send: PhantomData<*mut ()>,
156 scb: SCB, 185 scb: SCB,
157 time_driver: &'static RtcDriver,
158} 186}
159 187
160impl Executor { 188impl Executor {
@@ -167,7 +195,6 @@ impl Executor {
167 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 195 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
168 not_send: PhantomData, 196 not_send: PhantomData,
169 scb: cortex_m::Peripherals::steal().SCB, 197 scb: cortex_m::Peripherals::steal().SCB,
170 time_driver: get_driver(),
171 }); 198 });
172 199
173 let executor = EXECUTOR.as_mut().unwrap(); 200 let executor = EXECUTOR.as_mut().unwrap();
@@ -176,21 +203,31 @@ impl Executor {
176 }) 203 })
177 } 204 }
178 205
179 unsafe fn on_wakeup_irq(&mut self) { 206 pub(crate) unsafe fn on_wakeup_irq() {
180 self.time_driver.resume_time(); 207 critical_section::with(|cs| {
181 trace!("low power: resume"); 208 #[cfg(stm32wlex)]
182 } 209 {
183 210 let extscr = crate::pac::PWR.extscr().read();
184 pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { 211 if extscr.c1stop2f() || extscr.c1stopf() {
185 self.time_driver.set_rtc(rtc); 212 // when we wake from any stop mode we need to re-initialize the rcc
186 213 crate::rcc::apply_resume_config();
187 rtc.enable_wakeup_line(); 214 if extscr.c1stop2f() {
188 215 // when we wake from STOP2, we need to re-initialize the time driver
189 trace!("low power: stop with rtc configured"); 216 crate::time_driver::init_timer(cs);
217 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
218 // and given that we just woke from STOP2, we can reset them
219 crate::rcc::REFCOUNT_STOP2 = 0;
220 crate::rcc::REFCOUNT_STOP1 = 0;
221 }
222 }
223 }
224 get_driver().resume_time(cs);
225 trace!("low power: resume");
226 });
190 } 227 }
191 228
192 fn stop_mode(&self) -> Option<StopMode> { 229 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
193 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 230 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 && crate::rcc::REFCOUNT_STOP1 == 0 } {
194 Some(StopMode::Stop2) 231 Some(StopMode::Stop2)
195 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 232 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } {
196 Some(StopMode::Stop1) 233 Some(StopMode::Stop1)
@@ -201,7 +238,7 @@ impl Executor {
201 238
202 #[allow(unused_variables)] 239 #[allow(unused_variables)]
203 fn configure_stop(&mut self, stop_mode: StopMode) { 240 fn configure_stop(&mut self, stop_mode: StopMode) {
204 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba))] 241 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba, stm32wlex))]
205 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 242 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
206 #[cfg(stm32h5)] 243 #[cfg(stm32h5)]
207 crate::pac::PWR.pmcr().modify(|v| { 244 crate::pac::PWR.pmcr().modify(|v| {
@@ -213,17 +250,22 @@ impl Executor {
213 250
214 fn configure_pwr(&mut self) { 251 fn configure_pwr(&mut self) {
215 self.scb.clear_sleepdeep(); 252 self.scb.clear_sleepdeep();
253 // Clear any previous stop flags
254 #[cfg(stm32wlex)]
255 crate::pac::PWR.extscr().modify(|w| {
256 w.set_c1cssf(true);
257 });
216 258
217 compiler_fence(Ordering::SeqCst); 259 compiler_fence(Ordering::SeqCst);
218 260
219 let stop_mode = self.stop_mode(); 261 let stop_mode = critical_section::with(|cs| Self::stop_mode(cs));
220 262
221 if stop_mode.is_none() { 263 if stop_mode.is_none() {
222 trace!("low power: not ready to stop"); 264 trace!("low power: not ready to stop");
223 return; 265 return;
224 } 266 }
225 267
226 if self.time_driver.pause_time().is_err() { 268 if get_driver().pause_time().is_err() {
227 trace!("low power: failed to pause time"); 269 trace!("low power: failed to pause time");
228 return; 270 return;
229 } 271 }
@@ -266,6 +308,19 @@ impl Executor {
266 executor.inner.poll(); 308 executor.inner.poll();
267 self.configure_pwr(); 309 self.configure_pwr();
268 asm!("wfe"); 310 asm!("wfe");
311 #[cfg(stm32wlex)]
312 {
313 let es = crate::pac::PWR.extscr().read();
314 match (es.c1stopf(), es.c1stop2f()) {
315 (true, false) => debug!("low power: wake from STOP1"),
316 (false, true) => debug!("low power: wake from STOP2"),
317 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"),
318 (false, false) => trace!("low power: stop mode not entered"),
319 };
320 crate::pac::PWR.extscr().modify(|w| {
321 w.set_c1cssf(false);
322 });
323 }
269 }; 324 };
270 } 325 }
271 } 326 }
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index 3b2a10581..5b367c043 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -1,6 +1,8 @@
1use core::sync::atomic::{Ordering, compiler_fence}; 1use core::sync::atomic::{Ordering, compiler_fence};
2 2
3use crate::pac::common::{RW, Reg}; 3use crate::pac::common::{RW, Reg};
4#[cfg(backup_sram)]
5use crate::pac::pwr::vals::Retention;
4pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; 6pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
5use crate::time::Hertz; 7use crate::time::Hertz;
6 8
@@ -89,6 +91,8 @@ pub struct LsConfig {
89 pub rtc: RtcClockSource, 91 pub rtc: RtcClockSource,
90 pub lsi: bool, 92 pub lsi: bool,
91 pub lse: Option<LseConfig>, 93 pub lse: Option<LseConfig>,
94 #[cfg(backup_sram)]
95 pub enable_backup_sram: bool,
92} 96}
93 97
94impl LsConfig { 98impl LsConfig {
@@ -113,6 +117,8 @@ impl LsConfig {
113 peripherals_clocked: false, 117 peripherals_clocked: false,
114 }), 118 }),
115 lsi: false, 119 lsi: false,
120 #[cfg(backup_sram)]
121 enable_backup_sram: false,
116 } 122 }
117 } 123 }
118 124
@@ -121,6 +127,8 @@ impl LsConfig {
121 rtc: RtcClockSource::LSI, 127 rtc: RtcClockSource::LSI,
122 lsi: true, 128 lsi: true,
123 lse: None, 129 lse: None,
130 #[cfg(backup_sram)]
131 enable_backup_sram: false,
124 } 132 }
125 } 133 }
126 134
@@ -129,6 +137,8 @@ impl LsConfig {
129 rtc: RtcClockSource::DISABLE, 137 rtc: RtcClockSource::DISABLE,
130 lsi: false, 138 lsi: false,
131 lse: None, 139 lse: None,
140 #[cfg(backup_sram)]
141 enable_backup_sram: false,
132 } 142 }
133 } 143 }
134} 144}
@@ -193,6 +203,22 @@ impl LsConfig {
193 while !csr.read().lsi1rdy() {} 203 while !csr.read().lsi1rdy() {}
194 } 204 }
195 205
206 // Enable backup regulator for peristent battery backed sram
207 #[cfg(backup_sram)]
208 {
209 unsafe { super::BKSRAM_RETAINED = crate::pac::PWR.bdcr().read().bren() == Retention::PRESERVED };
210
211 crate::pac::PWR.bdcr().modify(|w| {
212 w.set_bren(match self.enable_backup_sram {
213 true => Retention::PRESERVED,
214 false => Retention::LOST,
215 });
216 });
217
218 // Wait for backup regulator voltage to stabilize
219 while self.enable_backup_sram && !crate::pac::PWR.bdsr().read().brrdy() {}
220 }
221
196 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. 222 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
197 // once set, changing it requires a backup domain reset. 223 // once set, changing it requires a backup domain reset.
198 // first check if the configuration matches what we want. 224 // first check if the configuration matches what we want.
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 2e1cbd702..584957c6d 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,3 +1,6 @@
1#[cfg(all(feature = "low-power", stm32wlex))]
2use core::mem::MaybeUninit;
3
1#[cfg(any(stm32l0, stm32l1))] 4#[cfg(any(stm32l0, stm32l1))]
2pub use crate::pac::pwr::vals::Vos as VoltageScale; 5pub use crate::pac::pwr::vals::Vos as VoltageScale;
3use crate::pac::rcc::regs::Cfgr; 6use crate::pac::rcc::regs::Cfgr;
@@ -11,6 +14,42 @@ use crate::time::Hertz;
11/// HSI speed 14/// HSI speed
12pub const HSI_FREQ: Hertz = Hertz(16_000_000); 15pub const HSI_FREQ: Hertz = Hertz(16_000_000);
13 16
17/// Saved RCC Config
18///
19/// Used when exiting STOP2 to re-enable clocks to their last configured state
20/// for chips that need it.
21#[cfg(all(feature = "low-power", stm32wlex))]
22static mut RESUME_RCC_CONFIG: MaybeUninit<Config> = MaybeUninit::uninit();
23
24/// Set the rcc config to be restored when exiting STOP2
25///
26/// Safety: Sets a mutable global.
27#[cfg(all(feature = "low-power", stm32wlex))]
28pub(crate) unsafe fn set_resume_config(config: Config) {
29 trace!("rcc set_resume_config()");
30 RESUME_RCC_CONFIG = MaybeUninit::new(config);
31}
32
33/// Get the rcc config to be restored when exiting STOP2
34///
35/// Safety: Reads a mutable global.
36#[cfg(all(feature = "low-power", stm32wlex))]
37pub(crate) unsafe fn get_resume_config() -> Config {
38 *(*core::ptr::addr_of_mut!(RESUME_RCC_CONFIG)).assume_init_ref()
39}
40
41#[cfg(all(feature = "low-power", stm32wlex))]
42/// Safety: should only be called from low power executable just after resuming from STOP2
43pub(crate) unsafe fn apply_resume_config() {
44 trace!("rcc apply_resume_config()");
45
46 while RCC.cfgr().read().sws() != Sysclk::MSI {}
47
48 let config = get_resume_config();
49
50 init(config);
51}
52
14#[derive(Clone, Copy, Eq, PartialEq)] 53#[derive(Clone, Copy, Eq, PartialEq)]
15pub enum HseMode { 54pub enum HseMode {
16 /// crystal/ceramic oscillator (HSEBYP=0) 55 /// crystal/ceramic oscillator (HSEBYP=0)
@@ -154,6 +193,10 @@ fn msi_enable(range: MSIRange) {
154} 193}
155 194
156pub(crate) unsafe fn init(config: Config) { 195pub(crate) unsafe fn init(config: Config) {
196 // save the rcc config because if we enter stop 2 we need to re-apply it on wakeup
197 #[cfg(all(feature = "low-power", stm32wlex))]
198 set_resume_config(config);
199
157 // Switch to MSI to prevent problems with PLL configuration. 200 // Switch to MSI to prevent problems with PLL configuration.
158 if !RCC.cr().read().msion() { 201 if !RCC.cr().read().msion() {
159 // Turn on MSI and configure it to 4MHz. 202 // Turn on MSI and configure it to 4MHz.
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index addfca3c3..01fa3a475 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -48,6 +48,9 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
48/// May be read without a critical section 48/// May be read without a critical section
49pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 49pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
50 50
51#[cfg(backup_sram)]
52pub(crate) static mut BKSRAM_RETAINED: bool = false;
53
51#[cfg(not(feature = "_dual-core"))] 54#[cfg(not(feature = "_dual-core"))]
52/// Frozen clock frequencies 55/// Frozen clock frequencies
53/// 56///
@@ -390,7 +393,7 @@ pub fn disable<T: RccPeripheral>() {
390/// 393///
391/// This should only be called after `init`. 394/// This should only be called after `init`.
392#[cfg(not(feature = "_dual-core"))] 395#[cfg(not(feature = "_dual-core"))]
393pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { 396pub fn reinit(config: Config, _rcc: &'_ mut crate::Peri<'_, crate::peripherals::RCC>) {
394 critical_section::with(|cs| init_rcc(cs, config)) 397 critical_section::with(|cs| init_rcc(cs, config))
395} 398}
396 399
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index 999f24714..e5bf30927 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -4,7 +4,7 @@ use embassy_time::{Duration, TICK_HZ};
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::peripherals::RTC; 6use crate::peripherals::RTC;
7use crate::rtc::SealedInstance; 7use crate::rtc::{RtcTimeProvider, SealedInstance};
8 8
9/// Represents an instant in time that can be substracted to compute a duration 9/// Represents an instant in time that can be substracted to compute a duration
10pub(super) struct RtcInstant { 10pub(super) struct RtcInstant {
@@ -68,7 +68,7 @@ pub(crate) enum WakeupPrescaler {
68} 68}
69 69
70#[cfg(any( 70#[cfg(any(
71 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba 71 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex
72))] 72))]
73impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 73impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
74 fn from(val: WakeupPrescaler) -> Self { 74 fn from(val: WakeupPrescaler) -> Self {
@@ -84,7 +84,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
84} 84}
85 85
86#[cfg(any( 86#[cfg(any(
87 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba 87 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba, stm32wlex
88))] 88))]
89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
@@ -117,7 +117,7 @@ impl WakeupPrescaler {
117impl Rtc { 117impl Rtc {
118 /// Return the current instant. 118 /// Return the current instant.
119 fn instant(&self) -> Result<RtcInstant, RtcError> { 119 fn instant(&self) -> Result<RtcInstant, RtcError> {
120 self.time_provider().read(|_, tr, ss| { 120 RtcTimeProvider::new().read(|_, tr, ss| {
121 let second = bcd2_to_byte((tr.st(), tr.su())); 121 let second = bcd2_to_byte((tr.st(), tr.su()));
122 122
123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
@@ -127,7 +127,7 @@ impl Rtc {
127 /// start the wakeup alarm and with a duration that is as close to but less than 127 /// start the wakeup alarm and with a duration that is as close to but less than
128 /// the requested duration, and record the instant the wakeup alarm was started 128 /// the requested duration, and record the instant the wakeup alarm was started
129 pub(crate) fn start_wakeup_alarm( 129 pub(crate) fn start_wakeup_alarm(
130 &self, 130 &mut self,
131 requested_duration: embassy_time::Duration, 131 requested_duration: embassy_time::Duration,
132 cs: critical_section::CriticalSection, 132 cs: critical_section::CriticalSection,
133 ) { 133 ) {
@@ -179,7 +179,10 @@ impl Rtc {
179 179
180 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 180 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
181 /// was called, otherwise none 181 /// was called, otherwise none
182 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 182 pub(crate) fn stop_wakeup_alarm(
183 &mut self,
184 cs: critical_section::CriticalSection,
185 ) -> Option<embassy_time::Duration> {
183 let instant = self.instant().unwrap(); 186 let instant = self.instant().unwrap();
184 if RTC::regs().cr().read().wute() { 187 if RTC::regs().cr().read().wute() {
185 trace!("rtc: stop wakeup alarm at {}", instant); 188 trace!("rtc: stop wakeup alarm at {}", instant);
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index bc6df528b..116b3c7ed 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -5,9 +5,13 @@ mod datetime;
5mod low_power; 5mod low_power;
6 6
7#[cfg(feature = "low-power")] 7#[cfg(feature = "low-power")]
8use core::cell::Cell; 8use core::cell::{Cell, RefCell, RefMut};
9#[cfg(feature = "low-power")]
10use core::ops;
9 11
10#[cfg(feature = "low-power")] 12#[cfg(feature = "low-power")]
13use critical_section::CriticalSection;
14#[cfg(feature = "low-power")]
11use embassy_sync::blocking_mutex::Mutex; 15use embassy_sync::blocking_mutex::Mutex;
12#[cfg(feature = "low-power")] 16#[cfg(feature = "low-power")]
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 17use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
@@ -44,11 +48,17 @@ pub enum RtcError {
44} 48}
45 49
46/// Provides immutable access to the current time of the RTC. 50/// Provides immutable access to the current time of the RTC.
51#[derive(Clone)]
47pub struct RtcTimeProvider { 52pub struct RtcTimeProvider {
48 _private: (), 53 _private: (),
49} 54}
50 55
51impl RtcTimeProvider { 56impl RtcTimeProvider {
57 /// Create a new RTC time provider instance.
58 pub(self) const fn new() -> Self {
59 Self { _private: () }
60 }
61
52 /// Return the current datetime. 62 /// Return the current datetime.
53 /// 63 ///
54 /// # Errors 64 /// # Errors
@@ -106,6 +116,50 @@ impl RtcTimeProvider {
106 } 116 }
107} 117}
108 118
119#[cfg(feature = "low-power")]
120/// Contains an RTC driver.
121pub struct RtcContainer {
122 pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
123}
124
125#[cfg(feature = "low-power")]
126impl RtcContainer {
127 pub(self) const fn new() -> Self {
128 Self {
129 mutex: &crate::time_driver::get_driver().rtc,
130 }
131 }
132
133 /// Acquire an RTC borrow.
134 pub fn borrow_mut<'a>(&self, cs: CriticalSection<'a>) -> RtcBorrow<'a> {
135 RtcBorrow {
136 ref_mut: self.mutex.borrow(cs).borrow_mut(),
137 }
138 }
139}
140
141#[cfg(feature = "low-power")]
142/// Contains an RTC borrow.
143pub struct RtcBorrow<'a> {
144 pub(self) ref_mut: RefMut<'a, Option<Rtc>>,
145}
146
147#[cfg(feature = "low-power")]
148impl<'a> ops::Deref for RtcBorrow<'a> {
149 type Target = Rtc;
150
151 fn deref(&self) -> &Self::Target {
152 self.ref_mut.as_ref().unwrap()
153 }
154}
155
156#[cfg(feature = "low-power")]
157impl<'a> ops::DerefMut for RtcBorrow<'a> {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 self.ref_mut.as_mut().unwrap()
160 }
161}
162
109/// RTC driver. 163/// RTC driver.
110pub struct Rtc { 164pub struct Rtc {
111 #[cfg(feature = "low-power")] 165 #[cfg(feature = "low-power")]
@@ -121,13 +175,21 @@ pub struct RtcConfig {
121 /// 175 ///
122 /// A high counter frequency may impact stop power consumption 176 /// A high counter frequency may impact stop power consumption
123 pub frequency: Hertz, 177 pub frequency: Hertz,
178
179 #[cfg(feature = "_allow-disable-rtc")]
180 /// Allow disabling the rtc, even when stop is configured
181 pub _disable_rtc: bool,
124} 182}
125 183
126impl Default for RtcConfig { 184impl Default for RtcConfig {
127 /// LSI with prescalers assuming 32.768 kHz. 185 /// LSI with prescalers assuming 32.768 kHz.
128 /// Raw sub-seconds in 1/256. 186 /// Raw sub-seconds in 1/256.
129 fn default() -> Self { 187 fn default() -> Self {
130 RtcConfig { frequency: Hertz(256) } 188 RtcConfig {
189 frequency: Hertz(256),
190 #[cfg(feature = "_allow-disable-rtc")]
191 _disable_rtc: false,
192 }
131 } 193 }
132} 194}
133 195
@@ -145,8 +207,19 @@ pub enum RtcCalibrationCyclePeriod {
145} 207}
146 208
147impl Rtc { 209impl Rtc {
210 #[cfg(not(feature = "low-power"))]
211 /// Create a new RTC instance.
212 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> (Self, RtcTimeProvider) {
213 (Self::new_inner(rtc_config), RtcTimeProvider::new())
214 }
215
216 #[cfg(feature = "low-power")]
148 /// Create a new RTC instance. 217 /// Create a new RTC instance.
149 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { 218 pub fn new(_rtc: Peri<'static, RTC>) -> (RtcContainer, RtcTimeProvider) {
219 (RtcContainer::new(), RtcTimeProvider::new())
220 }
221
222 pub(self) fn new_inner(rtc_config: RtcConfig) -> Self {
150 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 223 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
151 crate::rcc::enable_and_reset::<RTC>(); 224 crate::rcc::enable_and_reset::<RTC>();
152 225
@@ -165,10 +238,13 @@ impl Rtc {
165 // Wait for the clock to update after initialization 238 // Wait for the clock to update after initialization
166 #[cfg(not(rtc_v2_f2))] 239 #[cfg(not(rtc_v2_f2))]
167 { 240 {
168 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); 241 let now = RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap();
169 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} 242 while now == RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap() {}
170 } 243 }
171 244
245 #[cfg(feature = "low-power")]
246 this.enable_wakeup_line();
247
172 this 248 this
173 } 249 }
174 250
@@ -177,11 +253,6 @@ impl Rtc {
177 freqs.rtc.to_hertz().unwrap() 253 freqs.rtc.to_hertz().unwrap()
178 } 254 }
179 255
180 /// Acquire a [`RtcTimeProvider`] instance.
181 pub const fn time_provider(&self) -> RtcTimeProvider {
182 RtcTimeProvider { _private: () }
183 }
184
185 /// Set the datetime to a new value. 256 /// Set the datetime to a new value.
186 /// 257 ///
187 /// # Errors 258 /// # Errors
@@ -225,15 +296,6 @@ impl Rtc {
225 Ok(()) 296 Ok(())
226 } 297 }
227 298
228 /// Return the current datetime.
229 ///
230 /// # Errors
231 ///
232 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
233 pub fn now(&self) -> Result<DateTime, RtcError> {
234 self.time_provider().now()
235 }
236
237 /// Check if daylight savings time is active. 299 /// Check if daylight savings time is active.
238 pub fn get_daylight_savings(&self) -> bool { 300 pub fn get_daylight_savings(&self) -> bool {
239 let cr = RTC::regs().cr().read(); 301 let cr = RTC::regs().cr().read();
@@ -315,3 +377,15 @@ trait SealedInstance {
315 377
316 // fn apply_config(&mut self, rtc_config: RtcConfig); 378 // fn apply_config(&mut self, rtc_config: RtcConfig);
317} 379}
380
381#[cfg(feature = "low-power")]
382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig) {
383 #[cfg(feature = "_allow-disable-rtc")]
384 if config._disable_rtc {
385 return;
386 }
387
388 crate::time_driver::get_driver().set_rtc(cs, Rtc::new_inner(config));
389
390 trace!("low power: stop with rtc configured");
391}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 23f6ccb0c..8ac022536 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -93,7 +93,7 @@ impl super::Rtc {
93 }) 93 })
94 } 94 }
95 95
96 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 96 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
97 where 97 where
98 F: FnOnce(crate::pac::rtc::Rtc) -> R, 98 F: FnOnce(crate::pac::rtc::Rtc) -> R,
99 { 99 {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 01da5d70a..f7ebea73e 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -95,7 +95,7 @@ impl super::Rtc {
95 }) 95 })
96 } 96 }
97 97
98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 98 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
99 where 99 where
100 F: FnOnce(crate::pac::rtc::Rtc) -> R, 100 F: FnOnce(crate::pac::rtc::Rtc) -> R,
101 { 101 {
@@ -131,7 +131,7 @@ impl SealedInstance for crate::peripherals::RTC {
131 131
132 #[cfg(feature = "low-power")] 132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(stm32g4)] { 134 if #[cfg(any(stm32g4, stm32wlex))] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
@@ -142,7 +142,7 @@ impl SealedInstance for crate::peripherals::RTC {
142 142
143 #[cfg(feature = "low-power")] 143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!( 144 cfg_if::cfg_if!(
145 if #[cfg(stm32g4)] { 145 if #[cfg(any(stm32g4, stm32wlex))] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] { 147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; 148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 408d1b764..e05131040 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -1032,12 +1032,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1032 1032
1033 /// Wait for a previously started datapath transfer to complete from an interrupt. 1033 /// Wait for a previously started datapath transfer to complete from an interrupt.
1034 #[inline] 1034 #[inline]
1035 #[allow(unused)]
1035 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { 1036 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> {
1036 let regs = T::regs();
1037
1038 let res = poll_fn(|cx| { 1037 let res = poll_fn(|cx| {
1038 // Compiler might not be sufficiently constrained here
1039 // https://github.com/embassy-rs/embassy/issues/4723
1039 T::state().register(cx.waker()); 1040 T::state().register(cx.waker());
1040 let status = regs.star().read(); 1041 let status = T::regs().star().read();
1041 1042
1042 if status.dcrcfail() { 1043 if status.dcrcfail() {
1043 return Poll::Ready(Err(Error::Crc)); 1044 return Poll::Ready(Err(Error::Crc));
@@ -1052,10 +1053,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1052 if status.stbiterr() { 1053 if status.stbiterr() {
1053 return Poll::Ready(Err(Error::StBitErr)); 1054 return Poll::Ready(Err(Error::StBitErr));
1054 } 1055 }
1056 #[cfg(sdmmc_v1)]
1055 let done = match block { 1057 let done = match block {
1056 true => status.dbckend(), 1058 true => status.dbckend(),
1057 false => status.dataend(), 1059 false => status.dataend(),
1058 }; 1060 };
1061 #[cfg(sdmmc_v2)]
1062 let done = status.dataend();
1059 if done { 1063 if done {
1060 return Poll::Ready(Ok(())); 1064 return Poll::Ready(Ok(()));
1061 } 1065 }
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c27d09ea7..abb80ed26 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -125,26 +125,69 @@ impl Config {
125 ) 125 )
126 } 126 }
127} 127}
128
129/// SPI communication mode
130pub mod mode {
131 use stm32_metapac::spi::vals;
132
133 trait SealedMode {}
134
135 /// Trait for SPI communication mode operations.
136 #[allow(private_bounds)]
137 pub trait CommunicationMode: SealedMode {
138 /// Spi communication mode
139 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
140 const MASTER: vals::Mstr;
141 /// Spi communication mode
142 #[cfg(any(spi_v4, spi_v5, spi_v6))]
143 const MASTER: vals::Master;
144 }
145
146 /// Mode allowing for SPI master operations.
147 pub struct Master;
148 /// Mode allowing for SPI slave operations.
149 pub struct Slave;
150
151 impl SealedMode for Master {}
152 impl CommunicationMode for Master {
153 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
154 const MASTER: vals::Mstr = vals::Mstr::MASTER;
155 #[cfg(any(spi_v4, spi_v5, spi_v6))]
156 const MASTER: vals::Master = vals::Master::MASTER;
157 }
158
159 impl SealedMode for Slave {}
160 impl CommunicationMode for Slave {
161 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
162 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
163 #[cfg(any(spi_v4, spi_v5, spi_v6))]
164 const MASTER: vals::Master = vals::Master::SLAVE;
165 }
166}
167use mode::{CommunicationMode, Master, Slave};
168
128/// SPI driver. 169/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 170pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 171 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 172 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 173 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 174 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 175 miso: Option<Peri<'d, AnyPin>>,
176 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 177 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 178 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 179 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 180 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 181 gpio_speed: Speed,
140} 182}
141 183
142impl<'d, M: PeriMode> Spi<'d, M> { 184impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 185 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 186 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 187 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 188 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 189 miso: Option<Peri<'d, AnyPin>>,
190 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 191 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 192 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 193 config: Config,
@@ -155,6 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 198 sck,
156 mosi, 199 mosi,
157 miso, 200 miso,
201 nss,
158 tx_dma, 202 tx_dma,
159 rx_dma, 203 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 204 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -183,12 +227,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
183 w.set_cpha(cpha); 227 w.set_cpha(cpha);
184 w.set_cpol(cpol); 228 w.set_cpol(cpol);
185 229
186 w.set_mstr(vals::Mstr::MASTER); 230 w.set_mstr(CM::MASTER);
187 w.set_br(br); 231 w.set_br(br);
188 w.set_spe(true); 232 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 233 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 234 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 235 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
192 w.set_crcen(false); 236 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 237 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 238 // we're doing "fake rxonly", by actually writing one
@@ -210,11 +254,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
210 w.set_cpha(cpha); 254 w.set_cpha(cpha);
211 w.set_cpol(cpol); 255 w.set_cpol(cpol);
212 256
213 w.set_mstr(vals::Mstr::MASTER); 257 w.set_mstr(CM::MASTER);
214 w.set_br(br); 258 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 259 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 260 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 261 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
218 w.set_crcen(false); 262 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 263 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 264 w.set_spe(true);
@@ -229,8 +273,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
229 w.set_cpha(cpha); 273 w.set_cpha(cpha);
230 w.set_cpol(cpol); 274 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 275 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 276 w.set_ssm(CM::MASTER == vals::Master::MASTER);
233 w.set_master(vals::Master::MASTER); 277 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 278 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 279 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 280 w.set_midi(0);
@@ -469,7 +513,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 513 }
470} 514}
471 515
472impl<'d> Spi<'d, Blocking> { 516impl<'d> Spi<'d, Blocking, Slave> {
517 /// Create a new blocking SPI slave driver.
518 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
519 peri: Peri<'d, T>,
520 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
521 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
522 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
523 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
524 config: Config,
525 ) -> Self {
526 Self::new_inner(
527 peri,
528 new_pin!(sck, config.sck_af()),
529 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
530 new_pin!(miso, AfType::input(config.miso_pull)),
531 new_pin!(cs, AfType::input(Pull::None)),
532 None,
533 None,
534 config,
535 )
536 }
537}
538
539impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 540 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 541 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 542 peri: Peri<'d, T>,
@@ -485,6 +552,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 552 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 553 None,
487 None, 554 None,
555 None,
488 config, 556 config,
489 ) 557 )
490 } 558 }
@@ -503,6 +571,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 571 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 572 None,
505 None, 573 None,
574 None,
506 config, 575 config,
507 ) 576 )
508 } 577 }
@@ -521,6 +590,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 590 None,
522 None, 591 None,
523 None, 592 None,
593 None,
524 config, 594 config,
525 ) 595 )
526 } 596 }
@@ -540,12 +610,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 610 None,
541 None, 611 None,
542 None, 612 None,
613 None,
614 config,
615 )
616 }
617}
618
619impl<'d> Spi<'d, Async, Slave> {
620 /// Create a new SPI slave driver.
621 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
622 peri: Peri<'d, T>,
623 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
624 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
625 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
626 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
627 tx_dma: Peri<'d, impl TxDma<T>>,
628 rx_dma: Peri<'d, impl RxDma<T>>,
629 config: Config,
630 ) -> Self {
631 Self::new_inner(
632 peri,
633 new_pin!(sck, config.sck_af()),
634 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
635 new_pin!(miso, AfType::input(config.miso_pull)),
636 new_pin!(cs, AfType::input(Pull::None)),
637 new_dma!(tx_dma),
638 new_dma!(rx_dma),
543 config, 639 config,
544 ) 640 )
545 } 641 }
546} 642}
547 643
548impl<'d> Spi<'d, Async> { 644impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 645 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 646 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 647 peri: Peri<'d, T>,
@@ -561,6 +657,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 657 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 658 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 659 new_pin!(miso, AfType::input(config.miso_pull)),
660 None,
564 new_dma!(tx_dma), 661 new_dma!(tx_dma),
565 new_dma!(rx_dma), 662 new_dma!(rx_dma),
566 config, 663 config,
@@ -581,6 +678,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 678 new_pin!(sck, config.sck_af()),
582 None, 679 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 680 new_pin!(miso, AfType::input(config.miso_pull)),
681 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 682 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 683 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 684 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,6 +701,7 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 701 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 702 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 703 None,
704 None,
606 new_dma!(tx_dma), 705 new_dma!(tx_dma),
607 None, 706 None,
608 config, 707 config,
@@ -623,6 +722,7 @@ impl<'d> Spi<'d, Async> {
623 None, 722 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 723 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 724 None,
725 None,
626 new_dma!(tx_dma), 726 new_dma!(tx_dma),
627 None, 727 None,
628 config, 728 config,
@@ -646,7 +746,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 746 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 747 config.frequency = freq;
648 748
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 749 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 750 }
651 751
652 #[allow(dead_code)] 752 #[allow(dead_code)]
@@ -656,9 +756,11 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 756 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 757 config: Config,
658 ) -> Self { 758 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 759 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 760 }
761}
661 762
763impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 764 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 765 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
664 if data.is_empty() { 766 if data.is_empty() {
@@ -888,11 +990,12 @@ impl<'d> Spi<'d, Async> {
888 } 990 }
889} 991}
890 992
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 993impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 994 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 995 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 996 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 997 self.miso.as_ref().map(|x| x.set_as_disconnected());
998 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 999
897 self.info.rcc.disable(); 1000 self.info.rcc.disable();
898 } 1001 }
@@ -1127,7 +1230,7 @@ fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1127// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 1230// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1231macro_rules! impl_blocking {
1129 ($w:ident) => { 1232 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1233 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1234 type Error = Error;
1132 1235
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1236 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1238,7 @@ macro_rules! impl_blocking {
1135 } 1238 }
1136 } 1239 }
1137 1240
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1241 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1242 type Error = Error;
1140 1243
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1244 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1252,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1252impl_blocking!(u8);
1150impl_blocking!(u16); 1253impl_blocking!(u16);
1151 1254
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1255impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1256 type Error = Error;
1154} 1257}
1155 1258
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1259impl<'d, W: Word, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M, CM> {
1157 fn flush(&mut self) -> Result<(), Self::Error> { 1260 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1261 Ok(())
1159 } 1262 }
@@ -1186,7 +1289,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1289 }
1187} 1290}
1188 1291
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1292impl<'d, W: Word, CM: CommunicationMode> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async, CM> {
1190 async fn flush(&mut self) -> Result<(), Self::Error> { 1293 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1294 Ok(())
1192 } 1295 }
@@ -1328,7 +1431,7 @@ foreach_peripheral!(
1328 }; 1431 };
1329); 1432);
1330 1433
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1434impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1435 type Config = Config;
1333 type ConfigError = (); 1436 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1437 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 74b10a183..7db51d72e 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,6 +1,8 @@
1#![allow(non_snake_case)] 1#![allow(non_snake_case)]
2 2
3use core::cell::{Cell, RefCell}; 3use core::cell::{Cell, RefCell};
4#[cfg(all(feature = "low-power", stm32wlex))]
5use core::sync::atomic::AtomicU16;
4use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; 6use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
5 7
6use critical_section::CriticalSection; 8use critical_section::CriticalSection;
@@ -213,7 +215,13 @@ pub(crate) struct RtcDriver {
213 period: AtomicU32, 215 period: AtomicU32,
214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>, 216 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
215 #[cfg(feature = "low-power")] 217 #[cfg(feature = "low-power")]
216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 218 pub(crate) rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
219 #[cfg(feature = "low-power")]
220 /// The minimum pause time beyond which the executor will enter a low-power state.
221 min_stop_pause: Mutex<CriticalSectionRawMutex, Cell<embassy_time::Duration>>,
222 /// Saved count for the timer (its value is lost when entering STOP2)
223 #[cfg(all(feature = "low-power", stm32wlex))]
224 saved_count: AtomicU16,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 225 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
218} 226}
219 227
@@ -221,12 +229,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
221 period: AtomicU32::new(0), 229 period: AtomicU32::new(0),
222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 230 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
223 #[cfg(feature = "low-power")] 231 #[cfg(feature = "low-power")]
224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 232 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)),
233 #[cfg(feature = "low-power")]
234 min_stop_pause: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(embassy_time::Duration::from_millis(0))),
235 #[cfg(all(feature = "low-power", stm32wlex))]
236 saved_count: AtomicU16::new(0),
225 queue: Mutex::new(RefCell::new(Queue::new())) 237 queue: Mutex::new(RefCell::new(Queue::new()))
226}); 238});
227 239
228impl RtcDriver { 240impl RtcDriver {
229 fn init(&'static self, cs: critical_section::CriticalSection) { 241 /// initialize the timer, but don't start it. Used for chips like stm32wle5
242 /// for low power where the timer config is lost in STOP2.
243 fn init_timer(&'static self, cs: critical_section::CriticalSection) {
230 let r = regs_gp16(); 244 let r = regs_gp16();
231 245
232 rcc::enable_and_reset_with_cs::<T>(cs); 246 rcc::enable_and_reset_with_cs::<T>(cs);
@@ -259,10 +273,16 @@ impl RtcDriver {
259 w.set_ccie(0, true); 273 w.set_ccie(0, true);
260 }); 274 });
261 275
276 #[cfg(all(feature = "low-power", stm32wlex))]
277 r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst)));
278
262 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend(); 279 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend();
263 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() }; 280 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() };
281 }
264 282
265 r.cr1().modify(|w| w.set_cen(true)); 283 fn init(&'static self, cs: CriticalSection) {
284 self.init_timer(cs);
285 regs_gp16().cr1().modify(|w| w.set_cen(true));
266 } 286 }
267 287
268 fn on_interrupt(&self) { 288 fn on_interrupt(&self) {
@@ -379,27 +399,26 @@ impl RtcDriver {
379 #[cfg(feature = "low-power")] 399 #[cfg(feature = "low-power")]
380 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 400 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
381 fn stop_wakeup_alarm(&self, cs: CriticalSection) { 401 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
382 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { 402 if let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) {
383 self.add_time(offset, cs); 403 self.add_time(offset, cs);
384 } 404 }
385 } 405 }
386 406
387 /* 407 /*
388 Low-power public functions: all create a critical section 408 Low-power public functions: all create or require a critical section
389 */ 409 */
390 #[cfg(feature = "low-power")] 410 #[cfg(feature = "low-power")]
391 /// Set the rtc but panic if it's already been set 411 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) {
392 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { 412 self.min_stop_pause.borrow(cs).replace(min_stop_pause);
393 critical_section::with(|cs| {
394 rtc.stop_wakeup_alarm(cs);
395
396 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())
397 });
398 } 413 }
399 414
400 #[cfg(feature = "low-power")] 415 #[cfg(feature = "low-power")]
401 /// The minimum pause time beyond which the executor will enter a low-power state. 416 /// Set the rtc but panic if it's already been set
402 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); 417 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) {
418 rtc.stop_wakeup_alarm(cs);
419
420 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none());
421 }
403 422
404 #[cfg(feature = "low-power")] 423 #[cfg(feature = "low-power")]
405 /// Pause the timer if ready; return err if not 424 /// Pause the timer if ready; return err if not
@@ -413,17 +432,25 @@ impl RtcDriver {
413 self.stop_wakeup_alarm(cs); 432 self.stop_wakeup_alarm(cs);
414 433
415 let time_until_next_alarm = self.time_until_next_alarm(cs); 434 let time_until_next_alarm = self.time_until_next_alarm(cs);
416 if time_until_next_alarm < Self::MIN_STOP_PAUSE { 435 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() {
436 trace!(
437 "time_until_next_alarm < self.min_stop_pause ({})",
438 time_until_next_alarm
439 );
417 Err(()) 440 Err(())
418 } else { 441 } else {
419 self.rtc 442 self.rtc
420 .borrow(cs) 443 .borrow(cs)
421 .get() 444 .borrow_mut()
445 .as_mut()
422 .unwrap() 446 .unwrap()
423 .start_wakeup_alarm(time_until_next_alarm, cs); 447 .start_wakeup_alarm(time_until_next_alarm, cs);
424 448
425 regs_gp16().cr1().modify(|w| w.set_cen(false)); 449 regs_gp16().cr1().modify(|w| w.set_cen(false));
426 450 // save the count for the timer as its lost in STOP2 for stm32wlex
451 #[cfg(stm32wlex)]
452 self.saved_count
453 .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst);
427 Ok(()) 454 Ok(())
428 } 455 }
429 }) 456 })
@@ -431,18 +458,16 @@ impl RtcDriver {
431 458
432 #[cfg(feature = "low-power")] 459 #[cfg(feature = "low-power")]
433 /// Resume the timer with the given offset 460 /// Resume the timer with the given offset
434 pub(crate) fn resume_time(&self) { 461 pub(crate) fn resume_time(&self, cs: CriticalSection) {
435 if regs_gp16().cr1().read().cen() { 462 if regs_gp16().cr1().read().cen() {
436 // Time isn't currently stopped 463 // Time isn't currently stopped
437 464
438 return; 465 return;
439 } 466 }
440 467
441 critical_section::with(|cs| { 468 self.stop_wakeup_alarm(cs);
442 self.stop_wakeup_alarm(cs);
443 469
444 regs_gp16().cr1().modify(|w| w.set_cen(true)); 470 regs_gp16().cr1().modify(|w| w.set_cen(true));
445 })
446 } 471 }
447 472
448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 473 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
@@ -514,10 +539,15 @@ impl Driver for RtcDriver {
514} 539}
515 540
516#[cfg(feature = "low-power")] 541#[cfg(feature = "low-power")]
517pub(crate) fn get_driver() -> &'static RtcDriver { 542pub(crate) const fn get_driver() -> &'static RtcDriver {
518 &DRIVER 543 &DRIVER
519} 544}
520 545
521pub(crate) fn init(cs: CriticalSection) { 546pub(crate) fn init(cs: CriticalSection) {
522 DRIVER.init(cs) 547 DRIVER.init(cs)
523} 548}
549
550#[cfg(all(feature = "low-power", stm32wlex))]
551pub(crate) fn init_timer(cs: CriticalSection) {
552 DRIVER.init_timer(cs)
553}
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 75a83629c..9a56a41fb 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -2,7 +2,7 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr}; 5pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr};
6 6
7use super::low_level::{CountingMode, OutputPolarity, Timer}; 7use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin; 8use super::simple_pwm::PwmPin;
@@ -136,6 +136,16 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
136 self.inner.get_moe() 136 self.inner.get_moe()
137 } 137 }
138 138
139 /// Set Master Slave Mode 2
140 pub fn set_mms2(&mut self, mms2: Mms2) {
141 self.inner.set_mms2_selection(mms2);
142 }
143
144 /// Set Repetition Counter
145 pub fn set_repetition_counter(&mut self, val: u16) {
146 self.inner.set_repetition_counter(val);
147 }
148
139 /// Enable the given channel. 149 /// Enable the given channel.
140 pub fn enable(&mut self, channel: Channel) { 150 pub fn enable(&mut self, channel: Channel) {
141 self.inner.enable_channel(channel, true); 151 self.inner.enable_channel(channel, true);
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index ac039bb0d..0122fe4f7 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -10,7 +10,7 @@ use core::mem::ManuallyDrop;
10 10
11use embassy_hal_internal::Peri; 11use embassy_hal_internal::Peri;
12// Re-export useful enums 12// Re-export useful enums
13pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; 13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource};
14 14
15use super::*; 15use super::*;
16use crate::pac::timer::vals; 16use crate::pac::timer::vals;
@@ -143,20 +143,69 @@ pub enum OutputCompareMode {
143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as 143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
144 /// TIMx_CNT>TIMx_CCRx else inactive. 144 /// TIMx_CNT>TIMx_CCRx else inactive.
145 PwmMode2, 145 PwmMode2,
146 // TODO: there's more modes here depending on the chip family. 146
147 #[cfg(timer_v2)]
148 /// In up-counting mode, the channel is active until a trigger
149 /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM
150 /// mode 1 and the channels becomes active again at the next update. In down-counting
151 /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal).
152 /// Then, a comparison is performed as in PWM mode 1 and the channels becomes
153 /// inactive again at the next update.
154 OnePulseMode1,
155
156 #[cfg(timer_v2)]
157 /// In up-counting mode, the channel is inactive until a
158 /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in
159 /// PWM mode 2 and the channels becomes inactive again at the next update. In down
160 /// counting mode, the channel is active until a trigger event is detected (on tim_trgi
161 /// signal). Then, a comparison is performed as in PWM mode 1 and the channels
162 /// becomes active again at the next update.
163 OnePulseMode2,
164
165 #[cfg(timer_v2)]
166 /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1.
167 /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref.
168 CombinedPwmMode1,
169
170 #[cfg(timer_v2)]
171 /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2.
172 /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref.
173 CombinedPwmMode2,
174
175 #[cfg(timer_v2)]
176 /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref
177 /// when the counter is counting up, tim_oc2ref when it is counting down.
178 AsymmetricPwmMode1,
179
180 #[cfg(timer_v2)]
181 /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref
182 /// when the counter is counting up, tim_oc2ref when it is counting down.
183 AsymmetricPwmMode2,
147} 184}
148 185
149impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 186impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm {
150 fn from(mode: OutputCompareMode) -> Self { 187 fn from(mode: OutputCompareMode) -> Self {
151 match mode { 188 match mode {
152 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, 189 OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN,
153 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, 190 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH,
154 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, 191 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH,
155 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, 192 OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE,
156 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, 193 OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE,
157 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, 194 OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE,
158 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, 195 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1,
159 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, 196 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2,
197 #[cfg(timer_v2)]
198 OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1,
199 #[cfg(timer_v2)]
200 OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2,
201 #[cfg(timer_v2)]
202 OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1,
203 #[cfg(timer_v2)]
204 OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2,
205 #[cfg(timer_v2)]
206 OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1,
207 #[cfg(timer_v2)]
208 OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2,
160 } 209 }
161 } 210 }
162} 211}
@@ -640,6 +689,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
640 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) 689 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
641 } 690 }
642 691
692 /// Set Timer Master Mode
693 pub fn set_master_mode(&self, mms: MasterMode) {
694 self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
695 }
696
643 /// Set Timer Slave Mode 697 /// Set Timer Slave Mode
644 pub fn set_slave_mode(&self, sms: SlaveMode) { 698 pub fn set_slave_mode(&self, sms: SlaveMode) {
645 self.regs_gp16().smcr().modify(|r| r.set_sms(sms)); 699 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
@@ -760,6 +814,16 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
760 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val)); 814 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
761 } 815 }
762 816
817 /// Set master mode selection 2
818 pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
819 self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
820 }
821
822 /// Set repetition counter
823 pub fn set_repetition_counter(&self, val: u16) {
824 self.regs_advanced().rcr().modify(|w| w.set_rep(val));
825 }
826
763 /// Trigger software break 1 or 2 827 /// Trigger software break 1 or 2
764 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware. 828 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
765 pub fn trigger_software_break(&self, n: usize) { 829 pub fn trigger_software_break(&self, n: usize) {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index b09bc7166..804d1ef37 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -399,7 +399,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> {
399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { 399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
400 unsafe fn on_interrupt() { 400 unsafe fn on_interrupt() {
401 #[cfg(feature = "low-power")] 401 #[cfg(feature = "low-power")]
402 crate::low_power::on_wakeup_irq(); 402 crate::low_power::Executor::on_wakeup_irq();
403 403
404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); 404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
405 405
@@ -429,7 +429,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
429{ 429{
430 unsafe fn on_interrupt() { 430 unsafe fn on_interrupt() {
431 #[cfg(feature = "low-power")] 431 #[cfg(feature = "low-power")]
432 crate::low_power::on_wakeup_irq(); 432 crate::low_power::Executor::on_wakeup_irq();
433 433
434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); 434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
435 435
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index 5e38532bd..2d3e2b972 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -1,8 +1,8 @@
1//! Unique ID (UID) 1//! Unique ID (UID)
2 2
3/// Get this device's unique 96-bit ID. 3/// Get this device's unique 96-bit ID.
4pub fn uid() -> &'static [u8; 12] { 4pub fn uid() -> [u8; 12] {
5 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } 5 unsafe { *crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
6} 6}
7 7
8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits. 8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits.
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 20bfefd9e..bac570d27 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -7,7 +7,9 @@ use embassy_embedded_hal::SetConfig;
7use embedded_io_async::ReadReady; 7use embedded_io_async::ReadReady;
8use futures_util::future::{Either, select}; 8use futures_util::future::{Either, select};
9 9
10use super::{Config, ConfigError, Error, Info, State, UartRx, rdr, reconfigure, set_baudrate, sr}; 10use super::{
11 Config, ConfigError, Error, Info, State, UartRx, clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr,
12};
11use crate::Peri; 13use crate::Peri;
12use crate::dma::ReadableRingBuffer; 14use crate::dma::ReadableRingBuffer;
13use crate::gpio::{AnyPin, SealedPin as _}; 15use crate::gpio::{AnyPin, SealedPin as _};
@@ -338,26 +340,16 @@ impl Drop for RingBufferedUartRx<'_> {
338/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags 340/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags
339/// are cleared by a single read to the RDR register. 341/// are cleared by a single read to the RDR register.
340fn check_idle_and_errors(r: Regs) -> Result<bool, Error> { 342fn check_idle_and_errors(r: Regs) -> Result<bool, Error> {
341 // Critical section is required so that the flags aren't set after read and before clear 343 // SAFETY: read only and we only use Rx related flags
342 let sr = critical_section::with(|_| { 344 let sr = sr(r).read();
343 // SAFETY: read only and we only use Rx related flags 345
344 let sr = sr(r).read(); 346 #[cfg(not(any(usart_v3, usart_v4)))]
345 347 unsafe {
346 #[cfg(any(usart_v3, usart_v4))] 348 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
347 r.icr().write(|w| { 349 rdr(r).read_volatile()
348 w.set_idle(true); 350 };
349 w.set_pe(true); 351 clear_interrupt_flags(r, sr);
350 w.set_fe(true); 352
351 w.set_ne(true);
352 w.set_ore(true);
353 });
354 #[cfg(not(any(usart_v3, usart_v4)))]
355 unsafe {
356 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
357 rdr(r).read_volatile()
358 };
359 sr
360 });
361 if sr.pe() { 353 if sr.pe() {
362 Err(Error::Parity) 354 Err(Error::Parity)
363 } else if sr.fe() { 355 } else if sr.fe() {
diff --git a/embassy-stm32/src/vrefbuf/mod.rs b/embassy-stm32/src/vrefbuf/mod.rs
index b061306a0..43dd9c800 100644
--- a/embassy-stm32/src/vrefbuf/mod.rs
+++ b/embassy-stm32/src/vrefbuf/mod.rs
@@ -14,10 +14,10 @@ pub struct VoltageReferenceBuffer<'d, T: Instance> {
14#[cfg(rcc_wba)] 14#[cfg(rcc_wba)]
15fn get_refbuf_trim(voltage_scale: Vrs) -> usize { 15fn get_refbuf_trim(voltage_scale: Vrs) -> usize {
16 match voltage_scale { 16 match voltage_scale {
17 Vrs::VREF0 => 0x0BFA_07A8usize, 17 Vrs::VREF0 => 0x0BFA_07ABusize,
18 Vrs::VREF1 => 0x0BFA_07A9usize, 18 Vrs::VREF1 => 0x0BFA_07AAusize,
19 Vrs::VREF2 => 0x0BFA_07AAusize, 19 Vrs::VREF2 => 0x0BFA_07A9usize,
20 Vrs::VREF3 => 0x0BFA_07ABusize, 20 Vrs::VREF3 => 0x0BFA_07A8usize,
21 _ => panic!("Incorrect Vrs setting!"), 21 _ => panic!("Incorrect Vrs setting!"),
22 } 22 }
23} 23}