#![cfg_attr(docsrs, procmacros::doc_replace)]
use core::{
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
use enumset::{EnumSet, EnumSetType};
use private::*;
use crate::{
Async,
Blocking,
DriverMode,
dma::{
Channel,
ChannelRx,
ChannelTx,
DmaChannelFor,
DmaError,
DmaPeripheral,
DmaRxBuffer,
DmaTxBuffer,
PeripheralRxChannel,
PeripheralTxChannel,
},
gpio::{
self,
InputSignal,
NoPin,
OutputSignal,
interconnect::{self, PeripheralInput, PeripheralOutput},
},
interrupt::InterruptHandler,
parl_io::asynch::interrupt_handler,
peripherals::{PARL_IO, PCR},
soc::clocks::{ClockTree, ParlIoInstance},
system::{GenericPeripheralGuard, Peripheral},
time::Rate,
};
const MAX_DMA_SIZE: usize = 65535;
#[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))]
#[allow(clippy::enum_variant_names, reason = "peripheral is unstable")]
pub enum Error {
DmaError(DmaError),
MaxDmaTransferSizeExceeded,
}
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(parl_io_version = "1")]
#[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(parl_io_version = "1")]
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(parl_io_version = "2")]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EnableMode {
HighLevel,
PulseMode1,
PulseMode2,
PulseMode3,
PulseMode4,
PulseMode5,
PulseMode6,
}
#[cfg(parl_io_version = "2")]
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, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct RxConfig {
frequency: Rate,
bit_order: BitPackOrder,
timeout_ticks: Option<u16>,
}
impl Default for RxConfig {
fn default() -> Self {
Self {
frequency: Rate::from_khz(100),
bit_order: BitPackOrder::Msb,
timeout_ticks: None,
}
}
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct TxConfig {
frequency: Rate,
idle_value: u16,
sample_edge: SampleEdge,
bit_order: BitPackOrder,
}
impl Default for TxConfig {
fn default() -> Self {
Self {
frequency: Rate::from_khz(100),
idle_value: 0,
sample_edge: SampleEdge::Normal,
bit_order: BitPackOrder::Msb,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigError {
UnreachableClockRate,
}
impl core::error::Error for ConfigError {}
impl core::fmt::Display for ConfigError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ConfigError::UnreachableClockRate => {
write!(f, "The requested frequency is not supported")
}
}
}
}
impl TxClkPin for NoPin {
fn configure(&mut self) {
OutputSignal::PARL_TX_CLK.connect_to(self);
}
}
impl RxClkPin for NoPin {
fn configure(&mut self) {
InputSignal::PARL_RX_CLK.connect_to(self);
}
}
pub struct ClkOutPin<'d> {
pin: interconnect::OutputSignal<'d>,
}
impl<'d> ClkOutPin<'d> {
pub fn new(pin: impl PeripheralOutput<'d>) -> Self {
Self { pin: pin.into() }
}
}
impl TxClkPin for ClkOutPin<'_> {
fn configure(&mut self) {
self.pin.apply_output_config(&gpio::OutputConfig::default());
self.pin.set_output_enable(true);
OutputSignal::PARL_TX_CLK.connect_to(&self.pin);
}
}
pub struct ClkInPin<'d> {
pin: interconnect::InputSignal<'d>,
}
impl<'d> ClkInPin<'d> {
pub fn new(pin: impl PeripheralInput<'d>) -> Self {
Self { pin: pin.into() }
}
}
impl TxClkPin for ClkInPin<'_> {
fn configure(&mut self) {
let pcr = PCR::regs();
pcr.parl_clk_tx_conf()
.modify(|_, w| unsafe { w.parl_clk_tx_sel().bits(3).parl_clk_tx_div_num().bits(0) });
self.pin.apply_input_config(&gpio::InputConfig::default());
self.pin.set_input_enable(true);
InputSignal::PARL_TX_CLK.connect_to(&self.pin);
}
}
pub struct RxClkInPin<'d> {
pin: interconnect::InputSignal<'d>,
sample_edge: SampleEdge,
}
impl<'d> RxClkInPin<'d> {
pub fn new(pin: impl PeripheralInput<'d>, sample_edge: SampleEdge) -> Self {
Self {
pin: pin.into(),
sample_edge,
}
}
}
impl RxClkPin for RxClkInPin<'_> {
fn configure(&mut self) {
let pcr = PCR::regs();
pcr.parl_clk_rx_conf()
.modify(|_, w| unsafe { w.parl_clk_rx_sel().bits(3).parl_clk_rx_div_num().bits(0) });
self.pin.apply_input_config(&gpio::InputConfig::default());
self.pin.set_input_enable(true);
InputSignal::PARL_RX_CLK.connect_to(&self.pin);
Instance::set_rx_clk_edge_sel(self.sample_edge);
}
}
pub struct TxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + TxPins + ConfigurePins + 'd,
{
tx_pins: P,
valid_pin: interconnect::OutputSignal<'d>,
}
impl<'d, P> TxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + TxPins + ConfigurePins + 'd,
{
pub fn new(tx_pins: P, valid_pin: impl PeripheralOutput<'d>) -> Self {
Self {
tx_pins,
valid_pin: valid_pin.into(),
}
}
}
impl<'d, P> TxPins for TxPinConfigWithValidPin<'d, P> where
P: NotContainsValidSignalPin + TxPins + ConfigurePins + 'd
{
}
impl<'d, P> ConfigurePins for TxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + TxPins + ConfigurePins + 'd,
{
fn configure(&mut self) {
self.tx_pins.configure();
self.valid_pin
.apply_output_config(&gpio::OutputConfig::default());
self.valid_pin.set_output_enable(true);
#[cfg(esp32c5)]
{
use crate::gpio::interconnect::OutputSignal;
let valid_pin = core::mem::replace(
&mut self.valid_pin,
OutputSignal::new_level(crate::gpio::Level::Low),
);
let was_inverted = valid_pin.is_output_inverted();
self.valid_pin = valid_pin.with_output_inverter(!was_inverted);
}
Instance::tx_valid_pin_signal().connect_to(&self.valid_pin);
Instance::set_tx_hw_valid_en(true);
}
}
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) {
self.tx_pins.configure();
Instance::set_tx_hw_valid_en(true);
}
}
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 >] : interconnect::OutputSignal<'d>,
)+
}
impl<'d> $name<'d>
{
#[allow(clippy::too_many_arguments)]
pub fn new(
$(
[< pin_ $pin:lower >] : impl PeripheralOutput<'d>,
)+
) -> Self {
Self { $( [< pin_ $pin:lower >]: [< pin_ $pin:lower >].into() ),+ }
}
}
impl ConfigurePins for $name<'_>
{
fn configure(&mut self) {
$(
self.[< pin_ $pin:lower >].apply_output_config(&gpio::OutputConfig::default());
self.[< pin_ $pin:lower >].set_output_enable(true);
OutputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]);
)+
private::Instance::set_tx_bit_width( private::WidSel::[< Bits $width >]);
}
}
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(parl_io_version = "1")]
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 NotContainsValidSignalPin for TxOneBit<'_> {}
impl NotContainsValidSignalPin for TxTwoBits<'_> {}
impl NotContainsValidSignalPin for TxFourBits<'_> {}
#[cfg(any(esp32c5, esp32c6))]
impl NotContainsValidSignalPin for TxEightBits<'_> {}
#[cfg(esp32h2)]
impl ContainsValidSignalPin for TxEightBits<'_> {}
#[cfg(parl_io_version = "1")]
impl ContainsValidSignalPin for TxSixteenBits<'_> {}
pub struct RxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + RxPins + ConfigurePins,
{
rx_pins: P,
valid_pin: interconnect::InputSignal<'d>,
enable_mode: EnableMode,
}
impl<'d, P> RxPinConfigWithValidPin<'d, P>
where
P: NotContainsValidSignalPin + RxPins + ConfigurePins,
{
pub fn new(rx_pins: P, valid_pin: impl PeripheralInput<'d>, enable_mode: EnableMode) -> Self {
Self {
rx_pins,
valid_pin: valid_pin.into(),
enable_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) {
self.rx_pins.configure();
self.valid_pin
.apply_input_config(&gpio::InputConfig::default());
self.valid_pin.set_input_enable(true);
Instance::rx_valid_pin_signal().connect_to(&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);
}
}
}
pub struct RxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + RxPins + ConfigurePins,
{
rx_pins: P,
enable_mode: EnableMode,
}
impl<P> RxPinConfigIncludingValidPin<P>
where
P: ContainsValidSignalPin + RxPins + ConfigurePins,
{
pub fn new(rx_pins: P, enable_mode: EnableMode) -> Self {
Self {
rx_pins,
enable_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) {
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);
}
}
}
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 >] : interconnect::InputSignal<'d>,
)+
}
impl<'d> $name<'d>
{
#[allow(clippy::too_many_arguments)]
pub fn new(
$(
[< pin_ $pin:lower >] : impl PeripheralInput<'d>,
)+
) -> Self {
Self { $( [< pin_ $pin:lower >]: [< pin_ $pin:lower >].into() ),+ }
}
}
impl ConfigurePins for $name<'_>
{
fn configure(&mut self) {
$(
self.[< pin_ $pin:lower >].apply_input_config(&gpio::InputConfig::default());
self.[< pin_ $pin:lower >].set_input_enable(true);
InputSignal::$signal.connect_to(&self.[< pin_ $pin:lower >]);
)+
private::Instance::set_rx_bit_width( private::WidSel::[< Bits $width >]);
}
}
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(parl_io_version = "1")]
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 NotContainsValidSignalPin for RxOneBit<'_> {}
impl NotContainsValidSignalPin for RxTwoBits<'_> {}
impl NotContainsValidSignalPin for RxFourBits<'_> {}
#[cfg(any(esp32c5, esp32c6))]
impl NotContainsValidSignalPin for RxEightBits<'_> {}
#[cfg(esp32h2)]
impl ContainsValidSignalPin for RxEightBits<'_> {}
#[cfg(parl_io_version = "1")]
impl ContainsValidSignalPin for RxSixteenBits<'_> {}
impl<'d, Dm> TxCreator<'d, Dm>
where
Dm: DriverMode,
{
pub fn with_config<P, CP>(
self,
mut tx_pins: P,
mut clk_pin: CP,
config: TxConfig,
) -> Result<ParlIoTx<'d, Dm>, ConfigError>
where
P: TxPins + ConfigurePins + 'd,
CP: TxClkPin + 'd,
{
tx_pins.configure();
clk_pin.configure();
let mut this = ParlIoTx {
tx_channel: self.tx_channel,
_guard: ParlIoTxGuard::new(self._guard),
};
this.apply_config(&config)?;
Ok(this)
}
}
#[instability::unstable]
pub struct ParlIoTx<'d, Dm>
where
Dm: DriverMode,
{
tx_channel: ChannelTx<Dm, PeripheralTxChannel<PARL_IO<'d>>>,
_guard: ParlIoTxGuard,
}
impl<Dm> core::fmt::Debug for ParlIoTx<'_, Dm>
where
Dm: DriverMode,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParlIoTx").finish()
}
}
impl<'d, Dm> RxCreator<'d, Dm>
where
Dm: DriverMode,
{
pub fn with_config<P, CP>(
self,
mut rx_pins: P,
mut clk_pin: CP,
config: RxConfig,
) -> Result<ParlIoRx<'d, Dm>, ConfigError>
where
P: RxPins + ConfigurePins + 'd,
CP: RxClkPin + 'd,
{
Instance::set_rx_sw_en(true);
Instance::set_rx_sample_mode(SampleMode::InternalSoftwareEnable);
rx_pins.configure();
clk_pin.configure();
let mut this = ParlIoRx {
rx_channel: self.rx_channel,
_guard: ParlIoRxGuard::new(self._guard),
};
this.apply_config(&config)?;
Ok(this)
}
}
#[instability::unstable]
pub struct ParlIoRx<'d, Dm>
where
Dm: DriverMode,
{
rx_channel: ChannelRx<Dm, PeripheralRxChannel<PARL_IO<'d>>>,
_guard: ParlIoRxGuard,
}
impl<Dm> core::fmt::Debug for ParlIoRx<'_, Dm>
where
Dm: DriverMode,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ParlIoTx").finish()
}
}
fn internal_set_interrupt_handler(handler: InterruptHandler) {
let peri = unsafe { PARL_IO::steal() };
#[cfg(parl_io_version = "1")]
{
peri.disable_peri_interrupt_on_all_cores();
internal_listen(EnumSet::all(), false);
internal_clear_interrupts(EnumSet::all());
peri.bind_peri_interrupt(handler);
}
#[cfg(parl_io_version = "2")]
{
peri.disable_rx_interrupt_on_all_cores();
peri.disable_tx_interrupt_on_all_cores();
internal_listen(EnumSet::all(), false);
internal_clear_interrupts(EnumSet::all());
peri.bind_rx_interrupt(handler);
peri.bind_tx_interrupt(handler);
}
}
fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>, enable: bool) {
PARL_IO::regs().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 = PARL_IO::regs();
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 = PARL_IO::regs();
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 ParlIo<'d, Dm>
where
Dm: DriverMode,
{
pub tx: TxCreator<'d, Dm>,
pub rx: RxCreator<'d, Dm>,
}
impl<'d> ParlIo<'d, Blocking> {
pub fn new(
_parl_io: PARL_IO<'d>,
dma_channel: impl DmaChannelFor<PARL_IO<'d>>,
) -> Result<Self, Error> {
let tx_guard = GenericPeripheralGuard::new();
let rx_guard = GenericPeripheralGuard::new();
let dma_channel = Channel::new(dma_channel.degrade());
Ok(Self {
tx: TxCreator {
tx_channel: dma_channel.tx,
_guard: tx_guard,
},
rx: RxCreator {
rx_channel: dma_channel.rx,
_guard: rx_guard,
},
})
}
pub fn into_async(self) -> ParlIo<'d, Async> {
internal_set_interrupt_handler(interrupt_handler);
ParlIo {
tx: TxCreator {
tx_channel: self.tx.tx_channel.into_async(),
_guard: self.tx._guard,
},
rx: RxCreator {
rx_channel: self.rx.rx_channel.into_async(),
_guard: self.rx._guard,
},
}
}
#[instability::unstable]
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 ParlIo<'_, Blocking> {}
#[instability::unstable]
impl crate::interrupt::InterruptConfigurable for ParlIo<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
ParlIo::set_interrupt_handler(self, handler);
}
}
impl<'d> ParlIo<'d, Async> {
pub fn into_blocking(self) -> ParlIo<'d, Blocking> {
ParlIo {
tx: TxCreator {
tx_channel: self.tx.tx_channel.into_blocking(),
_guard: self.tx._guard,
},
rx: RxCreator {
rx_channel: self.rx.rx_channel.into_blocking(),
_guard: self.rx._guard,
},
}
}
}
impl<'d, Dm> ParlIoTx<'d, Dm>
where
Dm: DriverMode,
{
pub fn write<BUF>(
mut self,
number_of_bytes: usize,
mut buffer: BUF,
) -> Result<ParlIoTxTransfer<'d, BUF, Dm>, (Error, Self, BUF)>
where
BUF: DmaTxBuffer,
{
if number_of_bytes > MAX_DMA_SIZE {
return Err((Error::MaxDmaTransferSizeExceeded, self, buffer));
}
PCR::regs()
.parl_clk_tx_conf()
.modify(|_, w| w.parl_tx_rst_en().set_bit());
Instance::clear_tx_interrupts();
Instance::set_tx_bytes(number_of_bytes as u16);
let result = unsafe {
self.tx_channel
.prepare_transfer(DmaPeripheral::ParlIo, &mut buffer)
.and_then(|_| self.tx_channel.start_transfer())
};
if let Err(err) = result {
return Err((Error::DmaError(err), self, buffer));
}
while !Instance::is_tx_ready() {}
Instance::set_tx_start(true);
PCR::regs()
.parl_clk_tx_conf()
.modify(|_, w| w.parl_tx_rst_en().clear_bit());
Ok(ParlIoTxTransfer {
parl_io: ManuallyDrop::new(self),
buf_view: ManuallyDrop::new(buffer.into_view()),
})
}
pub fn apply_config(&mut self, config: &TxConfig) -> Result<(), ConfigError> {
if config.frequency.as_hz() > 40_000_000 {
return Err(ConfigError::UnreachableClockRate);
}
let frequency = ClockTree::with(|clocks| ParlIoInstance::ParlIo.tx_clock_frequency(clocks));
let divider = frequency / config.frequency.as_hz();
if divider > 0xFFFF {
return Err(ConfigError::UnreachableClockRate);
}
let divider = divider as u16;
PCR::regs()
.parl_clk_tx_conf()
.modify(|_, w| unsafe { w.parl_clk_tx_div_num().bits(divider) });
Instance::set_tx_idle_value(config.idle_value);
Instance::set_tx_sample_edge(config.sample_edge);
Instance::set_tx_bit_order(config.bit_order);
Ok(())
}
}
pub struct ParlIoTxTransfer<'d, BUF: DmaTxBuffer, Dm: DriverMode> {
parl_io: ManuallyDrop<ParlIoTx<'d, Dm>>,
buf_view: ManuallyDrop<BUF::View>,
}
impl<'d, BUF: DmaTxBuffer, Dm: DriverMode> ParlIoTxTransfer<'d, BUF, Dm> {
pub fn is_done(&self) -> bool {
Instance::is_tx_eof()
}
pub fn wait(mut self) -> (Result<(), DmaError>, ParlIoTx<'d, Dm>, BUF::Final) {
while !self.is_done() {}
Instance::set_tx_start(false);
Instance::clear_is_tx_done();
self.parl_io.tx_channel.stop_transfer();
let (parl_io, view) = self.release();
let result = if parl_io.tx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
};
(result, parl_io, BUF::from_view(view))
}
fn release(mut self) -> (ParlIoTx<'d, Dm>, BUF::View) {
let (parl_io, view) = unsafe {
(
ManuallyDrop::take(&mut self.parl_io),
ManuallyDrop::take(&mut self.buf_view),
)
};
core::mem::forget(self);
(parl_io, view)
}
}
impl<BUF: DmaTxBuffer, Dm: DriverMode> Deref for ParlIoTxTransfer<'_, BUF, Dm> {
type Target = BUF::View;
fn deref(&self) -> &Self::Target {
&self.buf_view
}
}
impl<BUF: DmaTxBuffer, Dm: DriverMode> DerefMut for ParlIoTxTransfer<'_, BUF, Dm> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buf_view
}
}
impl<BUF: DmaTxBuffer, Dm: DriverMode> Drop for ParlIoTxTransfer<'_, BUF, Dm> {
fn drop(&mut self) {
self.parl_io.tx_channel.stop_transfer();
let view = unsafe {
ManuallyDrop::drop(&mut self.parl_io);
ManuallyDrop::take(&mut self.buf_view)
};
let _ = BUF::from_view(view);
}
}
impl<'d, Dm> ParlIoRx<'d, Dm>
where
Dm: DriverMode,
{
pub fn read<BUF>(
mut self,
number_of_bytes: Option<usize>,
mut buffer: BUF,
) -> Result<ParlIoRxTransfer<'d, BUF, Dm>, (Error, Self, BUF)>
where
BUF: DmaRxBuffer,
{
PCR::regs()
.parl_clk_rx_conf()
.modify(|_, w| w.parl_rx_rst_en().set_bit());
Instance::clear_rx_interrupts();
if let Some(number_of_bytes) = number_of_bytes {
if number_of_bytes > MAX_DMA_SIZE {
return Err((Error::MaxDmaTransferSizeExceeded, self, buffer));
}
Instance::set_rx_bytes(number_of_bytes as u16);
Instance::set_eof_gen_sel(EofMode::ByteLen);
} else {
Instance::set_eof_gen_sel(EofMode::EnableSignal);
}
let result = unsafe {
self.rx_channel
.prepare_transfer(DmaPeripheral::ParlIo, &mut buffer)
.and_then(|_| self.rx_channel.start_transfer())
};
if let Err(err) = result {
return Err((Error::DmaError(err), self, buffer));
}
Instance::set_rx_reg_update();
Instance::set_rx_start(true);
PCR::regs()
.parl_clk_rx_conf()
.modify(|_, w| w.parl_rx_rst_en().clear_bit());
Ok(ParlIoRxTransfer {
parl_io: ManuallyDrop::new(self),
buf_view: ManuallyDrop::new(buffer.into_view()),
dma_result: None,
})
}
pub fn apply_config(&mut self, config: &RxConfig) -> Result<(), ConfigError> {
if config.frequency.as_hz() > 40_000_000 {
return Err(ConfigError::UnreachableClockRate);
}
let frequency = ClockTree::with(|clocks| ParlIoInstance::ParlIo.rx_clock_frequency(clocks));
let divider = frequency / config.frequency.as_hz();
if divider > 0xffff {
return Err(ConfigError::UnreachableClockRate);
}
let divider = divider as u16;
PCR::regs()
.parl_clk_rx_conf()
.modify(|_, w| unsafe { w.parl_clk_rx_div_num().bits(divider) });
Instance::set_rx_bit_order(config.bit_order);
Instance::set_rx_timeout_ticks(config.timeout_ticks);
Ok(())
}
}
pub struct ParlIoRxTransfer<'d, BUF: DmaRxBuffer, Dm: DriverMode> {
parl_io: ManuallyDrop<ParlIoRx<'d, Dm>>,
buf_view: ManuallyDrop<BUF::View>,
dma_result: Option<Result<(), DmaError>>,
}
impl<'d, BUF: DmaRxBuffer, Dm: DriverMode> ParlIoRxTransfer<'d, BUF, Dm> {
pub fn is_done(&self) -> bool {
if self.dma_result.is_some() {
return true;
}
let ch = &self.parl_io.rx_channel;
ch.is_done() || ch.has_eof_error() || ch.has_dscr_empty_error()
}
pub fn wait(mut self) -> (Result<(), DmaError>, ParlIoRx<'d, Dm>, BUF::Final) {
while !self.is_done() {}
Instance::set_rx_start(false);
self.parl_io.rx_channel.stop_transfer();
let dma_result = self.dma_result.take();
let (parl_io, view) = self.release();
let result = if parl_io.rx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
dma_result.unwrap_or(Ok(()))
};
(result, parl_io, BUF::from_view(view))
}
fn release(mut self) -> (ParlIoRx<'d, Dm>, BUF::View) {
let (parl_io, view) = unsafe {
(
ManuallyDrop::take(&mut self.parl_io),
ManuallyDrop::take(&mut self.buf_view),
)
};
core::mem::forget(self);
(parl_io, view)
}
}
impl<BUF: DmaRxBuffer, Dm: DriverMode> Deref for ParlIoRxTransfer<'_, BUF, Dm> {
type Target = BUF::View;
fn deref(&self) -> &Self::Target {
&self.buf_view
}
}
impl<BUF: DmaRxBuffer, Dm: DriverMode> DerefMut for ParlIoRxTransfer<'_, BUF, Dm> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buf_view
}
}
impl<BUF: DmaRxBuffer, Dm: DriverMode> Drop for ParlIoRxTransfer<'_, BUF, Dm> {
fn drop(&mut self) {
self.parl_io.rx_channel.stop_transfer();
let view = unsafe {
ManuallyDrop::drop(&mut self.parl_io);
ManuallyDrop::take(&mut self.buf_view)
};
let _ = BUF::from_view(view);
}
}
pub struct TxCreator<'d, Dm>
where
Dm: DriverMode,
{
tx_channel: ChannelTx<Dm, PeripheralTxChannel<PARL_IO<'d>>>,
_guard: GenericPeripheralGuard<{ Peripheral::ParlIo as u8 }>,
}
pub struct RxCreator<'d, Dm>
where
Dm: DriverMode,
{
rx_channel: ChannelRx<Dm, PeripheralRxChannel<PARL_IO<'d>>>,
_guard: GenericPeripheralGuard<{ Peripheral::ParlIo as u8 }>,
}
#[doc(hidden)]
pub trait TxPins {}
#[doc(hidden)]
pub trait RxPins {}
#[doc(hidden)]
pub trait ConfigurePins {
fn configure(&mut self);
}
#[doc(hidden)]
pub mod asynch {
use core::task::Poll;
use procmacros::handler;
use super::{ParlIoRxTransfer, ParlIoTxTransfer, private::Instance};
use crate::{
asynch::AtomicWaker,
dma::{DmaRxBuffer, DmaTxBuffer, asynch::DmaRxFuture},
};
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 {
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> {
if Instance::is_tx_done_set() {
Poll::Ready(())
} else {
TX_WAKER.register(cx.waker());
Instance::listen_tx_done();
Poll::Pending
}
}
}
impl Drop for TxDoneFuture {
fn drop(&mut self) {
Instance::unlisten_tx_done();
}
}
#[handler]
pub(super) fn interrupt_handler() {
if Instance::is_tx_done_set() {
Instance::unlisten_tx_done();
TX_WAKER.wake()
}
}
impl<BUF: DmaTxBuffer> ParlIoTxTransfer<'_, BUF, crate::Async> {
pub async fn wait_for_done(&mut self) {
let future = TxDoneFuture::new();
future.await;
}
}
impl<BUF: DmaRxBuffer> ParlIoRxTransfer<'_, BUF, crate::Async> {
pub async fn wait_for_done(&mut self) {
if self.dma_result.is_some() {
return;
}
let future = DmaRxFuture::new(&mut self.parl_io.rx_channel);
self.dma_result = Some(future.await);
}
}
}
mod private {
use super::{BitPackOrder, SampleEdge};
use crate::{
gpio::{InputSignal, OutputSignal},
peripherals::PARL_IO,
};
pub trait NotContainsValidSignalPin {}
pub trait ContainsValidSignalPin {}
pub trait TxClkPin {
fn configure(&mut self);
}
pub trait RxClkPin {
fn configure(&mut self);
}
#[cfg(parl_io_version = "1")]
pub(super) enum WidSel {
Bits16 = 0,
Bits8 = 1,
Bits4 = 2,
Bits2 = 3,
Bits1 = 4,
}
#[cfg(parl_io_version = "2")]
pub(super) enum WidSel {
Bits8 = 3,
Bits4 = 2,
Bits2 = 1,
Bits1 = 0,
}
pub(super) enum SampleMode {
ExternalLevel = 0,
ExternalPulse = 1,
InternalSoftwareEnable = 2,
}
pub(super) enum EofMode {
ByteLen,
EnableSignal,
}
pub(super) struct Instance;
#[cfg(parl_io_version = "1")]
impl Instance {
pub fn set_tx_bit_width(width: WidSel) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block
.tx_cfg1()
.modify(|_, w| unsafe { w.tx_idle_value().bits(value) });
}
pub fn set_tx_sample_edge(value: SampleEdge) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block
.tx_cfg0()
.modify(|_, w| w.tx_bit_unpack_order().bit(value as u8 == 1));
}
pub fn clear_tx_interrupts() {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block
.tx_cfg0()
.modify(|_, w| unsafe { w.tx_bytelen().bits(len) });
}
pub fn is_tx_ready() -> bool {
let reg_block = PARL_IO::regs();
reg_block.st().read().tx_ready().bit_is_set()
}
pub fn set_tx_start(value: bool) {
let reg_block = PARL_IO::regs();
reg_block.tx_cfg0().modify(|_, w| w.tx_start().bit(value));
}
pub fn is_tx_eof() -> bool {
let reg_block = PARL_IO::regs();
reg_block.int_raw().read().tx_eof().bit_is_set()
}
pub fn tx_valid_pin_signal() -> OutputSignal {
OutputSignal::PARL_TX_DATA15
}
pub fn set_tx_hw_valid_en(value: bool) {
let reg_block = PARL_IO::regs();
reg_block
.tx_cfg0()
.modify(|_, w| w.tx_hw_valid_en().bit(value));
}
pub fn set_rx_bit_width(width: WidSel) {
let reg_block = PARL_IO::regs();
reg_block
.rx_cfg0()
.modify(|_, w| unsafe { w.rx_bus_wid_sel().bits(width as u8) });
}
pub fn rx_valid_pin_signal() -> InputSignal {
InputSignal::PARL_RX_DATA15
}
pub fn set_rx_sw_en(value: bool) {
let reg_block = PARL_IO::regs();
reg_block.rx_cfg0().modify(|_, w| w.rx_sw_en().bit(value));
}
pub fn clear_rx_interrupts() {
let reg_block = PARL_IO::regs();
reg_block
.int_clr()
.write(|w| w.rx_fifo_wovf().clear_bit_by_one());
}
pub fn set_rx_bytes(len: u16) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block.rx_cfg0().modify(|_, w| {
w.rx_eof_gen_sel()
.bit(matches!(mode, EofMode::EnableSignal))
});
}
pub fn set_rx_pulse_submode_sel(sel: u8) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block.rx_cfg0().modify(|_, w| w.rx_start().bit(value));
}
pub fn set_rx_reg_update() {
let reg_block = PARL_IO::regs();
reg_block
.rx_cfg1()
.modify(|_, w| w.rx_reg_update().bit(true));
}
pub fn set_rx_bit_order(value: BitPackOrder) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 listen_tx_done() {
let reg_block = PARL_IO::regs();
reg_block.int_ena().modify(|_, w| w.tx_eof().set_bit());
}
pub fn unlisten_tx_done() {
let reg_block = PARL_IO::regs();
reg_block.int_ena().modify(|_, w| w.tx_eof().clear_bit());
}
pub fn is_tx_done_set() -> bool {
let reg_block = PARL_IO::regs();
reg_block.int_raw().read().tx_eof().bit()
}
pub fn clear_is_tx_done() {
let reg_block = PARL_IO::regs();
reg_block.int_clr().write(|w| w.tx_eof().clear_bit_by_one());
}
}
#[cfg(parl_io_version = "2")]
impl Instance {
pub fn set_tx_bit_width(width: WidSel) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block.st().read().tx_ready().bit_is_set()
}
pub fn set_tx_start(value: bool) {
let reg_block = PARL_IO::regs();
reg_block
.tx_start_cfg()
.modify(|_, w| w.tx_start().bit(value));
}
pub fn is_tx_eof() -> bool {
let reg_block = PARL_IO::regs();
reg_block.int_raw().read().tx_eof().bit_is_set()
}
pub fn tx_valid_pin_signal() -> OutputSignal {
cfg_if::cfg_if! {
if #[cfg(esp32c5)] {
OutputSignal::PARL_TX_CS
} else {
OutputSignal::PARL_TX_DATA7
}
}
}
pub fn set_tx_hw_valid_en(value: bool) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block
.rx_data_cfg()
.modify(|_, w| unsafe { w.rx_bus_wid_sel().bits(width as u8) });
}
pub fn rx_valid_pin_signal() -> InputSignal {
InputSignal::PARL_RX_DATA7
}
pub fn set_rx_sw_en(value: bool) {
let reg_block = PARL_IO::regs();
reg_block
.rx_mode_cfg()
.modify(|_, w| w.rx_sw_en().bit(value));
}
pub fn clear_rx_interrupts() {
let reg_block = PARL_IO::regs();
reg_block
.int_clr()
.write(|w| w.rx_fifo_wovf().clear_bit_by_one());
}
pub fn set_rx_bytes(len: u16) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block.rx_genrl_cfg().modify(|_, w| {
w.rx_eof_gen_sel()
.bit(matches!(mode, EofMode::EnableSignal))
});
}
pub fn set_rx_pulse_submode_sel(sel: u8) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 = PARL_IO::regs();
reg_block
.rx_start_cfg()
.modify(|_, w| w.rx_start().bit(value));
}
pub fn set_rx_reg_update() {
let reg_block = PARL_IO::regs();
reg_block
.reg_update()
.write(|w| w.rx_reg_update().bit(true));
}
pub fn set_rx_bit_order(value: BitPackOrder) {
let reg_block = PARL_IO::regs();
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 = PARL_IO::regs();
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 listen_tx_done() {
let reg_block = PARL_IO::regs();
reg_block.int_ena().modify(|_, w| w.tx_eof().set_bit());
}
pub fn unlisten_tx_done() {
let reg_block = PARL_IO::regs();
reg_block.int_ena().modify(|_, w| w.tx_eof().clear_bit());
}
pub fn is_tx_done_set() -> bool {
let reg_block = PARL_IO::regs();
reg_block.int_raw().read().tx_eof().bit()
}
pub fn clear_is_tx_done() {
let reg_block = PARL_IO::regs();
reg_block.int_clr().write(|w| w.tx_eof().clear_bit_by_one());
}
}
}
struct ParlIoTxGuard {
_guard: GenericPeripheralGuard<{ Peripheral::ParlIo as u8 }>,
}
impl ParlIoTxGuard {
pub fn new(_guard: GenericPeripheralGuard<{ Peripheral::ParlIo as u8 }>) -> Self {
ClockTree::with(|clocks| {
ParlIoInstance::ParlIo.configure_tx_clock(clocks, Default::default());
ParlIoInstance::ParlIo.request_tx_clock(clocks);
});
Self { _guard }
}
}
impl Drop for ParlIoTxGuard {
fn drop(&mut self) {
ClockTree::with(|clocks| ParlIoInstance::ParlIo.release_tx_clock(clocks));
}
}
struct ParlIoRxGuard {
_guard: GenericPeripheralGuard<{ Peripheral::ParlIo as u8 }>,
}
impl ParlIoRxGuard {
pub fn new(_guard: GenericPeripheralGuard<{ Peripheral::ParlIo as u8 }>) -> Self {
ClockTree::with(|clocks| {
ParlIoInstance::ParlIo.configure_rx_clock(clocks, Default::default());
ParlIoInstance::ParlIo.request_rx_clock(clocks);
});
Self { _guard }
}
}
impl Drop for ParlIoRxGuard {
fn drop(&mut self) {
ClockTree::with(|clocks| ParlIoInstance::ParlIo.release_rx_clock(clocks));
}
}