aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Kröger <[email protected]>2024-03-07 09:17:05 +0100
committerTimo Kröger <[email protected]>2024-03-12 08:14:42 +0100
commita3b12226170d6b1a9ded47cc043cc09489cee278 (patch)
treea57c8c51effc1ab2850ed186e91c49592b3a1709
parentd99fcfd0c285be220c8f0004974567d7d4e2607b (diff)
[UCPD] Improve Type-C CC handling
* Improved interrupt handling: Clear flags in ISR, check state change in future * Disable pull-up/pull-down resistors and voltage monitor on drop * nightly rustfmt
-rw-r--r--embassy-stm32/src/ucpd.rs62
-rw-r--r--examples/stm32g4/src/bin/usb_c_pd.rs12
2 files changed, 45 insertions, 29 deletions
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 98b82bacc..a366fadda 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -18,13 +18,14 @@ use core::future::poll_fn;
18use core::marker::PhantomData; 18use core::marker::PhantomData;
19use core::task::Poll; 19use core::task::Poll;
20 20
21use crate::rcc::RccPeripheral; 21use embassy_hal_internal::drop::OnDrop;
22use crate::{interrupt, pac};
23use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 22use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
24use embassy_sync::waitqueue::AtomicWaker; 23use embassy_sync::waitqueue::AtomicWaker;
25use pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk};
26 24
27pub use pac::ucpd::vals::TypecVstateCc as CcVState; 25use crate::interrupt;
26pub use crate::pac::ucpd::vals::TypecVstateCc as CcVState;
27use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk};
28use crate::rcc::RccPeripheral;
28 29
29/// Pull-up or Pull-down resistor state of both CC lines. 30/// Pull-up or Pull-down resistor state of both CC lines.
30#[derive(Debug, Clone, Copy, PartialEq)] 31#[derive(Debug, Clone, Copy, PartialEq)]
@@ -53,6 +54,16 @@ pub struct Ucpd<'d, T: Instance> {
53 _peri: PeripheralRef<'d, T>, 54 _peri: PeripheralRef<'d, T>,
54} 55}
55 56
57impl<'d, T: Instance> Drop for Ucpd<'d, T> {
58 fn drop(&mut self) {
59 T::REGS.cr().modify(|w| {
60 w.set_ccenable(Ccenable::DISABLED);
61 w.set_cc1tcdis(true);
62 w.set_cc2tcdis(true);
63 });
64 }
65}
66
56impl<'d, T: Instance> Ucpd<'d, T> { 67impl<'d, T: Instance> Ucpd<'d, T> {
57 /// Creates a new UCPD driver instance. 68 /// Creates a new UCPD driver instance.
58 pub fn new( 69 pub fn new(
@@ -113,13 +124,17 @@ impl<'d, T: Instance> Ucpd<'d, T> {
113 } else { 124 } else {
114 Ccenable::DISABLED 125 Ccenable::DISABLED
115 }); 126 });
127
128 // Make sure detector is enabled on both pins.
129 w.set_cc1tcdis(false);
130 w.set_cc2tcdis(false);
116 }); 131 });
117 132
118 // Disable dead-battery pull-down resistors which are enabled by default on boot. 133 // Disable dead-battery pull-down resistors which are enabled by default on boot.
119 critical_section::with(|_| { 134 critical_section::with(|_| {
120 // TODO: other families 135 // TODO: other families
121 #[cfg(stm32g4)] 136 #[cfg(stm32g4)]
122 pac::PWR 137 crate::pac::PWR
123 .cr3() 138 .cr3()
124 .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery)); 139 .modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery));
125 }); 140 });
@@ -138,26 +153,29 @@ impl<'d, T: Instance> Ucpd<'d, T> {
138 } 153 }
139 154
140 /// Waits for a change in voltage state on either CC line. 155 /// Waits for a change in voltage state on either CC line.
141 pub async fn wait_for_cc_change(&mut self) { 156 pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) {
142 let r = T::REGS; 157 let _on_drop = OnDrop::new(|| critical_section::with(|_| self.enable_cc_interrupts(false)));
158 let prev_vstate = self.cc_vstate();
143 poll_fn(|cx| { 159 poll_fn(|cx| {
144 let sr = r.sr().read(); 160 let vstate = self.cc_vstate();
145 if sr.typecevt1() || sr.typecevt2() { 161 if vstate != prev_vstate {
146 r.icr().write(|w| { 162 Poll::Ready(vstate)
147 w.set_typecevt1cf(true);
148 w.set_typecevt2cf(true);
149 });
150 Poll::Ready(())
151 } else { 163 } else {
152 T::waker().register(cx.waker()); 164 T::waker().register(cx.waker());
153 r.imr().modify(|w| { 165 self.enable_cc_interrupts(true);
154 w.set_typecevt1ie(true);
155 w.set_typecevt2ie(true);
156 });
157 Poll::Pending 166 Poll::Pending
158 } 167 }
159 }) 168 })
160 .await; 169 .await
170 }
171
172 fn enable_cc_interrupts(&self, enable: bool) {
173 critical_section::with(|_| {
174 T::REGS.imr().modify(|w| {
175 w.set_typecevt1ie(enable);
176 w.set_typecevt2ie(enable);
177 })
178 });
161 } 179 }
162} 180}
163 181
@@ -172,9 +190,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
172 let sr = r.sr().read(); 190 let sr = r.sr().read();
173 191
174 if sr.typecevt1() || sr.typecevt2() { 192 if sr.typecevt1() || sr.typecevt2() {
175 r.imr().modify(|w| { 193 r.icr().write(|w| {
176 w.set_typecevt1ie(true); 194 w.set_typecevt1cf(true);
177 w.set_typecevt2ie(true); 195 w.set_typecevt2cf(true);
178 }); 196 });
179 } 197 }
180 198
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs
index c442ab0a7..7a0065087 100644
--- a/examples/stm32g4/src/bin/usb_c_pd.rs
+++ b/examples/stm32g4/src/bin/usb_c_pd.rs
@@ -3,10 +3,8 @@
3 3
4use defmt::{info, Format}; 4use defmt::{info, Format};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::{ 6use embassy_stm32::ucpd::{self, CcPull, CcVState, Ucpd};
7 ucpd::{self, CcPull, CcVState, Ucpd}, 7use embassy_stm32::Config;
8 Config,
9};
10use embassy_time::{with_timeout, Duration}; 8use embassy_time::{with_timeout, Duration};
11use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
12 10
@@ -18,17 +16,17 @@ enum CableOrientation {
18} 16}
19 17
20// Returns true when the cable 18// Returns true when the cable
21async fn wait_attached<'d, T: ucpd::Instance>(ucpd: &mut Ucpd<'d, T>) -> CableOrientation { 19async fn wait_attached<T: ucpd::Instance>(ucpd: &mut Ucpd<'_, T>) -> CableOrientation {
22 loop { 20 loop {
23 let (cc1, cc2) = ucpd.cc_vstate(); 21 let (cc1, cc2) = ucpd.cc_vstate();
24 if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { 22 if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
25 // Detached, wait until attached by monitoring the CC lines. 23 // Detached, wait until attached by monitoring the CC lines.
26 ucpd.wait_for_cc_change().await; 24 ucpd.wait_for_cc_vstate_change().await;
27 continue; 25 continue;
28 } 26 }
29 27
30 // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). 28 // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
31 if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_change()) 29 if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_vstate_change())
32 .await 30 .await
33 .is_ok() 31 .is_ok()
34 { 32 {