mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 08:12:30 +00:00
[UCPD] Add support for non-SOP packets
Allow capturing (and distinguishing) non-SOP packets as well. The default configuration will just configure SOP packets. For ease of use the default receive function signature is unchanged as for PD sinks (which is likely the common usage) just SOP is enough so no need to differentiate.
This commit is contained in:
parent
d8459685fd
commit
1b0661ebb1
@ -27,7 +27,7 @@ use crate::dma::{ChannelAndRequest, TransferOptions};
|
|||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
|
use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
|
||||||
pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState};
|
pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
|
||||||
use crate::rcc::{self, RccPeripheral};
|
use crate::rcc::{self, RccPeripheral};
|
||||||
|
|
||||||
pub(crate) fn init(
|
pub(crate) fn init(
|
||||||
@ -86,6 +86,34 @@ pub enum CcPull {
|
|||||||
Source3_0A,
|
Source3_0A,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// UCPD configuration
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
/// Receive SOP packets
|
||||||
|
pub sop: bool,
|
||||||
|
/// Receive SOP' packets
|
||||||
|
pub sop_prime: bool,
|
||||||
|
/// Receive SOP'' packets
|
||||||
|
pub sop_double_prime: bool,
|
||||||
|
/// Receive SOP'_Debug packets
|
||||||
|
pub sop_prime_debug: bool,
|
||||||
|
/// Receive SOP''_Debug packets
|
||||||
|
pub sop_double_prime_debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
sop: true,
|
||||||
|
sop_prime: false,
|
||||||
|
sop_double_prime: false,
|
||||||
|
sop_prime_debug: false,
|
||||||
|
sop_double_prime_debug: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// UCPD driver.
|
/// UCPD driver.
|
||||||
pub struct Ucpd<'d, T: Instance> {
|
pub struct Ucpd<'d, T: Instance> {
|
||||||
cc_phy: CcPhy<'d, T>,
|
cc_phy: CcPhy<'d, T>,
|
||||||
@ -98,6 +126,7 @@ impl<'d, T: Instance> Ucpd<'d, T> {
|
|||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd,
|
cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd,
|
||||||
cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd,
|
cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd,
|
||||||
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(cc1, cc2);
|
into_ref!(cc1, cc2);
|
||||||
cc1.set_as_analog();
|
cc1.set_as_analog();
|
||||||
@ -129,9 +158,15 @@ impl<'d, T: Instance> Ucpd<'d, T> {
|
|||||||
// 1.75us * 17 = ~30us
|
// 1.75us * 17 = ~30us
|
||||||
w.set_ifrgap(17 - 1);
|
w.set_ifrgap(17 - 1);
|
||||||
|
|
||||||
// TODO: Currently only hard reset and SOP messages can be received.
|
|
||||||
// UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing).
|
// UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing).
|
||||||
w.set_rxordseten(0b1001);
|
let rxordset = (config.sop as u16) << 0
|
||||||
|
| (config.sop_prime as u16) << 1
|
||||||
|
| (config.sop_double_prime as u16) << 2
|
||||||
|
// Hard reset
|
||||||
|
| 0x1 << 3
|
||||||
|
| (config.sop_prime_debug as u16) << 4
|
||||||
|
| (config.sop_double_prime_debug as u16) << 5;
|
||||||
|
w.set_rxordseten(rxordset);
|
||||||
|
|
||||||
// Enable DMA
|
// Enable DMA
|
||||||
w.set_txdmaen(true);
|
w.set_txdmaen(true);
|
||||||
@ -288,6 +323,22 @@ impl<'d, T: Instance> CcPhy<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receive SOP.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Sop {
|
||||||
|
/// SOP
|
||||||
|
Sop,
|
||||||
|
/// SOP'
|
||||||
|
SopPrime,
|
||||||
|
/// SOP''
|
||||||
|
SopDoublePrime,
|
||||||
|
/// SOP'_Debug
|
||||||
|
SopPrimeDebug,
|
||||||
|
/// SOP''_Debug
|
||||||
|
SopDoublePrimeDebug,
|
||||||
|
}
|
||||||
|
|
||||||
/// Receive Error.
|
/// Receive Error.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
@ -340,6 +391,13 @@ impl<'d, T: Instance> PdPhy<'d, T> {
|
|||||||
///
|
///
|
||||||
/// Returns the number of received bytes or an error.
|
/// Returns the number of received bytes or an error.
|
||||||
pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
|
pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
|
||||||
|
self.receive_with_sop(buf).await.map(|(_sop, size)| size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Receives SOP and a PD message into the provided buffer.
|
||||||
|
///
|
||||||
|
/// Returns the start of packet type and number of received bytes or an error.
|
||||||
|
pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> {
|
||||||
let r = T::REGS;
|
let r = T::REGS;
|
||||||
|
|
||||||
let dma = unsafe {
|
let dma = unsafe {
|
||||||
@ -388,7 +446,18 @@ impl<'d, T: Instance> PdPhy<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(r.rx_payszr().read().rxpaysz().into())
|
let sop = match r.rx_ordsetr().read().rxordset() {
|
||||||
|
Rxordset::SOP => Sop::Sop,
|
||||||
|
Rxordset::SOPPRIME => Sop::SopPrime,
|
||||||
|
Rxordset::SOPDOUBLEPRIME => Sop::SopDoublePrime,
|
||||||
|
Rxordset::SOPPRIMEDEBUG => Sop::SopPrimeDebug,
|
||||||
|
Rxordset::SOPDOUBLEPRIMEDEBUG => Sop::SopDoublePrimeDebug,
|
||||||
|
Rxordset::CABLERESET => return Err(RxError::HardReset),
|
||||||
|
// Extension headers are not supported
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((sop, r.rx_payszr().read().rxpaysz().into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_rx_interrupt(enable: bool) {
|
fn enable_rx_interrupt(enable: bool) {
|
||||||
|
@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4);
|
let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default());
|
||||||
ucpd.cc_phy().set_pull(CcPull::Sink);
|
ucpd.cc_phy().set_pull(CcPull::Sink);
|
||||||
|
|
||||||
info!("Waiting for USB connection...");
|
info!("Waiting for USB connection...");
|
||||||
|
@ -106,8 +106,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
// Wire between PD0 and PA8
|
// Wire between PD0 and PA8
|
||||||
let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15);
|
let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15, Default::default());
|
||||||
let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2);
|
let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2, Default::default());
|
||||||
|
|
||||||
join(
|
join(
|
||||||
source(ucpd1, p.DMA1_CH1, p.DMA1_CH2),
|
source(ucpd1, p.DMA1_CH1, p.DMA1_CH2),
|
||||||
|
Loading…
Reference in New Issue
Block a user