mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-22 06:42:32 +00:00
Merge pull request #3271 from sjoerdsimons/ucpd-sop-filters
[UCPD] Add support for non-SOP packets
This commit is contained in:
commit
fac71e594e
@ -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