use enumset::{EnumSet, EnumSetType};
use fugit::HertzU32;
use peripheral::PeripheralRef;
use private::*;
use crate::{
dma::{
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
Channel,
ChannelRx,
ChannelTx,
DescriptorChain,
DmaChannelConvert,
DmaDescriptor,
DmaEligible,
DmaError,
DmaPeripheral,
DmaTransferRx,
DmaTransferTx,
ReadBuffer,
Rx,
Tx,
WriteBuffer,
},
gpio::{
interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput},
NoPin,
},
interrupt::InterruptHandler,
peripheral::{self, Peripheral},
peripherals::{self, Interrupt, PARL_IO},
system::PeripheralClockControl,
Async,
Blocking,
InterruptConfigurable,
Mode,
};
#[allow(unused)]
const MAX_DMA_SIZE: usize = 32736;
#[derive(Debug, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ParlIoInterrupt {
TxFifoReEmpty,
RxFifoWOvf,
TxEof,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
DmaError(DmaError),
MaxDmaTransferSizeExceeded,
UnreachableClockRate,
}
impl From<DmaError> for Error {
fn from(value: DmaError) -> Self {
Error::DmaError(value)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SampleEdge {
Normal = 0,
Invert = 1,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BitPackOrder {
Msb = 0,
Lsb = 1,
}
#[cfg(esp32c6)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EnableMode {
HighLevel,
LowLevel,
PulseMode1,
PulseMode2,
PulseMode3,
PulseMode4,
PulseMode5,
PulseMode6,
PulseMode7,
PulseMode8,
PulseMode9,
PulseMode10,
PulseMode11,
PulseMode12,
}
#[cfg(esp32c6)]
impl EnableMode {
fn pulse_submode_sel(&self) -> Option<u8> {
match self {
EnableMode::PulseMode1 => Some(0),
EnableMode::PulseMode2 => Some(1),
EnableMode::PulseMode3 => Some(2),
EnableMode::PulseMode4 => Some(3),
EnableMode::PulseMode5 => Some(4),
EnableMode::PulseMode6 => Some(5),
EnableMode::PulseMode7 => Some(6),
EnableMode::PulseMode8 => Some(7),
EnableMode::PulseMode9 => Some(8),
EnableMode::PulseMode10 => Some(9),
EnableMode::PulseMode11 => Some(10),
EnableMode::PulseMode12 => Some(11),
_ => None,
}
}
fn level_submode_sel(&self) -> Option<u8> {
match self {
EnableMode::HighLevel => Some(0),
EnableMode::LowLevel => Some(1),
_ => None,
}
}
fn smp_model_sel(&self) -> Option<self::private::SampleMode> {
match self {
EnableMode::HighLevel => Some(self::private::SampleMode::ExternalLevel),
EnableMode::LowLevel => Some(self::private::SampleMode::ExternalLevel),
_ => Some(self::private::SampleMode::ExternalPulse),
}
}
}
#[cfg(esp32h2)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EnableMode {
HighLevel,
PulseMode1,
PulseMode2,
PulseMode3,
PulseMode4,
PulseMode5,
PulseMode6,
}
#[cfg(esp32h2)]
impl EnableMode {
fn pulse_submode_sel(&self) -> Option<u8> {
match self {
EnableMode::PulseMode1 => Some(0),
EnableMode::PulseMode2 => Some(1),
EnableMode::PulseMode3 => Some(2),
EnableMode::PulseMode4 => Some(3),
EnableMode::PulseMode5 => Some(4),
EnableMode::PulseMode6 => Some(5),
_ => None,
}
}
fn level_submode_sel(&self) -> Option<u8> {
match self {
EnableMode::HighLevel => Some(0),
_ => None,
}
}
fn smp_model_sel(&self) -> Option<self::private::SampleMode> {
match self {
EnableMode::HighLevel => Some(self::private::SampleMode::ExternalLevel),
_ => Some(self::private::SampleMode::ExternalPulse),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EofMode {
ByteLen,
EnableSignal,
}
impl TxClkPin for NoPin {
fn configure(&mut self) {
crate::gpio::OutputSignal::PARL_TX_CLK.connect_to(self);
}
}
impl RxClkPin for NoPin {
fn configure(&mut self) {
crate::gpio::InputSignal::PARL_RX_CLK.connect_to(self);
}
}
pub struct ClkOutPin<'d> {
pin: PeripheralRef<'d, OutputConnection>,
}
impl<'d> ClkOutPin<'d> {
pub fn new(pin: impl Peripheral<P = impl PeripheralOutput> + 'd) -> Self {
crate::into_mapped_ref!(pin);
Self { pin }
}
}
impl TxClkPin for ClkOutPin<'_> {
fn configure(&mut self) {
self.pin.set_to_push_pull_output(crate::private::Internal);
crate::gpio::OutputSignal::PARL_TX_CLK.connect_to(&mut self.pin);
}
}
pub struct ClkInPin<'d> {
pin: PeripheralRef<'d, InputConnection>,
}
impl<'d> ClkInPin<'d> {
pub fn new(pin: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
crate::into_mapped_ref!(pin);
Self { pin }
}
}
impl TxClkPin for ClkInPin<'_> {
fn configure(&mut self) {
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
pcr.parl_clk_tx_conf()
.modify(|_, w| unsafe { w.parl_clk_tx_sel().bits(3).parl_clk_tx_div_num().bits(0) }); self.pin
.init_input(crate::gpio::Pull::None, crate::private::Internal);
crate::gpio::InputSignal::PARL_TX_CLK.connect_to(&mut self.pin);
}
}
pub struct RxClkInPin<'d> {
pin: PeripheralRef<'d, InputConnection>,
sample_edge: SampleEdge,
}
impl<'d> RxClkInPin<'d> {
pub fn new(
pin: impl Peripheral<P = impl PeripheralInput> + 'd,
sample_edge: SampleEdge,
) -> Self {
crate::into_mapped_ref!(pin);
Self { pin, sample_edge }
}
}
impl RxClkPin for RxClkInPin<'_> {
fn configure(&mut self) {
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
pcr.parl_clk_rx_conf()
.modify(|_, w| unsafe { w.parl_clk_rx_sel().bits(3).parl_clk_rx_div_num().bits(0) }); self.pin
.init_input(crate::gpio::Pull::None, crate::private::Internal);
crate::gpio::InputSignal::PARL_RX_CLK.connect_to(&mut self.pin);
Instance::set_rx_clk_edge_sel(self.sample_edge);
}
}
pub struct TxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + TxPins + ConfigurePins,
{
tx_pins: P,
valid_pin: PeripheralRef<'d, OutputConnection>,
}
impl<'d, P> TxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + TxPins + ConfigurePins,
{
pub fn new(tx_pins: P, valid_pin: impl Peripheral<P = impl PeripheralOutput> + 'd) -> Self {
crate::into_mapped_ref!(valid_pin);
Self { tx_pins, valid_pin }
}
}
impl<P> TxPins for TxPinConfigWithValidPin<'_, P> where
P: NotContainsValidSignalPin + TxPins + ConfigurePins
{
}
impl<P> ConfigurePins for TxPinConfigWithValidPin<'_, P>
where
P: NotContainsValidSignalPin + TxPins + ConfigurePins,
{
fn configure(&mut self) -> Result<(), Error> {
self.tx_pins.configure()?;
self.valid_pin
.set_to_push_pull_output(crate::private::Internal);
Instance::tx_valid_pin_signal().connect_to(&mut self.valid_pin);
Instance::set_tx_hw_valid_en(true);
Ok(())
}
}
pub struct TxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + TxPins + ConfigurePins,
{
tx_pins: P,
}
impl<P> TxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + TxPins + ConfigurePins,
{
pub fn new(tx_pins: P) -> Self {
Self { tx_pins }
}
}
impl<P> TxPins for TxPinConfigIncludingValidPin<P> where
P: ContainsValidSignalPin + TxPins + ConfigurePins
{
}
impl<P> ConfigurePins for TxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + TxPins + ConfigurePins,
{
fn configure(&mut self) -> Result<(), Error> {
self.tx_pins.configure()?;
Instance::set_tx_hw_valid_en(true);
Ok(())
}
}
macro_rules! tx_pins {
($name:ident, $width:literal, $($pin:ident = $signal:ident),+ ) => {
paste::paste! {
#[doc = "Data pin configuration for "]
#[doc = stringify!($width)]
#[doc = "bit output mode"]
pub struct $name<'d> {
$(
[< pin_ $pin:lower >] : PeripheralRef<'d, OutputConnection>,
)+
}
impl<'d> $name<'d>
{
#[allow(clippy::too_many_arguments)]
pub fn new(
$(
[< pin_ $pin:lower >] : impl Peripheral<P = impl PeripheralOutput > + 'd,
)+
) -> Self {
crate::into_mapped_ref!($( [< pin_ $pin:lower >] ),+);
Self { $( [< pin_ $pin:lower >] ),+ }
}
}
impl ConfigurePins for $name<'_>
{
fn configure(&mut self) -> Result<(), Error>{
$(
self.[< pin_ $pin:lower >].set_to_push_pull_output(crate::private::Internal);
crate::gpio::OutputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]);
)+
private::Instance::set_tx_bit_width( private::WidSel::[< Bits $width >]);
Ok(())
}
}
impl TxPins for $name<'_> {}
}
};
}
tx_pins!(TxOneBit, 1, P0 = PARL_TX_DATA0);
tx_pins!(TxTwoBits, 2, P0 = PARL_TX_DATA0, P1 = PARL_TX_DATA1);
tx_pins!(
TxFourBits,
4,
P0 = PARL_TX_DATA0,
P1 = PARL_TX_DATA1,
P2 = PARL_TX_DATA2,
P3 = PARL_TX_DATA3
);
tx_pins!(
TxEightBits,
8,
P0 = PARL_TX_DATA0,
P1 = PARL_TX_DATA1,
P2 = PARL_TX_DATA2,
P3 = PARL_TX_DATA3,
P4 = PARL_TX_DATA4,
P5 = PARL_TX_DATA5,
P6 = PARL_TX_DATA6,
P7 = PARL_TX_DATA7
);
#[cfg(esp32c6)]
tx_pins!(
TxSixteenBits,
16,
P0 = PARL_TX_DATA0,
P1 = PARL_TX_DATA1,
P2 = PARL_TX_DATA2,
P3 = PARL_TX_DATA3,
P4 = PARL_TX_DATA4,
P5 = PARL_TX_DATA5,
P6 = PARL_TX_DATA6,
P7 = PARL_TX_DATA7,
P8 = PARL_TX_DATA8,
P9 = PARL_TX_DATA9,
P10 = PARL_TX_DATA10,
P11 = PARL_TX_DATA11,
P12 = PARL_TX_DATA12,
P13 = PARL_TX_DATA13,
P14 = PARL_TX_DATA14,
P15 = PARL_TX_DATA15
);
impl FullDuplex for TxOneBit<'_> {}
impl FullDuplex for TxTwoBits<'_> {}
impl FullDuplex for TxFourBits<'_> {}
impl FullDuplex for TxEightBits<'_> {}
impl NotContainsValidSignalPin for TxOneBit<'_> {}
impl NotContainsValidSignalPin for TxTwoBits<'_> {}
impl NotContainsValidSignalPin for TxFourBits<'_> {}
#[cfg(esp32c6)]
impl NotContainsValidSignalPin for TxEightBits<'_> {}
#[cfg(esp32h2)]
impl ContainsValidSignalPin for TxEightBits<'_> {}
#[cfg(esp32c6)]
impl ContainsValidSignalPin for TxSixteenBits<'_> {}
pub struct RxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + RxPins + ConfigurePins,
{
rx_pins: P,
valid_pin: PeripheralRef<'d, InputConnection>,
enable_mode: EnableMode,
eof_mode: EofMode,
}
impl<'d, P> RxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + RxPins + ConfigurePins,
{
pub fn new(
rx_pins: P,
valid_pin: impl Peripheral<P = impl PeripheralInput> + 'd,
enable_mode: EnableMode,
eof_mode: EofMode,
) -> Self {
crate::into_mapped_ref!(valid_pin);
Self {
rx_pins,
valid_pin,
enable_mode,
eof_mode,
}
}
}
impl<P> RxPins for RxPinConfigWithValidPin<'_, P> where
P: NotContainsValidSignalPin + RxPins + ConfigurePins
{
}
impl<P> ConfigurePins for RxPinConfigWithValidPin<'_, P>
where
P: NotContainsValidSignalPin + RxPins + ConfigurePins,
{
fn configure(&mut self) -> Result<(), Error> {
self.rx_pins.configure()?;
self.valid_pin
.init_input(crate::gpio::Pull::None, crate::private::Internal);
Instance::rx_valid_pin_signal().connect_to(&mut self.valid_pin);
Instance::set_rx_sw_en(false);
if let Some(sel) = self.enable_mode.pulse_submode_sel() {
Instance::set_rx_pulse_submode_sel(sel);
}
if let Some(sel) = self.enable_mode.level_submode_sel() {
Instance::set_rx_level_submode_sel(sel);
}
if let Some(sel) = self.enable_mode.smp_model_sel() {
Instance::set_rx_sample_mode(sel);
}
Instance::set_eof_gen_sel(self.eof_mode);
Ok(())
}
}
pub struct RxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + RxPins + ConfigurePins,
{
rx_pins: P,
enable_mode: EnableMode,
eof_mode: EofMode,
}
impl<P> RxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + RxPins + ConfigurePins,
{
pub fn new(rx_pins: P, enable_mode: EnableMode, eof_mode: EofMode) -> Self {
Self {
rx_pins,
enable_mode,
eof_mode,
}
}
}
impl<P> RxPins for RxPinConfigIncludingValidPin<P> where
P: ContainsValidSignalPin + RxPins + ConfigurePins
{
}
impl<P> ConfigurePins for RxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + RxPins + ConfigurePins,
{
fn configure(&mut self) -> Result<(), Error> {
self.rx_pins.configure()?;
Instance::set_rx_sw_en(false);
if let Some(sel) = self.enable_mode.pulse_submode_sel() {
Instance::set_rx_pulse_submode_sel(sel);
}
if let Some(sel) = self.enable_mode.level_submode_sel() {
Instance::set_rx_level_submode_sel(sel);
}
if let Some(sel) = self.enable_mode.smp_model_sel() {
Instance::set_rx_sample_mode(sel);
}
Instance::set_eof_gen_sel(self.eof_mode);
Ok(())
}
}
macro_rules! rx_pins {
($name:ident, $width:literal, $($pin:ident = $signal:ident),+ ) => {
paste::paste! {
#[doc = "Data pin configuration for "]
#[doc = stringify!($width)]
#[doc = "bit input mode"]
pub struct $name<'d> {
$(
[< pin_ $pin:lower >] : PeripheralRef<'d, InputConnection>,
)+
}
impl<'d> $name<'d>
{
#[allow(clippy::too_many_arguments)]
pub fn new(
$(
[< pin_ $pin:lower >] : impl Peripheral<P = impl PeripheralInput > + 'd,
)+
) -> Self {
crate::into_mapped_ref!($( [< pin_ $pin:lower >] ),+);
Self { $( [< pin_ $pin:lower >] ),+ }
}
}
impl ConfigurePins for $name<'_>
{
fn configure(&mut self) -> Result<(), Error> {
$(
self.[< pin_ $pin:lower >].init_input(crate::gpio::Pull::None, crate::private::Internal);
crate::gpio::InputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]);
)+
private::Instance::set_rx_bit_width( private::WidSel::[< Bits $width >]);
Ok(())
}
}
impl RxPins for $name<'_> {}
}
};
}
rx_pins!(RxOneBit, 1, P0 = PARL_RX_DATA0);
rx_pins!(RxTwoBits, 2, P0 = PARL_RX_DATA0, P1 = PARL_RX_DATA1);
rx_pins!(
RxFourBits,
4,
P0 = PARL_RX_DATA0,
P1 = PARL_RX_DATA1,
P2 = PARL_RX_DATA2,
P3 = PARL_RX_DATA3
);
rx_pins!(
RxEightBits,
8,
P0 = PARL_RX_DATA0,
P1 = PARL_RX_DATA1,
P2 = PARL_RX_DATA2,
P3 = PARL_RX_DATA3,
P4 = PARL_RX_DATA4,
P5 = PARL_RX_DATA5,
P6 = PARL_RX_DATA6,
P7 = PARL_RX_DATA7
);
#[cfg(esp32c6)]
rx_pins!(
RxSixteenBits,
16,
P0 = PARL_RX_DATA0,
P1 = PARL_RX_DATA1,
P2 = PARL_RX_DATA2,
P3 = PARL_RX_DATA3,
P4 = PARL_RX_DATA4,
P5 = PARL_RX_DATA5,
P6 = PARL_RX_DATA6,
P7 = PARL_RX_DATA7,
P8 = PARL_RX_DATA8,
P9 = PARL_RX_DATA9,
P10 = PARL_RX_DATA10,
P11 = PARL_RX_DATA11,
P12 = PARL_RX_DATA12,
P13 = PARL_RX_DATA13,
P14 = PARL_RX_DATA14,
P15 = PARL_RX_DATA15
);
impl FullDuplex for RxOneBit<'_> {}
impl FullDuplex for RxTwoBits<'_> {}
impl FullDuplex for RxFourBits<'_> {}
impl FullDuplex for RxEightBits<'_> {}
impl NotContainsValidSignalPin for RxOneBit<'_> {}
impl NotContainsValidSignalPin for RxTwoBits<'_> {}
impl NotContainsValidSignalPin for RxFourBits<'_> {}
#[cfg(esp32c6)]
impl NotContainsValidSignalPin for RxEightBits<'_> {}
#[cfg(esp32h2)]
impl ContainsValidSignalPin for RxEightBits<'_> {}
#[cfg(esp32c6)]
impl ContainsValidSignalPin for RxSixteenBits<'_> {}
impl<'d, DM> TxCreatorFullDuplex<'d, DM>
where
DM: Mode,
{
pub fn with_config<P, CP>(
self,
mut tx_pins: P,
mut clk_pin: CP,
idle_value: u16,
sample_edge: SampleEdge,
bit_order: BitPackOrder,
) -> Result<ParlIoTx<'d, DM>, Error>
where
P: FullDuplex + TxPins + ConfigurePins,
CP: TxClkPin,
{
tx_pins.configure()?;
clk_pin.configure();
Instance::set_tx_idle_value(idle_value);
Instance::set_tx_sample_edge(sample_edge);
Instance::set_tx_bit_order(bit_order);
Ok(ParlIoTx {
tx_channel: self.tx_channel,
tx_chain: DescriptorChain::new(self.descriptors),
})
}
}
impl<'d, DM> TxCreator<'d, DM>
where
DM: Mode,
{
pub fn with_config<P, CP>(
self,
tx_pins: &'d mut P,
clk_pin: &'d mut CP,
idle_value: u16,
sample_edge: SampleEdge,
bit_order: BitPackOrder,
) -> Result<ParlIoTx<'d, DM>, Error>
where
P: TxPins + ConfigurePins,
CP: TxClkPin,
{
tx_pins.configure()?;
clk_pin.configure();
Instance::set_tx_idle_value(idle_value);
Instance::set_tx_sample_edge(sample_edge);
Instance::set_tx_bit_order(bit_order);
Ok(ParlIoTx {
tx_channel: self.tx_channel,
tx_chain: DescriptorChain::new(self.descriptors),
})
}
}
pub struct ParlIoTx<'d, DM>
where
DM: Mode,
{
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
tx_chain: DescriptorChain,
}
impl<DM> core::fmt::Debug for ParlIoTx<'_, DM>
where
DM: Mode,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParlIoTx").finish()
}
}
impl<'d, DM> RxCreatorFullDuplex<'d, DM>
where
DM: Mode,
{
pub fn with_config<P, CP>(
self,
rx_pins: &'d mut P,
clk_pin: &'d mut CP,
bit_order: BitPackOrder,
timeout_ticks: Option<u16>,
) -> Result<ParlIoRx<'d, DM>, Error>
where
P: FullDuplex + RxPins + ConfigurePins,
CP: RxClkPin,
{
rx_pins.configure()?;
clk_pin.configure();
Instance::set_rx_bit_order(bit_order);
Instance::set_rx_timeout_ticks(timeout_ticks);
Ok(ParlIoRx {
rx_channel: self.rx_channel,
rx_chain: DescriptorChain::new(self.descriptors),
})
}
}
impl<'d, DM> RxCreator<'d, DM>
where
DM: Mode,
{
pub fn with_config<P, CP>(
self,
rx_pins: &'d mut P,
clk_pin: &'d mut CP,
bit_order: BitPackOrder,
timeout_ticks: Option<u16>,
) -> Result<ParlIoRx<'d, DM>, Error>
where
P: RxPins + ConfigurePins,
CP: RxClkPin,
{
rx_pins.configure()?;
clk_pin.configure();
Instance::set_rx_bit_order(bit_order);
Instance::set_rx_timeout_ticks(timeout_ticks);
Ok(ParlIoRx {
rx_channel: self.rx_channel,
rx_chain: DescriptorChain::new(self.descriptors),
})
}
}
pub struct ParlIoRx<'d, DM>
where
DM: Mode,
{
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
rx_chain: DescriptorChain,
}
impl<DM> core::fmt::Debug for ParlIoRx<'_, DM>
where
DM: Mode,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParlIoTx").finish()
}
}
fn internal_set_interrupt_handler(handler: InterruptHandler) {
#[cfg(esp32c6)]
{
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::PARL_IO);
}
internal_listen(EnumSet::all(), false);
internal_clear_interrupts(EnumSet::all());
unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler());
unwrap!(crate::interrupt::enable(
Interrupt::PARL_IO,
handler.priority()
));
}
#[cfg(esp32h2)]
{
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
internal_listen(EnumSet::all(), false);
internal_clear_interrupts(EnumSet::all());
unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler());
unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler());
unwrap!(crate::interrupt::enable(
Interrupt::PARL_IO_TX,
handler.priority(),
));
unwrap!(crate::interrupt::enable(
Interrupt::PARL_IO_RX,
handler.priority(),
));
}
}
fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>, enable: bool) {
let parl_io = unsafe { PARL_IO::steal() };
parl_io.int_ena().write(|w| {
for interrupt in interrupts {
match interrupt {
ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().bit(enable),
ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().bit(enable),
ParlIoInterrupt::TxEof => w.tx_eof().bit(enable),
};
}
w
});
}
fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
let mut res = EnumSet::new();
let parl_io = unsafe { PARL_IO::steal() };
let ints = parl_io.int_st().read();
if ints.tx_fifo_rempty().bit() {
res.insert(ParlIoInterrupt::TxFifoReEmpty);
}
if ints.rx_fifo_wovf().bit() {
res.insert(ParlIoInterrupt::RxFifoWOvf);
}
if ints.tx_eof().bit() {
res.insert(ParlIoInterrupt::TxEof);
}
res
}
fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) {
let parl_io = unsafe { PARL_IO::steal() };
parl_io.int_clr().write(|w| {
for interrupt in interrupts {
match interrupt {
ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().clear_bit_by_one(),
ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().clear_bit_by_one(),
ParlIoInterrupt::TxEof => w.tx_eof().clear_bit_by_one(),
};
}
w
});
}
pub struct ParlIoFullDuplex<'d, DM>
where
DM: Mode,
{
pub tx: TxCreatorFullDuplex<'d, DM>,
pub rx: RxCreatorFullDuplex<'d, DM>,
}
impl<'d> ParlIoFullDuplex<'d, Blocking> {
pub fn new<CH, DM>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
dma_channel: Channel<'d, DM, CH>,
tx_descriptors: &'static mut [DmaDescriptor],
rx_descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32,
) -> Result<Self, Error>
where
DM: Mode,
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
Channel<'d, Blocking, CH>: From<Channel<'d, DM, CH>>,
{
let dma_channel = Channel::<Blocking, CH>::from(dma_channel);
internal_init(frequency)?;
Ok(Self {
tx: TxCreatorFullDuplex {
tx_channel: dma_channel.tx.degrade(),
descriptors: tx_descriptors,
},
rx: RxCreatorFullDuplex {
rx_channel: dma_channel.rx.degrade(),
descriptors: rx_descriptors,
},
})
}
pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> {
ParlIoFullDuplex {
tx: TxCreatorFullDuplex {
tx_channel: self.tx.tx_channel.into_async(),
descriptors: self.tx.descriptors,
},
rx: RxCreatorFullDuplex {
rx_channel: self.rx.rx_channel.into_async(),
descriptors: self.rx.descriptors,
},
}
}
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
internal_set_interrupt_handler(handler);
}
pub fn listen(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_listen(interrupts.into(), true);
}
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_listen(interrupts.into(), false);
}
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
internal_interrupts()
}
pub fn clear_interrupts(&mut self, interrupts: EnumSet<ParlIoInterrupt>) {
internal_clear_interrupts(interrupts);
}
}
impl crate::private::Sealed for ParlIoFullDuplex<'_, Blocking> {}
impl InterruptConfigurable for ParlIoFullDuplex<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
ParlIoFullDuplex::set_interrupt_handler(self, handler);
}
}
impl<'d> ParlIoFullDuplex<'d, Async> {
pub fn into_blocking(self) -> ParlIoFullDuplex<'d, Blocking> {
ParlIoFullDuplex {
tx: TxCreatorFullDuplex {
tx_channel: self.tx.tx_channel.into_blocking(),
descriptors: self.tx.descriptors,
},
rx: RxCreatorFullDuplex {
rx_channel: self.rx.rx_channel.into_blocking(),
descriptors: self.rx.descriptors,
},
}
}
}
pub struct ParlIoTxOnly<'d, DM>
where
DM: Mode,
{
pub tx: TxCreator<'d, DM>,
}
impl<'d, DM> ParlIoTxOnly<'d, DM>
where
DM: Mode,
{
pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
dma_channel: Channel<'d, DM, CH>,
descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32,
) -> Result<Self, Error>
where
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
{
internal_init(frequency)?;
Ok(Self {
tx: TxCreator {
tx_channel: dma_channel.tx.degrade(),
descriptors,
},
})
}
}
impl ParlIoTxOnly<'_, Blocking> {
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
internal_set_interrupt_handler(handler);
}
pub fn listen(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_listen(interrupts.into(), true);
}
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_listen(interrupts.into(), false);
}
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
internal_interrupts()
}
pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_clear_interrupts(interrupts.into());
}
}
impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {}
impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
ParlIoTxOnly::set_interrupt_handler(self, handler);
}
}
pub struct ParlIoRxOnly<'d, DM>
where
DM: Mode,
{
pub rx: RxCreator<'d, DM>,
}
impl<'d, DM> ParlIoRxOnly<'d, DM>
where
DM: Mode,
{
pub fn new<CH>(
_parl_io: impl Peripheral<P = peripherals::PARL_IO> + 'd,
dma_channel: Channel<'d, DM, CH>,
descriptors: &'static mut [DmaDescriptor],
frequency: HertzU32,
) -> Result<Self, Error>
where
CH: DmaChannelConvert<<PARL_IO as DmaEligible>::Dma>,
{
internal_init(frequency)?;
Ok(Self {
rx: RxCreator {
rx_channel: dma_channel.rx.degrade(),
descriptors,
},
})
}
}
impl ParlIoRxOnly<'_, Blocking> {
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
internal_set_interrupt_handler(handler);
}
pub fn listen(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_listen(interrupts.into(), true);
}
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_listen(interrupts.into(), false);
}
pub fn interrupts(&mut self) -> EnumSet<ParlIoInterrupt> {
internal_interrupts()
}
pub fn clear_interrupts(&mut self, interrupts: impl Into<EnumSet<ParlIoInterrupt>>) {
internal_clear_interrupts(interrupts.into());
}
}
impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {}
impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
ParlIoRxOnly::set_interrupt_handler(self, handler);
}
}
fn internal_init(frequency: HertzU32) -> Result<(), Error> {
if frequency.raw() > 40_000_000 {
return Err(Error::UnreachableClockRate);
}
PeripheralClockControl::reset(crate::system::Peripheral::ParlIo);
PeripheralClockControl::enable(crate::system::Peripheral::ParlIo);
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
let divider = crate::soc::constants::PARL_IO_SCLK / frequency.raw();
if divider > 0xffff {
return Err(Error::UnreachableClockRate);
}
let divider = divider as u16;
pcr.parl_clk_tx_conf().modify(|_, w| unsafe {
w.parl_clk_tx_en().set_bit();
w.parl_clk_tx_sel().bits(1); w.parl_clk_tx_div_num().bits(divider)
});
pcr.parl_clk_rx_conf().modify(|_, w| unsafe {
w.parl_clk_rx_en().set_bit();
w.parl_clk_rx_sel().bits(1); w.parl_clk_rx_div_num().bits(divider)
});
Instance::set_rx_sw_en(true);
Instance::set_rx_sample_mode(SampleMode::InternalSoftwareEnable);
Ok(())
}
impl<DM> ParlIoTx<'_, DM>
where
DM: Mode,
{
pub fn write_dma<'t, TXBUF>(
&'t mut self,
words: &'t TXBUF,
) -> Result<DmaTransferTx<'t, Self>, Error>
where
TXBUF: ReadBuffer,
{
let (ptr, len) = unsafe { words.read_buffer() };
if len > MAX_DMA_SIZE {
return Err(Error::MaxDmaTransferSizeExceeded);
}
self.start_write_bytes_dma(ptr, len)?;
Ok(DmaTransferTx::new(self))
}
fn start_write_bytes_dma(&mut self, ptr: *const u8, len: usize) -> Result<(), Error> {
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
pcr.parl_clk_tx_conf()
.modify(|_, w| w.parl_tx_rst_en().set_bit());
Instance::clear_tx_interrupts();
Instance::set_tx_bytes(len as u16);
self.tx_channel.is_done();
unsafe {
self.tx_chain.fill_for_tx(false, ptr, len)?;
self.tx_channel
.prepare_transfer_without_start(DmaPeripheral::ParlIo, &self.tx_chain)
.and_then(|_| self.tx_channel.start_transfer())?;
}
while !Instance::is_tx_ready() {}
Instance::set_tx_start(true);
pcr.parl_clk_tx_conf()
.modify(|_, w| w.parl_tx_rst_en().clear_bit());
Ok(())
}
}
impl<DM> DmaSupport for ParlIoTx<'_, DM>
where
DM: Mode,
{
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
while !Instance::is_tx_eof() {}
Instance::set_tx_start(false);
}
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, DM> DmaSupportTx for ParlIoTx<'d, DM>
where
DM: Mode,
{
type TX = ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>;
fn tx(&mut self) -> &mut Self::TX {
&mut self.tx_channel
}
fn chain(&mut self) -> &mut DescriptorChain {
&mut self.tx_chain
}
}
impl<'d, DM> ParlIoRx<'d, DM>
where
DM: Mode,
{
pub fn read_dma<'t, RXBUF>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<DmaTransferRx<'t, Self>, Error>
where
RXBUF: WriteBuffer,
{
let (ptr, len) = unsafe { words.write_buffer() };
if !Instance::is_suc_eof_generated_externally() && len > MAX_DMA_SIZE {
return Err(Error::MaxDmaTransferSizeExceeded);
}
Self::start_receive_bytes_dma(&mut self.rx_channel, &mut self.rx_chain, ptr, len)?;
Ok(DmaTransferRx::new(self))
}
fn start_receive_bytes_dma(
rx_channel: &mut ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
rx_chain: &mut DescriptorChain,
ptr: *mut u8,
len: usize,
) -> Result<(), Error> {
let pcr = unsafe { &*crate::peripherals::PCR::PTR };
pcr.parl_clk_rx_conf()
.modify(|_, w| w.parl_rx_rst_en().set_bit());
pcr.parl_clk_rx_conf()
.modify(|_, w| w.parl_rx_rst_en().clear_bit());
Instance::clear_rx_interrupts();
Instance::set_rx_bytes(len as u16);
unsafe {
rx_chain.fill_for_rx(false, ptr, len)?;
rx_channel
.prepare_transfer_without_start(DmaPeripheral::ParlIo, rx_chain)
.and_then(|_| rx_channel.start_transfer())?;
}
Instance::set_rx_reg_update();
Instance::set_rx_start(true);
Ok(())
}
}
impl<DM> DmaSupport for ParlIoRx<'_, DM>
where
DM: Mode,
{
fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) {
loop {
if self.rx_channel.is_done()
|| self.rx_channel.has_eof_error()
|| self.rx_channel.has_dscr_empty_error()
{
break;
}
}
Instance::set_rx_start(false);
}
fn peripheral_dma_stop(&mut self) {
unreachable!("unsupported")
}
}
impl<'d, DM> DmaSupportRx for ParlIoRx<'d, DM>
where
DM: Mode,
{
type RX = ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>;
fn rx(&mut self) -> &mut Self::RX {
&mut self.rx_channel
}
fn chain(&mut self) -> &mut DescriptorChain {
&mut self.rx_chain
}
}
pub struct TxCreator<'d, DM>
where
DM: Mode,
{
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor],
}
pub struct RxCreator<'d, DM>
where
DM: Mode,
{
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor],
}
pub struct TxCreatorFullDuplex<'d, DM>
where
DM: Mode,
{
tx_channel: ChannelTx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor],
}
pub struct RxCreatorFullDuplex<'d, DM>
where
DM: Mode,
{
rx_channel: ChannelRx<'d, DM, <PARL_IO as DmaEligible>::Dma>,
descriptors: &'static mut [DmaDescriptor],
}
#[doc(hidden)]
pub mod asynch {
use core::task::Poll;
use embassy_sync::waitqueue::AtomicWaker;
use procmacros::handler;
use super::{private::Instance, Error, ParlIoRx, ParlIoTx, MAX_DMA_SIZE};
use crate::{
dma::{asynch::DmaRxFuture, ReadBuffer, WriteBuffer},
peripherals::Interrupt,
};
static TX_WAKER: AtomicWaker = AtomicWaker::new();
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct TxDoneFuture {}
impl TxDoneFuture {
pub fn new() -> Self {
Instance::listen_tx_done();
Self {}
}
}
impl core::future::Future for TxDoneFuture {
type Output = ();
fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
let mut parl_io = unsafe { crate::peripherals::PARL_IO::steal() };
#[cfg(esp32c6)]
{
parl_io.bind_parl_io_interrupt(interrupt_handler.handler());
crate::interrupt::enable(Interrupt::PARL_IO, interrupt_handler.priority()).unwrap();
}
#[cfg(esp32h2)]
{
parl_io.bind_parl_io_tx_interrupt(interrupt_handler.handler());
crate::interrupt::enable(Interrupt::PARL_IO_TX, interrupt_handler.priority())
.unwrap();
}
TX_WAKER.register(cx.waker());
if Instance::is_listening_tx_done() {
Poll::Pending
} else {
Poll::Ready(())
}
}
}
#[handler]
fn interrupt_handler() {
if Instance::is_tx_done_set() {
Instance::clear_is_tx_done();
Instance::unlisten_tx_done();
TX_WAKER.wake()
}
}
impl ParlIoTx<'_, crate::Async> {
pub async fn write_dma_async<TXBUF>(&mut self, words: &TXBUF) -> Result<(), Error>
where
TXBUF: ReadBuffer,
{
let (ptr, len) = unsafe { words.read_buffer() };
if len > MAX_DMA_SIZE {
return Err(Error::MaxDmaTransferSizeExceeded);
}
let future = TxDoneFuture::new();
self.start_write_bytes_dma(ptr, len)?;
future.await;
Ok(())
}
}
impl ParlIoRx<'_, crate::Async> {
pub async fn read_dma_async<'t, RXBUF>(
&'t mut self,
words: &'t mut RXBUF,
) -> Result<(), Error>
where
RXBUF: WriteBuffer,
{
let (ptr, len) = unsafe { words.write_buffer() };
if !Instance::is_suc_eof_generated_externally() && len > MAX_DMA_SIZE {
return Err(Error::MaxDmaTransferSizeExceeded);
}
let future = DmaRxFuture::new(&mut self.rx_channel);
Self::start_receive_bytes_dma(future.rx, &mut self.rx_chain, ptr, len)?;
future.await?;
Ok(())
}
}
}
mod private {
use super::{BitPackOrder, EofMode, Error, SampleEdge};
pub trait FullDuplex {}
pub trait NotContainsValidSignalPin {}
pub trait ContainsValidSignalPin {}
pub trait TxPins {}
pub trait RxPins {}
pub trait TxClkPin {
fn configure(&mut self);
}
pub trait RxClkPin {
fn configure(&mut self);
}
pub trait ConfigurePins {
fn configure(&mut self) -> Result<(), Error>;
}
#[cfg(esp32c6)]
pub(super) enum WidSel {
Bits16 = 0,
Bits8 = 1,
Bits4 = 2,
Bits2 = 3,
Bits1 = 4,
}
#[cfg(esp32h2)]
pub(super) enum WidSel {
Bits8 = 3,
Bits4 = 2,
Bits2 = 1,
Bits1 = 0,
}
pub(super) enum SampleMode {
ExternalLevel = 0,
ExternalPulse = 1,
InternalSoftwareEnable = 2,
}
pub(super) struct Instance;
#[cfg(esp32c6)]
impl Instance {
pub fn set_tx_bit_width(width: WidSel) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_cfg0()
.modify(|_, w| unsafe { w.tx_bus_wid_sel().bits(width as u8) });
}
pub fn set_tx_idle_value(value: u16) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_cfg1()
.modify(|_, w| unsafe { w.tx_idle_value().bits(value) });
}
pub fn set_tx_sample_edge(value: SampleEdge) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_cfg0()
.modify(|_, w| w.tx_smp_edge_sel().bit(value as u8 == 1));
}
pub fn set_tx_bit_order(value: BitPackOrder) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_cfg0()
.modify(|_, w| w.tx_bit_unpack_order().bit(value as u8 == 1));
}
pub fn clear_tx_interrupts() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_clr().write(|w| {
w.tx_fifo_rempty()
.clear_bit_by_one()
.tx_eof()
.clear_bit_by_one()
});
}
pub fn set_tx_bytes(len: u16) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_cfg0()
.modify(|_, w| unsafe { w.tx_bytelen().bits(len) });
}
pub fn is_tx_ready() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.st().read().tx_ready().bit_is_set()
}
pub fn set_tx_start(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.tx_cfg0().modify(|_, w| w.tx_start().bit(value));
}
pub fn is_tx_eof() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_raw().read().tx_eof().bit_is_set()
}
pub fn tx_valid_pin_signal() -> crate::gpio::OutputSignal {
crate::gpio::OutputSignal::PARL_TX_DATA15
}
pub fn set_tx_hw_valid_en(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_cfg0()
.modify(|_, w| w.tx_hw_valid_en().bit(value));
}
pub fn set_rx_bit_width(width: WidSel) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| unsafe { w.rx_bus_wid_sel().bits(width as u8) });
}
pub fn rx_valid_pin_signal() -> crate::gpio::InputSignal {
crate::gpio::InputSignal::PARL_RX_DATA15
}
pub fn set_rx_sw_en(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.rx_cfg0().modify(|_, w| w.rx_sw_en().bit(value));
}
pub fn clear_rx_interrupts() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.int_clr()
.write(|w| w.rx_fifo_wovf().clear_bit_by_one());
}
pub fn set_rx_bytes(len: u16) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| unsafe { w.rx_data_bytelen().bits(len) });
}
pub fn set_rx_sample_mode(sample_mode: SampleMode) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| unsafe { w.rx_smp_mode_sel().bits(sample_mode as u8) });
}
pub fn set_eof_gen_sel(mode: EofMode) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| w.rx_eof_gen_sel().bit(mode == EofMode::EnableSignal));
}
pub fn set_rx_pulse_submode_sel(sel: u8) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| unsafe { w.rx_pulse_submode_sel().bits(sel) });
}
pub fn set_rx_level_submode_sel(sel: u8) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| w.rx_level_submode_sel().bit(sel == 1));
}
pub fn set_rx_clk_edge_sel(edge: SampleEdge) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| w.rx_clk_edge_sel().bit(edge as u8 == 1));
}
pub fn set_rx_start(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.rx_cfg0().modify(|_, w| w.rx_start().bit(value));
}
pub fn set_rx_reg_update() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg1()
.modify(|_, w| w.rx_reg_update().bit(true));
}
pub fn set_rx_bit_order(value: BitPackOrder) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_cfg0()
.modify(|_, w| w.rx_bit_pack_order().bit(value as u8 == 1));
}
pub fn set_rx_timeout_ticks(value: Option<u16>) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.rx_cfg1().modify(|_, w| unsafe {
w.rx_timeout_en()
.bit(value.is_some())
.rx_timeout_threshold()
.bits(value.unwrap_or(0xfff))
});
}
pub fn is_suc_eof_generated_externally() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.rx_cfg0().read().rx_eof_gen_sel().bit_is_set()
}
pub fn listen_tx_done() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_ena().modify(|_, w| w.tx_eof().set_bit());
}
pub fn unlisten_tx_done() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_ena().modify(|_, w| w.tx_eof().clear_bit());
}
pub fn is_listening_tx_done() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_ena().read().tx_eof().bit()
}
pub fn is_tx_done_set() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_raw().read().tx_eof().bit()
}
pub fn clear_is_tx_done() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_clr().write(|w| w.tx_eof().clear_bit_by_one());
}
}
#[cfg(esp32h2)]
impl Instance {
pub fn set_tx_bit_width(width: WidSel) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_data_cfg()
.modify(|_, w| unsafe { w.tx_bus_wid_sel().bits(width as u8) });
}
pub fn set_tx_idle_value(value: u16) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_genrl_cfg()
.modify(|_, w| unsafe { w.tx_idle_value().bits(value) });
}
pub fn set_tx_sample_edge(value: SampleEdge) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.tx_clk_cfg().modify(|_, w| {
w.tx_clk_i_inv()
.bit(value == SampleEdge::Invert)
.tx_clk_o_inv()
.bit(value == SampleEdge::Invert)
});
}
pub fn set_tx_bit_order(value: BitPackOrder) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_data_cfg()
.modify(|_, w| w.tx_data_order_inv().bit(value as u8 == 1));
}
pub fn clear_tx_interrupts() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_clr().write(|w| {
w.tx_fifo_rempty()
.clear_bit_by_one()
.tx_eof()
.clear_bit_by_one()
});
}
pub fn set_tx_bytes(len: u16) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_data_cfg()
.modify(|_, w| unsafe { w.tx_bitlen().bits((len as u32) * 8) });
}
pub fn is_tx_ready() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.st().read().tx_ready().bit_is_set()
}
pub fn set_tx_start(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_start_cfg()
.modify(|_, w| w.tx_start().bit(value));
}
pub fn is_tx_eof() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_raw().read().tx_eof().bit_is_set()
}
pub fn tx_valid_pin_signal() -> crate::gpio::OutputSignal {
crate::gpio::OutputSignal::PARL_TX_DATA7
}
pub fn set_tx_hw_valid_en(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.tx_genrl_cfg()
.modify(|_, w| w.tx_valid_output_en().bit(value));
}
pub fn set_rx_bit_width(width: WidSel) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_data_cfg()
.modify(|_, w| unsafe { w.rx_bus_wid_sel().bits(width as u8) });
}
pub fn rx_valid_pin_signal() -> crate::gpio::InputSignal {
crate::gpio::InputSignal::PARL_RX_DATA7
}
pub fn set_rx_sw_en(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_mode_cfg()
.modify(|_, w| w.rx_sw_en().bit(value));
}
pub fn clear_rx_interrupts() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.int_clr()
.write(|w| w.rx_fifo_wovf().clear_bit_by_one());
}
pub fn set_rx_bytes(len: u16) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_data_cfg()
.modify(|_, w| unsafe { w.rx_bitlen().bits((len as u32) * 8) });
}
pub fn set_rx_sample_mode(sample_mode: SampleMode) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_mode_cfg()
.modify(|_, w| unsafe { w.rx_smp_mode_sel().bits(sample_mode as u8) });
}
pub fn set_eof_gen_sel(mode: EofMode) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_genrl_cfg()
.modify(|_, w| w.rx_eof_gen_sel().bit(mode == EofMode::EnableSignal));
}
pub fn set_rx_pulse_submode_sel(sel: u8) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_mode_cfg()
.modify(|_, w| unsafe { w.rx_pulse_submode_sel().bits(sel) });
}
pub fn set_rx_level_submode_sel(_sel: u8) {
}
pub fn set_rx_clk_edge_sel(value: SampleEdge) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.rx_clk_cfg().modify(|_, w| {
w.rx_clk_i_inv()
.bit(value == SampleEdge::Invert)
.rx_clk_o_inv()
.bit(value == SampleEdge::Invert)
});
}
pub fn set_rx_start(value: bool) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_start_cfg()
.modify(|_, w| w.rx_start().bit(value));
}
pub fn set_rx_reg_update() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.reg_update()
.write(|w| w.rx_reg_update().bit(true));
}
pub fn set_rx_bit_order(value: BitPackOrder) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_data_cfg()
.modify(|_, w| w.rx_data_order_inv().bit(value as u8 == 1));
}
pub fn set_rx_timeout_ticks(value: Option<u16>) {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.rx_genrl_cfg().modify(|_, w| unsafe {
w.rx_timeout_en()
.bit(value.is_some())
.rx_timeout_thres()
.bits(value.unwrap_or(0xfff))
});
}
pub fn is_suc_eof_generated_externally() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block
.rx_genrl_cfg()
.read()
.rx_eof_gen_sel()
.bit_is_set()
}
pub fn listen_tx_done() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_ena().modify(|_, w| w.tx_eof().set_bit());
}
pub fn unlisten_tx_done() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_ena().modify(|_, w| w.tx_eof().clear_bit());
}
pub fn is_listening_tx_done() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_ena().read().tx_eof().bit()
}
pub fn is_tx_done_set() -> bool {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_raw().read().tx_eof().bit()
}
pub fn clear_is_tx_done() {
let reg_block: crate::peripherals::PARL_IO =
unsafe { crate::peripherals::PARL_IO::steal() };
reg_block.int_clr().write(|w| w.tx_eof().clear_bit_by_one());
}
}
}