aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authoreZio Pan <[email protected]>2024-01-02 11:55:09 +0800
committerGitHub <[email protected]>2024-01-02 11:55:09 +0800
commitf5a218a018d3ecd899db0ec5460a4e00dac78abe (patch)
treef4bce8b63044bf2de9277385d229b4dbaf4c53e2 /embassy-stm32
parent873ee0615147b4a4e0aacd069ce8ac8df611bbbf (diff)
parent9c2d2ff64d302437e2e0568372c76bf37bbfacf4 (diff)
Merge branch 'embassy-rs:main' into simplepwm-dma
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/src/i2c/v1.rs20
-rw-r--r--embassy-stm32/src/lib.rs50
-rw-r--r--embassy-stm32/src/rtc/mod.rs20
-rw-r--r--embassy-stm32/src/rtc/v3.rs6
-rw-r--r--embassy-stm32/src/usart/mod.rs87
-rw-r--r--embassy-stm32/src/usb/usb.rs6
6 files changed, 147 insertions, 42 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index df5b44c2d..cbbc201de 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -1,3 +1,9 @@
1//! # I2Cv1
2//!
3//! This implementation is used for STM32F1, STM32F2, STM32F4, and STM32L1 devices.
4//!
5//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead.
6
1use core::future::poll_fn; 7use core::future::poll_fn;
2use core::task::Poll; 8use core::task::Poll;
3 9
@@ -10,6 +16,17 @@ use crate::dma::Transfer;
10use crate::pac::i2c; 16use crate::pac::i2c;
11use crate::time::Hertz; 17use crate::time::Hertz;
12 18
19// /!\ /!\
20// /!\ Implementation note! /!\
21// /!\ /!\
22//
23// It's somewhat unclear whether using interrupts here in a *strictly* one-shot style is actually
24// what we want! If you are looking in this file because you are doing async I2C and your code is
25// just totally hanging (sometimes), maybe swing by this issue:
26// <https://github.com/embassy-rs/embassy/issues/2372>.
27//
28// There's some more details there, and we might have a fix for you. But please let us know if you
29// hit a case like this!
13pub unsafe fn on_interrupt<T: Instance>() { 30pub unsafe fn on_interrupt<T: Instance>() {
14 let regs = T::regs(); 31 let regs = T::regs();
15 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 32 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
@@ -375,6 +392,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
375 T::regs().sr2().read(); 392 T::regs().sr2().read();
376 Poll::Ready(Ok(())) 393 Poll::Ready(Ok(()))
377 } else { 394 } else {
395 // If we need to go around, then re-enable the interrupts, otherwise nothing
396 // can wake us up and we'll hang.
397 Self::enable_interrupts();
378 Poll::Pending 398 Poll::Pending
379 } 399 }
380 } 400 }
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 207f7ed8f..f10e9d50d 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -208,32 +208,30 @@ pub fn init(config: Config) -> Peripherals {
208 let p = Peripherals::take_with_cs(cs); 208 let p = Peripherals::take_with_cs(cs);
209 209
210 #[cfg(dbgmcu)] 210 #[cfg(dbgmcu)]
211 if config.enable_debug_during_sleep { 211 crate::pac::DBGMCU.cr().modify(|cr| {
212 crate::pac::DBGMCU.cr().modify(|cr| { 212 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
213 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] 213 {
214 { 214 cr.set_dbg_stop(config.enable_debug_during_sleep);
215 cr.set_dbg_stop(true); 215 cr.set_dbg_standby(config.enable_debug_during_sleep);
216 cr.set_dbg_standby(true); 216 }
217 } 217 #[cfg(any(
218 #[cfg(any( 218 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
219 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 219 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
220 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 220 ))]
221 ))] 221 {
222 { 222 cr.set_dbg_sleep(config.enable_debug_during_sleep);
223 cr.set_dbg_sleep(true); 223 cr.set_dbg_stop(config.enable_debug_during_sleep);
224 cr.set_dbg_stop(true); 224 cr.set_dbg_standby(config.enable_debug_during_sleep);
225 cr.set_dbg_standby(true); 225 }
226 } 226 #[cfg(dbgmcu_h7)]
227 #[cfg(dbgmcu_h7)] 227 {
228 { 228 cr.set_d1dbgcken(config.enable_debug_during_sleep);
229 cr.set_d1dbgcken(true); 229 cr.set_d3dbgcken(config.enable_debug_during_sleep);
230 cr.set_d3dbgcken(true); 230 cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
231 cr.set_dbgsleep_d1(true); 231 cr.set_dbgstby_d1(config.enable_debug_during_sleep);
232 cr.set_dbgstby_d1(true); 232 cr.set_dbgstop_d1(config.enable_debug_during_sleep);
233 cr.set_dbgstop_d1(true); 233 }
234 } 234 });
235 });
236 }
237 235
238 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] 236 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
239 peripherals::SYSCFG::enable_and_reset_with_cs(cs); 237 peripherals::SYSCFG::enable_and_reset_with_cs(cs);
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 65e8713f0..1ffb567b3 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -24,7 +24,7 @@ use crate::time::Hertz;
24 ), 24 ),
25 path = "v2.rs" 25 path = "v2.rs"
26)] 26)]
27#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] 27#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")]
28mod _version; 28mod _version;
29#[allow(unused_imports)] 29#[allow(unused_imports)]
30pub use _version::*; 30pub use _version::*;
@@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler {
43 Div16 = 16, 43 Div16 = 16,
44} 44}
45 45
46#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] 46#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
47impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 47impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
48 fn from(val: WakeupPrescaler) -> Self { 48 fn from(val: WakeupPrescaler) -> Self {
49 use crate::pac::rtc::vals::Wucksel; 49 use crate::pac::rtc::vals::Wucksel;
@@ -57,7 +57,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
57 } 57 }
58} 58}
59 59
60#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] 60#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
61impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 61impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
62 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 62 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
63 use crate::pac::rtc::vals::Wucksel; 63 use crate::pac::rtc::vals::Wucksel;
@@ -348,7 +348,7 @@ impl Rtc {
348 ) { 348 ) {
349 use embassy_time::{Duration, TICK_HZ}; 349 use embassy_time::{Duration, TICK_HZ};
350 350
351 #[cfg(any(rtc_v3, rtc_v3u5))] 351 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
352 use crate::pac::rtc::vals::Calrf; 352 use crate::pac::rtc::vals::Calrf;
353 353
354 // Panic if the rcc mod knows we're not using low-power rtc 354 // Panic if the rcc mod knows we're not using low-power rtc
@@ -375,7 +375,7 @@ impl Rtc {
375 while !regs.isr().read().wutwf() {} 375 while !regs.isr().read().wutwf() {}
376 } 376 }
377 377
378 #[cfg(any(rtc_v3, rtc_v3u5))] 378 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
379 { 379 {
380 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 380 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
381 while !regs.icsr().read().wutwf() {} 381 while !regs.icsr().read().wutwf() {}
@@ -404,7 +404,7 @@ impl Rtc {
404 /// was called, otherwise none 404 /// was called, otherwise none
405 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 405 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
406 use crate::interrupt::typelevel::Interrupt; 406 use crate::interrupt::typelevel::Interrupt;
407 #[cfg(any(rtc_v3, rtc_v3u5))] 407 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
408 use crate::pac::rtc::vals::Calrf; 408 use crate::pac::rtc::vals::Calrf;
409 409
410 let instant = self.instant().unwrap(); 410 let instant = self.instant().unwrap();
@@ -420,13 +420,19 @@ impl Rtc {
420 ))] 420 ))]
421 regs.isr().modify(|w| w.set_wutf(false)); 421 regs.isr().modify(|w| w.set_wutf(false));
422 422
423 #[cfg(any(rtc_v3, rtc_v3u5))] 423 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
424 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 424 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
425 425
426 #[cfg(not(stm32l5))]
426 crate::pac::EXTI 427 crate::pac::EXTI
427 .pr(0) 428 .pr(0)
428 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 429 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
429 430
431 #[cfg(stm32l5)]
432 crate::pac::EXTI
433 .fpr(0)
434 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
435
430 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); 436 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
431 }); 437 });
432 } 438 }
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 902776b0a..114141b64 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -135,6 +135,12 @@ impl sealed::Instance for crate::peripherals::RTC {
135 #[cfg(all(feature = "low-power", stm32g4))] 135 #[cfg(all(feature = "low-power", stm32g4))]
136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
137 137
138 #[cfg(all(feature = "low-power", stm32l5))]
139 const EXTI_WAKEUP_LINE: usize = 17;
140
141 #[cfg(all(feature = "low-power", stm32l5))]
142 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
143
138 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { 144 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
139 #[allow(clippy::if_same_then_else)] 145 #[allow(clippy::if_same_then_else)]
140 if register < Self::BACKUP_REGISTER_COUNT { 146 if register < Self::BACKUP_REGISTER_COUNT {
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 8a0c85d2c..ea727b010 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -743,7 +743,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
743 T::enable_and_reset(); 743 T::enable_and_reset();
744 T::enable_and_reset(); 744 T::enable_and_reset();
745 745
746 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 746 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
747 } 747 }
748 748
749 /// Create a new bidirectional UART with request-to-send and clear-to-send pins 749 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
@@ -770,7 +770,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
770 w.set_rtse(true); 770 w.set_rtse(true);
771 w.set_ctse(true); 771 w.set_ctse(true);
772 }); 772 });
773 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 773 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
774 } 774 }
775 775
776 #[cfg(not(any(usart_v1, usart_v2)))] 776 #[cfg(not(any(usart_v1, usart_v2)))]
@@ -795,10 +795,76 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
795 T::regs().cr3().write(|w| { 795 T::regs().cr3().write(|w| {
796 w.set_dem(true); 796 w.set_dem(true);
797 }); 797 });
798 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 798 Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
799 } 799 }
800 800
801 fn new_inner( 801 /// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
802 ///
803 /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin.
804 /// There is no functional difference between these methods, as both allow bidirectional communication.
805 ///
806 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
807 /// I/O in idle or in reception.
808 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
809 /// on the line must be managed by software (for instance by using a centralized arbiter).
810 #[cfg(not(any(usart_v1, usart_v2)))]
811 #[doc(alias("HDSEL"))]
812 pub fn new_half_duplex(
813 peri: impl Peripheral<P = T> + 'd,
814 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
815 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
816 tx_dma: impl Peripheral<P = TxDma> + 'd,
817 rx_dma: impl Peripheral<P = RxDma> + 'd,
818 mut config: Config,
819 ) -> Result<Self, ConfigError> {
820 // UartRx and UartTx have one refcount ea.
821 T::enable_and_reset();
822 T::enable_and_reset();
823
824 config.swap_rx_tx = false;
825
826 into_ref!(peri, tx, tx_dma, rx_dma);
827
828 T::regs().cr3().write(|w| w.set_hdsel(true));
829 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
830
831 Self::new_inner(peri, tx_dma, rx_dma, config)
832 }
833
834 /// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
835 ///
836 /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin.
837 /// There is no functional difference between these methods, as both allow bidirectional communication.
838 ///
839 /// The pin is always released when no data is transmitted. Thus, it acts as a standard
840 /// I/O in idle or in reception.
841 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
842 /// on the line must be managed by software (for instance by using a centralized arbiter).
843 #[cfg(not(any(usart_v1, usart_v2)))]
844 #[doc(alias("HDSEL"))]
845 pub fn new_half_duplex_on_rx(
846 peri: impl Peripheral<P = T> + 'd,
847 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
848 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
849 tx_dma: impl Peripheral<P = TxDma> + 'd,
850 rx_dma: impl Peripheral<P = RxDma> + 'd,
851 mut config: Config,
852 ) -> Result<Self, ConfigError> {
853 // UartRx and UartTx have one refcount ea.
854 T::enable_and_reset();
855 T::enable_and_reset();
856
857 config.swap_rx_tx = true;
858
859 into_ref!(peri, rx, tx_dma, rx_dma);
860
861 T::regs().cr3().write(|w| w.set_hdsel(true));
862 rx.set_as_af(rx.af_num(), AFType::OutputPushPull);
863
864 Self::new_inner(peri, tx_dma, rx_dma, config)
865 }
866
867 fn new_inner_configure(
802 peri: impl Peripheral<P = T> + 'd, 868 peri: impl Peripheral<P = T> + 'd,
803 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 869 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
804 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 870 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@@ -808,8 +874,6 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
808 ) -> Result<Self, ConfigError> { 874 ) -> Result<Self, ConfigError> {
809 into_ref!(peri, rx, tx, tx_dma, rx_dma); 875 into_ref!(peri, rx, tx, tx_dma, rx_dma);
810 876
811 let r = T::regs();
812
813 // Some chips do not have swap_rx_tx bit 877 // Some chips do not have swap_rx_tx bit
814 cfg_if::cfg_if! { 878 cfg_if::cfg_if! {
815 if #[cfg(any(usart_v3, usart_v4))] { 879 if #[cfg(any(usart_v3, usart_v4))] {
@@ -827,6 +891,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
827 } 891 }
828 } 892 }
829 893
894 Self::new_inner(peri, tx_dma, rx_dma, config)
895 }
896
897 fn new_inner(
898 peri: PeripheralRef<'d, T>,
899 tx_dma: PeripheralRef<'d, TxDma>,
900 rx_dma: PeripheralRef<'d, RxDma>,
901 config: Config,
902 ) -> Result<Self, ConfigError> {
903 let r = T::regs();
904
830 configure(r, &config, T::frequency(), T::KIND, true, true)?; 905 configure(r, &config, T::frequency(), T::KIND, true, true)?;
831 906
832 T::Interrupt::unpend(); 907 T::Interrupt::unpend();
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index a8aebfe1f..04b1b35e8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -701,10 +701,10 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
701 } 701 }
702 702
703 async fn wait_enabled(&mut self) { 703 async fn wait_enabled(&mut self) {
704 trace!("wait_enabled OUT WAITING"); 704 trace!("wait_enabled IN WAITING");
705 let index = self.info.addr.index(); 705 let index = self.info.addr.index();
706 poll_fn(|cx| { 706 poll_fn(|cx| {
707 EP_OUT_WAKERS[index].register(cx.waker()); 707 EP_IN_WAKERS[index].register(cx.waker());
708 let regs = T::regs(); 708 let regs = T::regs();
709 if regs.epr(index).read().stat_tx() == Stat::DISABLED { 709 if regs.epr(index).read().stat_tx() == Stat::DISABLED {
710 Poll::Pending 710 Poll::Pending
@@ -713,7 +713,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
713 } 713 }
714 }) 714 })
715 .await; 715 .await;
716 trace!("wait_enabled OUT OK"); 716 trace!("wait_enabled IN OK");
717 } 717 }
718} 718}
719 719