aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorMatteo Meluzzi <[email protected]>2025-10-02 10:53:31 +0200
committerMatteo Meluzzi <[email protected]>2025-10-02 10:53:31 +0200
commit828a8df18d04877df1f55f04354980b28ff2f2f8 (patch)
treec4fa405f5eba7a14b6d435d6cc746c9e0dc52632 /embassy-stm32/src
parent176649e71ad442ca9856af6c11989b0b2f228c4b (diff)
parent194a721d0eab929a2af0a2a4e45ca8e70e0d3f0a (diff)
Merge branch 'main' into 17-add-support-for-boot-protocol
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/rcc/bd.rs10
-rw-r--r--embassy-stm32/src/rcc/c0.rs14
-rw-r--r--embassy-stm32/src/rcc/mco.rs23
-rw-r--r--embassy-stm32/src/rtc/low_power.rs36
-rw-r--r--embassy-stm32/src/rtc/mod.rs21
-rw-r--r--embassy-stm32/src/rtc/v2.rs8
-rw-r--r--embassy-stm32/src/timer/qei.rs100
-rw-r--r--embassy-stm32/src/usart/buffered.rs67
-rw-r--r--embassy-stm32/src/usart/mod.rs71
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs118
10 files changed, 321 insertions, 147 deletions
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index e2c704405..63fc195dd 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -52,9 +52,9 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
52 } 52 }
53} 53}
54 54
55#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] 55#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))]
56type Bdcr = crate::pac::rcc::regs::Bdcr; 56type Bdcr = crate::pac::rcc::regs::Bdcr;
57#[cfg(any(rtc_v2l0, rtc_v2l1))] 57#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
58type Bdcr = crate::pac::rcc::regs::Csr; 58type Bdcr = crate::pac::rcc::regs::Csr;
59#[cfg(any(stm32c0))] 59#[cfg(any(stm32c0))]
60type Bdcr = crate::pac::rcc::regs::Csr1; 60type Bdcr = crate::pac::rcc::regs::Csr1;
@@ -76,9 +76,9 @@ fn unlock() {
76} 76}
77 77
78fn bdcr() -> Reg<Bdcr, RW> { 78fn bdcr() -> Reg<Bdcr, RW> {
79 #[cfg(any(rtc_v2l0, rtc_v2l1))] 79 #[cfg(any(rtc_v2_l0, rtc_v2_l1))]
80 return crate::pac::RCC.csr(); 80 return crate::pac::RCC.csr();
81 #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] 81 #[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))]
82 return crate::pac::RCC.bdcr(); 82 return crate::pac::RCC.bdcr();
83 #[cfg(any(stm32c0))] 83 #[cfg(any(stm32c0))]
84 return crate::pac::RCC.csr1(); 84 return crate::pac::RCC.csr1();
@@ -273,7 +273,7 @@ impl LsConfig {
273 273
274 if self.rtc != RtcClockSource::DISABLE { 274 if self.rtc != RtcClockSource::DISABLE {
275 bdcr().modify(|w| { 275 bdcr().modify(|w| {
276 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] 276 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))]
277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
278 278
279 #[cfg(not(rcc_wba))] 279 #[cfg(not(rcc_wba))]
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index c2295bab6..99f22273d 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -49,6 +49,10 @@ pub struct Config {
49 /// System Clock Configuration 49 /// System Clock Configuration
50 pub sys: Sysclk, 50 pub sys: Sysclk,
51 51
52 /// HSI48 Configuration
53 #[cfg(crs)]
54 pub hsi48: Option<super::Hsi48Config>,
55
52 pub ahb_pre: AHBPrescaler, 56 pub ahb_pre: AHBPrescaler,
53 pub apb1_pre: APBPrescaler, 57 pub apb1_pre: APBPrescaler,
54 58
@@ -68,6 +72,8 @@ impl Config {
68 }), 72 }),
69 hse: None, 73 hse: None,
70 sys: Sysclk::HSISYS, 74 sys: Sysclk::HSISYS,
75 #[cfg(crs)]
76 hsi48: Some(crate::rcc::Hsi48Config::new()),
71 ahb_pre: AHBPrescaler::DIV1, 77 ahb_pre: AHBPrescaler::DIV1,
72 apb1_pre: APBPrescaler::DIV1, 78 apb1_pre: APBPrescaler::DIV1,
73 ls: crate::rcc::LsConfig::new(), 79 ls: crate::rcc::LsConfig::new(),
@@ -127,6 +133,10 @@ pub(crate) unsafe fn init(config: Config) {
127 } 133 }
128 }; 134 };
129 135
136 // Configure HSI48 if required
137 #[cfg(crs)]
138 let hsi48 = config.hsi48.map(super::init_hsi48);
139
130 let rtc = config.ls.init(); 140 let rtc = config.ls.init();
131 141
132 let sys = match config.sys { 142 let sys = match config.sys {
@@ -185,13 +195,13 @@ pub(crate) unsafe fn init(config: Config) {
185 hsi: hsi, 195 hsi: hsi,
186 hsiker: hsiker, 196 hsiker: hsiker,
187 hse: hse, 197 hse: hse,
198 #[cfg(crs)]
199 hsi48: hsi48,
188 rtc: rtc, 200 rtc: rtc,
189 201
190 // TODO 202 // TODO
191 lsi: None, 203 lsi: None,
192 lse: None, 204 lse: None,
193 #[cfg(crs)]
194 hsi48: None,
195 ); 205 );
196 206
197 RCC.ccipr() 207 RCC.ccipr()
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index 59ccc8cb5..fa4b45a20 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -91,12 +91,29 @@ pub struct Mco<'d, T: McoInstance> {
91 91
92impl<'d, T: McoInstance> Mco<'d, T> { 92impl<'d, T: McoInstance> Mco<'d, T> {
93 /// Create a new MCO instance. 93 /// Create a new MCO instance.
94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self { 94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, config: McoConfig) -> Self {
95 critical_section::with(|_| unsafe { 95 critical_section::with(|_| unsafe {
96 T::_apply_clock_settings(source, prescaler); 96 T::_apply_clock_settings(source, config.prescaler);
97 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 97 set_as_af!(pin, AfType::output(OutputType::PushPull, config.speed));
98 }); 98 });
99 99
100 Self { phantom: PhantomData } 100 Self { phantom: PhantomData }
101 } 101 }
102} 102}
103
104#[non_exhaustive]
105pub struct McoConfig {
106 /// Master Clock Out prescaler
107 pub prescaler: McoPrescaler,
108 /// IO Drive Strength
109 pub speed: Speed,
110}
111
112impl Default for McoConfig {
113 fn default() -> Self {
114 Self {
115 prescaler: McoPrescaler::DIV1,
116 speed: Speed::VeryHigh,
117 }
118 }
119}
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index 78ccd3e6c..a81ac6746 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,4 +1,8 @@
1#[cfg(feature = "time")]
2use embassy_time::{Duration, TICK_HZ};
3
1use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; 4use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError};
5use crate::interrupt::typelevel::Interrupt;
2use crate::peripherals::RTC; 6use crate::peripherals::RTC;
3use crate::rtc::SealedInstance; 7use crate::rtc::SealedInstance;
4 8
@@ -11,7 +15,7 @@ pub(super) struct RtcInstant {
11} 15}
12 16
13impl RtcInstant { 17impl RtcInstant {
14 #[cfg(not(rtc_v2f2))] 18 #[cfg(not(rtc_v2_f2))]
15 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> { 19 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
16 if second > 59 { 20 if second > 59 {
17 Err(DateTimeError::InvalidSecond) 21 Err(DateTimeError::InvalidSecond)
@@ -38,8 +42,6 @@ impl core::ops::Sub for RtcInstant {
38 type Output = embassy_time::Duration; 42 type Output = embassy_time::Duration;
39 43
40 fn sub(self, rhs: Self) -> Self::Output { 44 fn sub(self, rhs: Self) -> Self::Output {
41 use embassy_time::{Duration, TICK_HZ};
42
43 let second = if self.second < rhs.second { 45 let second = if self.second < rhs.second {
44 self.second + 60 46 self.second + 60
45 } else { 47 } else {
@@ -129,11 +131,6 @@ impl Rtc {
129 requested_duration: embassy_time::Duration, 131 requested_duration: embassy_time::Duration,
130 cs: critical_section::CriticalSection, 132 cs: critical_section::CriticalSection,
131 ) { 133 ) {
132 use embassy_time::{Duration, TICK_HZ};
133
134 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
135 use crate::pac::rtc::vals::Calrf;
136
137 // Panic if the rcc mod knows we're not using low-power rtc 134 // Panic if the rcc mod knows we're not using low-power rtc
138 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 135 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
139 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); 136 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap();
@@ -150,17 +147,15 @@ impl Rtc {
150 self.write(false, |regs| { 147 self.write(false, |regs| {
151 regs.cr().modify(|w| w.set_wute(false)); 148 regs.cr().modify(|w| w.set_wute(false));
152 149
153 #[cfg(any( 150 #[cfg(rtc_v2)]
154 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
155 ))]
156 { 151 {
157 regs.isr().modify(|w| w.set_wutf(false)); 152 regs.isr().modify(|w| w.set_wutf(false));
158 while !regs.isr().read().wutwf() {} 153 while !regs.isr().read().wutwf() {}
159 } 154 }
160 155
161 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 156 #[cfg(rtc_v3)]
162 { 157 {
163 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 158 regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR));
164 while !regs.icsr().read().wutwf() {} 159 while !regs.icsr().read().wutwf() {}
165 } 160 }
166 161
@@ -185,10 +180,6 @@ impl Rtc {
185 /// 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`
186 /// was called, otherwise none 181 /// was called, otherwise none
187 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 182 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
188 use crate::interrupt::typelevel::Interrupt;
189 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
190 use crate::pac::rtc::vals::Calrf;
191
192 let instant = self.instant().unwrap(); 183 let instant = self.instant().unwrap();
193 if RTC::regs().cr().read().wute() { 184 if RTC::regs().cr().read().wute() {
194 trace!("rtc: stop wakeup alarm at {}", instant); 185 trace!("rtc: stop wakeup alarm at {}", instant);
@@ -197,13 +188,10 @@ impl Rtc {
197 regs.cr().modify(|w| w.set_wutie(false)); 188 regs.cr().modify(|w| w.set_wutie(false));
198 regs.cr().modify(|w| w.set_wute(false)); 189 regs.cr().modify(|w| w.set_wute(false));
199 190
200 #[cfg(any( 191 #[cfg(rtc_v2)]
201 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
202 ))]
203 regs.isr().modify(|w| w.set_wutf(false)); 192 regs.isr().modify(|w| w.set_wutf(false));
204 193 #[cfg(rtc_v3)]
205 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 194 regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR));
206 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
207 195
208 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar, 196 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
209 // there is a table for every "Event input" / "EXTI Line". 197 // there is a table for every "Event input" / "EXTI Line".
@@ -222,8 +210,6 @@ impl Rtc {
222 } 210 }
223 211
224 pub(crate) fn enable_wakeup_line(&self) { 212 pub(crate) fn enable_wakeup_line(&self) {
225 use crate::interrupt::typelevel::Interrupt;
226
227 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); 213 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
228 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; 214 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
229 215
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 449f3008a..92dec0960 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -18,14 +18,9 @@ use crate::pac::rtc::regs::{Dr, Tr};
18use crate::time::Hertz; 18use crate::time::Hertz;
19 19
20/// refer to AN4759 to compare features of RTC2 and RTC3 20/// refer to AN4759 to compare features of RTC2 and RTC3
21#[cfg_attr(any(rtc_v1), path = "v1.rs")] 21#[cfg_attr(rtc_v1, path = "v1.rs")]
22#[cfg_attr( 22#[cfg_attr(rtc_v2, path = "v2.rs")]
23 any( 23#[cfg_attr(rtc_v3, path = "v3.rs")]
24 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
25 ),
26 path = "v2.rs"
27)]
28#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs, rtc_v3c0), path = "v3.rs")]
29mod _version; 24mod _version;
30#[allow(unused_imports)] 25#[allow(unused_imports)]
31pub use _version::*; 26pub use _version::*;
@@ -72,12 +67,12 @@ impl RtcTimeProvider {
72 67
73 // Calculate second fraction and multiply to microseconds 68 // Calculate second fraction and multiply to microseconds
74 // Formula from RM0410 69 // Formula from RM0410
75 #[cfg(not(rtc_v2f2))] 70 #[cfg(not(rtc_v2_f2))]
76 let us = { 71 let us = {
77 let prediv = RTC::regs().prer().read().prediv_s() as f32; 72 let prediv = RTC::regs().prer().read().prediv_s() as f32;
78 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 73 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32
79 }; 74 };
80 #[cfg(rtc_v2f2)] 75 #[cfg(rtc_v2_f2)]
81 let us = 0; 76 let us = 0;
82 77
83 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) 78 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime)
@@ -87,9 +82,9 @@ impl RtcTimeProvider {
87 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> { 82 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> {
88 let r = RTC::regs(); 83 let r = RTC::regs();
89 84
90 #[cfg(not(rtc_v2f2))] 85 #[cfg(not(rtc_v2_f2))]
91 let read_ss = || r.ssr().read().ss(); 86 let read_ss = || r.ssr().read().ss();
92 #[cfg(rtc_v2f2)] 87 #[cfg(rtc_v2_f2)]
93 let read_ss = || 0; 88 let read_ss = || 0;
94 89
95 let mut ss = read_ss(); 90 let mut ss = read_ss();
@@ -168,7 +163,7 @@ impl Rtc {
168 this.configure(async_psc, sync_psc); 163 this.configure(async_psc, sync_psc);
169 164
170 // Wait for the clock to update after initialization 165 // Wait for the clock to update after initialization
171 #[cfg(not(rtc_v2f2))] 166 #[cfg(not(rtc_v2_f2))]
172 { 167 {
173 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); 168 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap();
174 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} 169 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 28380a3c0..23f6ccb0c 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -11,11 +11,11 @@ impl super::Rtc {
11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { 11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
12 self.write(true, |rtc| { 12 self.write(true, |rtc| {
13 rtc.cr().modify(|w| { 13 rtc.cr().modify(|w| {
14 #[cfg(not(rtc_v2f2))] 14 #[cfg(not(rtc_v2_f2))]
15 w.set_bypshad(true); 15 w.set_bypshad(true);
16 #[cfg(rtc_v2f2)] 16 #[cfg(rtc_v2_f2)]
17 w.set_fmt(false); 17 w.set_fmt(false);
18 #[cfg(not(rtc_v2f2))] 18 #[cfg(not(rtc_v2_f2))]
19 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); 19 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
20 w.set_osel(Osel::DISABLED); 20 w.set_osel(Osel::DISABLED);
21 w.set_pol(Pol::HIGH); 21 w.set_pol(Pol::HIGH);
@@ -36,7 +36,7 @@ impl super::Rtc {
36 /// 36 ///
37 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler` 37 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler`
38 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12). 38 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12).
39 #[cfg(not(rtc_v2f2))] 39 #[cfg(not(rtc_v2_f2))]
40 pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) { 40 pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) {
41 const RTC_CALR_MIN_PPM: f32 = -487.1; 41 const RTC_CALR_MIN_PPM: f32 = -487.1;
42 const RTC_CALR_MAX_PPM: f32 = 488.5; 42 const RTC_CALR_MAX_PPM: f32 = 488.5;
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 82b5968b0..bb152731c 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -1,8 +1,6 @@
1//! Quadrature decoder using a timer. 1//! Quadrature decoder using a timer.
2 2
3use core::marker::PhantomData; 3use stm32_metapac::timer::vals::{self, Sms};
4
5use stm32_metapac::timer::vals;
6 4
7use super::low_level::Timer; 5use super::low_level::Timer;
8pub use super::{Ch1, Ch2}; 6pub use super::{Ch1, Ch2};
@@ -11,35 +9,59 @@ use crate::gpio::{AfType, AnyPin, Pull};
11use crate::timer::TimerChannel; 9use crate::timer::TimerChannel;
12use crate::Peri; 10use crate::Peri;
13 11
14/// Counting direction 12/// Qei driver config.
15pub enum Direction { 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16 /// Counting up. 14#[derive(Clone, Copy)]
17 Upcounting, 15pub struct Config {
18 /// Counting down. 16 /// Configures the internal pull up/down resistor for Qei's channel 1 pin.
19 Downcounting, 17 pub ch1_pull: Pull,
18 /// Configures the internal pull up/down resistor for Qei's channel 2 pin.
19 pub ch2_pull: Pull,
20 /// Specifies the encoder mode to use for the Qei peripheral.
21 pub mode: QeiMode,
20} 22}
21 23
22/// Wrapper for using a pin with QEI. 24impl Default for Config {
23pub struct QeiPin<'d, T, Channel, #[cfg(afio)] A> { 25 /// Arbitrary defaults to preserve backwards compatibility
24 #[allow(unused)] 26 fn default() -> Self {
25 pin: Peri<'d, AnyPin>, 27 Self {
26 phantom: PhantomData<if_afio!((T, Channel, A))>, 28 ch1_pull: Pull::None,
29 ch2_pull: Pull::None,
30 mode: QeiMode::Mode3,
31 }
32 }
27} 33}
28 34
29impl<'d, T: GeneralInstance4Channel, C: QeiChannel, #[cfg(afio)] A> if_afio!(QeiPin<'d, T, C, A>) { 35/// See STMicro AN4013 for §2.3 for more information
30 /// Create a new QEI pin instance. 36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>) -> Self { 37#[derive(Clone, Copy)]
32 critical_section::with(|_| { 38pub enum QeiMode {
33 pin.set_low(); 39 /// Direct alias for [`Sms::ENCODER_MODE_1`]
34 set_as_af!(pin, AfType::input(Pull::None)); 40 Mode1,
35 }); 41 /// Direct alias for [`Sms::ENCODER_MODE_2`]
36 QeiPin { 42 Mode2,
37 pin: pin.into(), 43 /// Direct alias for [`Sms::ENCODER_MODE_3`]
38 phantom: PhantomData, 44 Mode3,
45}
46
47impl From<QeiMode> for Sms {
48 fn from(mode: QeiMode) -> Self {
49 match mode {
50 QeiMode::Mode1 => Sms::ENCODER_MODE_1,
51 QeiMode::Mode2 => Sms::ENCODER_MODE_2,
52 QeiMode::Mode3 => Sms::ENCODER_MODE_3,
39 } 53 }
40 } 54 }
41} 55}
42 56
57/// Counting direction
58pub enum Direction {
59 /// Counting up.
60 Upcounting,
61 /// Counting down.
62 Downcounting,
63}
64
43trait SealedQeiChannel: TimerChannel {} 65trait SealedQeiChannel: TimerChannel {}
44 66
45/// Marker trait for a timer channel eligible for use with QEI. 67/// Marker trait for a timer channel eligible for use with QEI.
@@ -55,20 +77,28 @@ impl SealedQeiChannel for Ch2 {}
55/// Quadrature decoder driver. 77/// Quadrature decoder driver.
56pub struct Qei<'d, T: GeneralInstance4Channel> { 78pub struct Qei<'d, T: GeneralInstance4Channel> {
57 inner: Timer<'d, T>, 79 inner: Timer<'d, T>,
80 _ch1: Peri<'d, AnyPin>,
81 _ch2: Peri<'d, AnyPin>,
58} 82}
59 83
60impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 84impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
61 /// Create a new quadrature decoder driver. 85 /// Create a new quadrature decoder driver, with a given [`Config`].
62 #[allow(unused)] 86 #[allow(unused)]
63 pub fn new<#[cfg(afio)] A>( 87 pub fn new<CH1: QeiChannel, CH2: QeiChannel, #[cfg(afio)] A>(
64 tim: Peri<'d, T>, 88 tim: Peri<'d, T>,
65 ch1: if_afio!(QeiPin<'d, T, Ch1, A>), 89 ch1: Peri<'d, if_afio!(impl TimerPin<T, CH1, A>)>,
66 ch2: if_afio!(QeiPin<'d, T, Ch2, A>), 90 ch2: Peri<'d, if_afio!(impl TimerPin<T, CH2, A>)>,
91 config: Config,
67 ) -> Self { 92 ) -> Self {
68 Self::new_inner(tim) 93 // Configure the pins to be used for the QEI peripheral.
69 } 94 critical_section::with(|_| {
95 ch1.set_low();
96 set_as_af!(ch1, AfType::input(config.ch1_pull));
97
98 ch2.set_low();
99 set_as_af!(ch2, AfType::input(config.ch2_pull));
100 });
70 101
71 fn new_inner(tim: Peri<'d, T>) -> Self {
72 let inner = Timer::new(tim); 102 let inner = Timer::new(tim);
73 let r = inner.regs_gp16(); 103 let r = inner.regs_gp16();
74 104
@@ -88,13 +118,17 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
88 }); 118 });
89 119
90 r.smcr().modify(|w| { 120 r.smcr().modify(|w| {
91 w.set_sms(vals::Sms::ENCODER_MODE_3); 121 w.set_sms(config.mode.into());
92 }); 122 });
93 123
94 r.arr().modify(|w| w.set_arr(u16::MAX)); 124 r.arr().modify(|w| w.set_arr(u16::MAX));
95 r.cr1().modify(|w| w.set_cen(true)); 125 r.cr1().modify(|w| w.set_cen(true));
96 126
97 Self { inner } 127 Self {
128 inner,
129 _ch1: ch1.into(),
130 _ch2: ch2.into(),
131 }
98 } 132 }
99 133
100 /// Get direction. 134 /// Get direction.
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index c734eed49..10dc02334 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,7 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
@@ -68,8 +68,15 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
69 } 69 }
70 70
71 if !state.rx_buf.is_empty() { 71 let eager = state.eager_reads.load(Ordering::Relaxed);
72 state.rx_waker.wake(); 72 if eager > 0 {
73 if state.rx_buf.available() >= eager {
74 state.rx_waker.wake();
75 }
76 } else {
77 if state.rx_buf.is_half_full() {
78 state.rx_waker.wake();
79 }
73 } 80 }
74 } 81 }
75 82
@@ -132,6 +139,7 @@ pub(super) struct State {
132 tx_done: AtomicBool, 139 tx_done: AtomicBool,
133 tx_rx_refcount: AtomicU8, 140 tx_rx_refcount: AtomicU8,
134 half_duplex_readback: AtomicBool, 141 half_duplex_readback: AtomicBool,
142 eager_reads: AtomicUsize,
135} 143}
136 144
137impl State { 145impl State {
@@ -144,6 +152,7 @@ impl State {
144 tx_done: AtomicBool::new(true), 152 tx_done: AtomicBool::new(true),
145 tx_rx_refcount: AtomicU8::new(0), 153 tx_rx_refcount: AtomicU8::new(0),
146 half_duplex_readback: AtomicBool::new(false), 154 half_duplex_readback: AtomicBool::new(false),
155 eager_reads: AtomicUsize::new(0),
147 } 156 }
148 } 157 }
149} 158}
@@ -419,6 +428,9 @@ impl<'d> BufferedUart<'d> {
419 let state = T::buffered_state(); 428 let state = T::buffered_state();
420 let kernel_clock = T::frequency(); 429 let kernel_clock = T::frequency();
421 430
431 state
432 .eager_reads
433 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
422 state.half_duplex_readback.store( 434 state.half_duplex_readback.store(
423 config.duplex == Duplex::Half(HalfDuplexReadback::Readback), 435 config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
424 Ordering::Relaxed, 436 Ordering::Relaxed,
@@ -456,6 +468,9 @@ impl<'d> BufferedUart<'d> {
456 let info = self.rx.info; 468 let info = self.rx.info;
457 let state = self.rx.state; 469 let state = self.rx.state;
458 state.tx_rx_refcount.store(2, Ordering::Relaxed); 470 state.tx_rx_refcount.store(2, Ordering::Relaxed);
471 state
472 .eager_reads
473 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
459 474
460 info.rcc.enable_and_reset(); 475 info.rcc.enable_and_reset();
461 476
@@ -527,6 +542,11 @@ impl<'d> BufferedUart<'d> {
527 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 542 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
528 reconfigure(self.rx.info, self.rx.kernel_clock, config)?; 543 reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
529 544
545 self.rx
546 .state
547 .eager_reads
548 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
549
530 self.rx.info.regs.cr1().modify(|w| { 550 self.rx.info.regs.cr1().modify(|w| {
531 w.set_rxneie(true); 551 w.set_rxneie(true);
532 w.set_idleie(true); 552 w.set_idleie(true);
@@ -553,24 +573,30 @@ impl<'d> BufferedUartRx<'d> {
553 poll_fn(move |cx| { 573 poll_fn(move |cx| {
554 let state = self.state; 574 let state = self.state;
555 let mut rx_reader = unsafe { state.rx_buf.reader() }; 575 let mut rx_reader = unsafe { state.rx_buf.reader() };
556 let data = rx_reader.pop_slice(); 576 let mut buf_len = 0;
577 let mut data = rx_reader.pop_slice();
557 578
558 if !data.is_empty() { 579 while !data.is_empty() && buf_len < buf.len() {
559 let len = data.len().min(buf.len()); 580 let data_len = data.len().min(buf.len() - buf_len);
560 buf[..len].copy_from_slice(&data[..len]); 581 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
582 buf_len += data_len;
561 583
562 let do_pend = state.rx_buf.is_full(); 584 let do_pend = state.rx_buf.is_full();
563 rx_reader.pop_done(len); 585 rx_reader.pop_done(data_len);
564 586
565 if do_pend { 587 if do_pend {
566 self.info.interrupt.pend(); 588 self.info.interrupt.pend();
567 } 589 }
568 590
569 return Poll::Ready(Ok(len)); 591 data = rx_reader.pop_slice();
570 } 592 }
571 593
572 state.rx_waker.register(cx.waker()); 594 if buf_len != 0 {
573 Poll::Pending 595 Poll::Ready(Ok(buf_len))
596 } else {
597 state.rx_waker.register(cx.waker());
598 Poll::Pending
599 }
574 }) 600 })
575 .await 601 .await
576 } 602 }
@@ -579,21 +605,24 @@ impl<'d> BufferedUartRx<'d> {
579 loop { 605 loop {
580 let state = self.state; 606 let state = self.state;
581 let mut rx_reader = unsafe { state.rx_buf.reader() }; 607 let mut rx_reader = unsafe { state.rx_buf.reader() };
582 let data = rx_reader.pop_slice(); 608 let mut buf_len = 0;
609 let mut data = rx_reader.pop_slice();
583 610
584 if !data.is_empty() { 611 while !data.is_empty() && buf_len < buf.len() {
585 let len = data.len().min(buf.len()); 612 let data_len = data.len().min(buf.len() - buf_len);
586 buf[..len].copy_from_slice(&data[..len]); 613 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
614 buf_len += data_len;
587 615
588 let do_pend = state.rx_buf.is_full(); 616 let do_pend = state.rx_buf.is_full();
589 rx_reader.pop_done(len); 617 rx_reader.pop_done(data_len);
590 618
591 if do_pend { 619 if do_pend {
592 self.info.interrupt.pend(); 620 self.info.interrupt.pend();
593 } 621 }
594 622
595 return Ok(len); 623 data = rx_reader.pop_slice();
596 } 624 }
625 return Ok(buf_len);
597 } 626 }
598 } 627 }
599 628
@@ -633,6 +662,10 @@ impl<'d> BufferedUartRx<'d> {
633 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 662 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
634 reconfigure(self.info, self.kernel_clock, config)?; 663 reconfigure(self.info, self.kernel_clock, config)?;
635 664
665 self.state
666 .eager_reads
667 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
668
636 self.info.regs.cr1().modify(|w| { 669 self.info.regs.cr1().modify(|w| {
637 w.set_rxneie(true); 670 w.set_rxneie(true);
638 w.set_idleie(true); 671 w.set_idleie(true);
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index ff211e0c9..0d2d86aca 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -4,7 +4,7 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; 7use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
@@ -185,6 +185,12 @@ pub enum ConfigError {
185 RxOrTxNotEnabled, 185 RxOrTxNotEnabled,
186 /// Data bits and parity combination not supported 186 /// Data bits and parity combination not supported
187 DataParityNotSupported, 187 DataParityNotSupported,
188 /// DE assertion time too high
189 #[cfg(not(any(usart_v1, usart_v2)))]
190 DeAssertionTimeTooHigh,
191 /// DE deassertion time too high
192 #[cfg(not(any(usart_v1, usart_v2)))]
193 DeDeassertionTimeTooHigh,
188} 194}
189 195
190#[non_exhaustive] 196#[non_exhaustive]
@@ -206,6 +212,21 @@ pub struct Config {
206 /// If false: the error is ignored and cleared 212 /// If false: the error is ignored and cleared
207 pub detect_previous_overrun: bool, 213 pub detect_previous_overrun: bool,
208 214
215 /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
216 /// typically only wake/return after line idle or after the buffer is at least half full
217 /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions
218 /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances.
219 ///
220 /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are
221 /// available in the buffer, in addition to waking/returning when the conditions described
222 /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx`
223 /// will trigger an interrupt for every received word to check the buffer level, which may
224 /// impact performance at high data rates.
225 ///
226 /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either
227 /// return a single word, a full buffer, or after line idle.
228 pub eager_reads: Option<usize>,
229
209 /// Set this to true if the line is considered noise free. 230 /// Set this to true if the line is considered noise free.
210 /// This will increase the receiver’s tolerance to clock deviations, 231 /// This will increase the receiver’s tolerance to clock deviations,
211 /// but will effectively disable noise detection. 232 /// but will effectively disable noise detection.
@@ -239,6 +260,14 @@ pub struct Config {
239 /// Set the pin configuration for the DE pin. 260 /// Set the pin configuration for the DE pin.
240 pub de_config: OutputConfig, 261 pub de_config: OutputConfig,
241 262
263 /// Set DE assertion time before the first start bit, 0-31 16ths of a bit period.
264 #[cfg(not(any(usart_v1, usart_v2)))]
265 pub de_assertion_time: u8,
266
267 /// Set DE deassertion time after the last stop bit, 0-31 16ths of a bit period.
268 #[cfg(not(any(usart_v1, usart_v2)))]
269 pub de_deassertion_time: u8,
270
242 // private: set by new_half_duplex, not by the user. 271 // private: set by new_half_duplex, not by the user.
243 duplex: Duplex, 272 duplex: Duplex,
244} 273}
@@ -270,6 +299,7 @@ impl Default for Config {
270 parity: Parity::ParityNone, 299 parity: Parity::ParityNone,
271 // historical behavior 300 // historical behavior
272 detect_previous_overrun: false, 301 detect_previous_overrun: false,
302 eager_reads: None,
273 #[cfg(not(usart_v1))] 303 #[cfg(not(usart_v1))]
274 assume_noise_free: false, 304 assume_noise_free: false,
275 #[cfg(any(usart_v3, usart_v4))] 305 #[cfg(any(usart_v3, usart_v4))]
@@ -283,6 +313,10 @@ impl Default for Config {
283 tx_config: OutputConfig::PushPull, 313 tx_config: OutputConfig::PushPull,
284 rts_config: OutputConfig::PushPull, 314 rts_config: OutputConfig::PushPull,
285 de_config: OutputConfig::PushPull, 315 de_config: OutputConfig::PushPull,
316 #[cfg(not(any(usart_v1, usart_v2)))]
317 de_assertion_time: 0,
318 #[cfg(not(any(usart_v1, usart_v2)))]
319 de_deassertion_time: 0,
286 duplex: Duplex::Full, 320 duplex: Duplex::Full,
287 } 321 }
288 } 322 }
@@ -966,6 +1000,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
966 let info = self.info; 1000 let info = self.info;
967 let state = self.state; 1001 let state = self.state;
968 state.tx_rx_refcount.store(1, Ordering::Relaxed); 1002 state.tx_rx_refcount.store(1, Ordering::Relaxed);
1003 state
1004 .eager_reads
1005 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
969 1006
970 info.rcc.enable_and_reset(); 1007 info.rcc.enable_and_reset();
971 1008
@@ -982,6 +1019,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
982 1019
983 /// Reconfigure the driver 1020 /// Reconfigure the driver
984 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 1021 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1022 self.state
1023 .eager_reads
1024 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
985 reconfigure(self.info, self.kernel_clock, config) 1025 reconfigure(self.info, self.kernel_clock, config)
986 } 1026 }
987 1027
@@ -1462,6 +1502,9 @@ impl<'d, M: Mode> Uart<'d, M> {
1462 let info = self.rx.info; 1502 let info = self.rx.info;
1463 let state = self.rx.state; 1503 let state = self.rx.state;
1464 state.tx_rx_refcount.store(2, Ordering::Relaxed); 1504 state.tx_rx_refcount.store(2, Ordering::Relaxed);
1505 state
1506 .eager_reads
1507 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1465 1508
1466 info.rcc.enable_and_reset(); 1509 info.rcc.enable_and_reset();
1467 1510
@@ -1690,6 +1733,16 @@ fn configure(
1690 return Err(ConfigError::RxOrTxNotEnabled); 1733 return Err(ConfigError::RxOrTxNotEnabled);
1691 } 1734 }
1692 1735
1736 #[cfg(not(any(usart_v1, usart_v2)))]
1737 let dem = r.cr3().read().dem();
1738
1739 #[cfg(not(any(usart_v1, usart_v2)))]
1740 if config.de_assertion_time > 31 {
1741 return Err(ConfigError::DeAssertionTimeTooHigh);
1742 } else if config.de_deassertion_time > 31 {
1743 return Err(ConfigError::DeDeassertionTimeTooHigh);
1744 }
1745
1693 // UART must be disabled during configuration. 1746 // UART must be disabled during configuration.
1694 r.cr1().modify(|w| { 1747 r.cr1().modify(|w| {
1695 w.set_ue(false); 1748 w.set_ue(false);
@@ -1738,6 +1791,20 @@ fn configure(
1738 w.set_re(enable_rx); 1791 w.set_re(enable_rx);
1739 } 1792 }
1740 1793
1794 #[cfg(not(any(usart_v1, usart_v2)))]
1795 if dem {
1796 w.set_deat(if over8 {
1797 config.de_assertion_time / 2
1798 } else {
1799 config.de_assertion_time
1800 });
1801 w.set_dedt(if over8 {
1802 config.de_assertion_time / 2
1803 } else {
1804 config.de_assertion_time
1805 });
1806 }
1807
1741 // configure word size and parity, since the parity bit is inserted into the MSB position, 1808 // configure word size and parity, since the parity bit is inserted into the MSB position,
1742 // it increases the effective word size 1809 // it increases the effective word size
1743 match (config.parity, config.data_bits) { 1810 match (config.parity, config.data_bits) {
@@ -2022,6 +2089,7 @@ struct State {
2022 rx_waker: AtomicWaker, 2089 rx_waker: AtomicWaker,
2023 tx_waker: AtomicWaker, 2090 tx_waker: AtomicWaker,
2024 tx_rx_refcount: AtomicU8, 2091 tx_rx_refcount: AtomicU8,
2092 eager_reads: AtomicUsize,
2025} 2093}
2026 2094
2027impl State { 2095impl State {
@@ -2030,6 +2098,7 @@ impl State {
2030 rx_waker: AtomicWaker::new(), 2098 rx_waker: AtomicWaker::new(),
2031 tx_waker: AtomicWaker::new(), 2099 tx_waker: AtomicWaker::new(),
2032 tx_rx_refcount: AtomicU8::new(0), 2100 tx_rx_refcount: AtomicU8::new(0),
2101 eager_reads: AtomicUsize::new(0),
2033 } 2102 }
2034 } 2103 }
2035} 2104}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 5f4e87834..27071fb31 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -26,9 +26,9 @@ use crate::Peri;
26/// contain enough bytes to fill the buffer passed by the caller of 26/// contain enough bytes to fill the buffer passed by the caller of
27/// the function, or is empty. 27/// the function, or is empty.
28/// 28///
29/// Waiting for bytes operates in one of two modes, depending on 29/// Waiting for bytes operates in one of three modes, depending on
30/// the behavior of the sender and the size of the buffer passed 30/// the behavior of the sender, the size of the buffer passed
31/// to the function: 31/// to the function, and the configuration:
32/// 32///
33/// - If the sender sends intermittently, the 'idle line' 33/// - If the sender sends intermittently, the 'idle line'
34/// condition will be detected when the sender stops, and any 34/// condition will be detected when the sender stops, and any
@@ -47,7 +47,11 @@ use crate::Peri;
47/// interrupt when those specific buffer addresses have been 47/// interrupt when those specific buffer addresses have been
48/// written. 48/// written.
49/// 49///
50/// In both cases this will result in variable latency due to the 50/// - If `eager_reads` is enabled in `config`, the UART interrupt
51/// is enabled on all data reception and the call will only wait
52/// for at least one byte to be available before returning.
53///
54/// In the first two cases this will result in variable latency due to the
51/// buffering effect. For example, if the baudrate is 2400 bps, and 55/// buffering effect. For example, if the baudrate is 2400 bps, and
52/// the configuration is 8 data bits, no parity bit, and one stop bit, 56/// the configuration is 8 data bits, no parity bit, and one stop bit,
53/// then a byte will be received every ~4.16ms. If the ring buffer is 57/// then a byte will be received every ~4.16ms. If the ring buffer is
@@ -68,15 +72,10 @@ use crate::Peri;
68/// sending, but would be falsely triggered in the worst-case 72/// sending, but would be falsely triggered in the worst-case
69/// buffer delay scenario. 73/// buffer delay scenario.
70/// 74///
71/// Note: This latency is caused by the limited capabilities of the 75/// Note: Enabling `eager_reads` with `RingBufferedUartRx` will enable
72/// STM32 DMA controller; since it cannot generate an interrupt when 76/// an UART RXNE interrupt, which will cause an interrupt to occur on
73/// it stores a byte into an empty ring buffer, or in any other 77/// every received data byte. The data is still copied using DMA, but
74/// configurable conditions, it is not possible to take notice of the 78/// there is nevertheless additional processing overhead for each byte.
75/// contents of the ring buffer more quickly without introducing
76/// polling. As a result the latency can be reduced by calling the
77/// read functions repeatedly with smaller buffers to receive the
78/// available bytes, as each call to a read function will explicitly
79/// check the ring buffer for available bytes.
80pub struct RingBufferedUartRx<'d> { 79pub struct RingBufferedUartRx<'d> {
81 info: &'static Info, 80 info: &'static Info,
82 state: &'static State, 81 state: &'static State,
@@ -133,6 +132,9 @@ impl<'d> UartRx<'d, Async> {
133impl<'d> RingBufferedUartRx<'d> { 132impl<'d> RingBufferedUartRx<'d> {
134 /// Reconfigure the driver 133 /// Reconfigure the driver
135 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 134 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
135 self.state
136 .eager_reads
137 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
136 reconfigure(self.info, self.kernel_clock, config) 138 reconfigure(self.info, self.kernel_clock, config)
137 } 139 }
138 140
@@ -148,8 +150,8 @@ impl<'d> RingBufferedUartRx<'d> {
148 let r = self.info.regs; 150 let r = self.info.regs;
149 // clear all interrupts and DMA Rx Request 151 // clear all interrupts and DMA Rx Request
150 r.cr1().modify(|w| { 152 r.cr1().modify(|w| {
151 // disable RXNE interrupt 153 // use RXNE only when returning reads early
152 w.set_rxneie(false); 154 w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed) > 0);
153 // enable parity interrupt if not ParityNone 155 // enable parity interrupt if not ParityNone
154 w.set_peie(w.pce()); 156 w.set_peie(w.pce());
155 // enable idle line interrupt 157 // enable idle line interrupt
@@ -248,39 +250,67 @@ impl<'d> RingBufferedUartRx<'d> {
248 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 250 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
249 compiler_fence(Ordering::SeqCst); 251 compiler_fence(Ordering::SeqCst);
250 252
251 // Future which completes when idle line is detected 253 loop {
252 let s = self.state; 254 // Future which completes when idle line is detected
253 let uart = poll_fn(|cx| { 255 let s = self.state;
254 s.rx_waker.register(cx.waker()); 256 let mut uart_init = false;
255 257 let uart = poll_fn(|cx| {
256 compiler_fence(Ordering::SeqCst); 258 s.rx_waker.register(cx.waker());
257 259
258 if check_idle_and_errors(self.info.regs)? { 260 compiler_fence(Ordering::SeqCst);
259 // Idle line is detected 261
260 Poll::Ready(Ok(())) 262 // We may have been woken by IDLE or, if eager_reads is set, by RXNE.
261 } else { 263 // However, DMA will clear RXNE, so we can't check directly, and because
262 Poll::Pending 264 // the other future borrows `ring_buf`, we can't check `len()` here either.
263 } 265 // Instead, return from this future and we'll check the length afterwards.
264 }); 266 let eager = s.eager_reads.load(Ordering::Relaxed) > 0;
267
268 let idle = check_idle_and_errors(self.info.regs)?;
269 if idle || (eager && uart_init) {
270 // Idle line is detected, or eager reads is set and some data is available.
271 Poll::Ready(Ok(idle))
272 } else {
273 uart_init = true;
274 Poll::Pending
275 }
276 });
265 277
266 let mut dma_init = false; 278 let mut dma_init = false;
267 // Future which completes when the DMA controller indicates it 279 // Future which completes when the DMA controller indicates it
268 // has written to the ring buffer's middle byte, or last byte 280 // has written to the ring buffer's middle byte, or last byte
269 let dma = poll_fn(|cx| { 281 let dma = poll_fn(|cx| {
270 self.ring_buf.set_waker(cx.waker()); 282 self.ring_buf.set_waker(cx.waker());
271 283
272 let status = match dma_init { 284 let status = match dma_init {
273 false => Poll::Pending, 285 false => Poll::Pending,
274 true => Poll::Ready(()), 286 true => Poll::Ready(()),
275 }; 287 };
276 288
277 dma_init = true; 289 dma_init = true;
278 status 290 status
279 }); 291 });
280 292
281 match select(uart, dma).await { 293 match select(uart, dma).await {
282 Either::Left((result, _)) => result, 294 // UART woke with line idle
283 Either::Right(((), _)) => Ok(()), 295 Either::Left((Ok(true), _)) => {
296 return Ok(());
297 }
298 // UART woke without idle or error: word received
299 Either::Left((Ok(false), _)) => {
300 let eager = self.state.eager_reads.load(Ordering::Relaxed);
301 if eager > 0 && self.ring_buf.len().unwrap_or(0) >= eager {
302 return Ok(());
303 } else {
304 continue;
305 }
306 }
307 // UART woke with error
308 Either::Left((Err(e), _)) => {
309 return Err(e);
310 }
311 // DMA woke
312 Either::Right(((), _)) => return Ok(()),
313 }
284 } 314 }
285 } 315 }
286 316