mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
[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
This commit is contained in:
parent
d99fcfd0c2
commit
a3b1222617
@ -18,13 +18,14 @@ use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::{interrupt, pac};
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk};
|
||||
|
||||
pub use pac::ucpd::vals::TypecVstateCc as CcVState;
|
||||
use crate::interrupt;
|
||||
pub use crate::pac::ucpd::vals::TypecVstateCc as CcVState;
|
||||
use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk};
|
||||
use crate::rcc::RccPeripheral;
|
||||
|
||||
/// Pull-up or Pull-down resistor state of both CC lines.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
@ -53,6 +54,16 @@ pub struct Ucpd<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Drop for Ucpd<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::REGS.cr().modify(|w| {
|
||||
w.set_ccenable(Ccenable::DISABLED);
|
||||
w.set_cc1tcdis(true);
|
||||
w.set_cc2tcdis(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Ucpd<'d, T> {
|
||||
/// Creates a new UCPD driver instance.
|
||||
pub fn new(
|
||||
@ -113,13 +124,17 @@ impl<'d, T: Instance> Ucpd<'d, T> {
|
||||
} else {
|
||||
Ccenable::DISABLED
|
||||
});
|
||||
|
||||
// Make sure detector is enabled on both pins.
|
||||
w.set_cc1tcdis(false);
|
||||
w.set_cc2tcdis(false);
|
||||
});
|
||||
|
||||
// Disable dead-battery pull-down resistors which are enabled by default on boot.
|
||||
critical_section::with(|_| {
|
||||
// TODO: other families
|
||||
#[cfg(stm32g4)]
|
||||
pac::PWR
|
||||
crate::pac::PWR
|
||||
.cr3()
|
||||
.modify(|w| w.set_ucpd1_dbdis(cc_pull != CcPull::SinkDeadBattery));
|
||||
});
|
||||
@ -138,26 +153,29 @@ impl<'d, T: Instance> Ucpd<'d, T> {
|
||||
}
|
||||
|
||||
/// Waits for a change in voltage state on either CC line.
|
||||
pub async fn wait_for_cc_change(&mut self) {
|
||||
let r = T::REGS;
|
||||
pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) {
|
||||
let _on_drop = OnDrop::new(|| critical_section::with(|_| self.enable_cc_interrupts(false)));
|
||||
let prev_vstate = self.cc_vstate();
|
||||
poll_fn(|cx| {
|
||||
let sr = r.sr().read();
|
||||
if sr.typecevt1() || sr.typecevt2() {
|
||||
r.icr().write(|w| {
|
||||
w.set_typecevt1cf(true);
|
||||
w.set_typecevt2cf(true);
|
||||
});
|
||||
Poll::Ready(())
|
||||
let vstate = self.cc_vstate();
|
||||
if vstate != prev_vstate {
|
||||
Poll::Ready(vstate)
|
||||
} else {
|
||||
T::waker().register(cx.waker());
|
||||
r.imr().modify(|w| {
|
||||
w.set_typecevt1ie(true);
|
||||
w.set_typecevt2ie(true);
|
||||
});
|
||||
self.enable_cc_interrupts(true);
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
.await
|
||||
}
|
||||
|
||||
fn enable_cc_interrupts(&self, enable: bool) {
|
||||
critical_section::with(|_| {
|
||||
T::REGS.imr().modify(|w| {
|
||||
w.set_typecevt1ie(enable);
|
||||
w.set_typecevt2ie(enable);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,9 +190,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let sr = r.sr().read();
|
||||
|
||||
if sr.typecevt1() || sr.typecevt2() {
|
||||
r.imr().modify(|w| {
|
||||
w.set_typecevt1ie(true);
|
||||
w.set_typecevt2ie(true);
|
||||
r.icr().write(|w| {
|
||||
w.set_typecevt1cf(true);
|
||||
w.set_typecevt2cf(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,8 @@
|
||||
|
||||
use defmt::{info, Format};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::{
|
||||
ucpd::{self, CcPull, CcVState, Ucpd},
|
||||
Config,
|
||||
};
|
||||
use embassy_stm32::ucpd::{self, CcPull, CcVState, Ucpd};
|
||||
use embassy_stm32::Config;
|
||||
use embassy_time::{with_timeout, Duration};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
@ -18,17 +16,17 @@ enum CableOrientation {
|
||||
}
|
||||
|
||||
// Returns true when the cable
|
||||
async fn wait_attached<'d, T: ucpd::Instance>(ucpd: &mut Ucpd<'d, T>) -> CableOrientation {
|
||||
async fn wait_attached<T: ucpd::Instance>(ucpd: &mut Ucpd<'_, T>) -> CableOrientation {
|
||||
loop {
|
||||
let (cc1, cc2) = ucpd.cc_vstate();
|
||||
if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
|
||||
// Detached, wait until attached by monitoring the CC lines.
|
||||
ucpd.wait_for_cc_change().await;
|
||||
ucpd.wait_for_cc_vstate_change().await;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
|
||||
if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_change())
|
||||
if with_timeout(Duration::from_millis(100), ucpd.wait_for_cc_vstate_change())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user