use esp_hal::parl_io::BitPackOrder;
use esp_hal::parl_io::ClkOutPin;
use esp_hal::parl_io::ConfigurePins;
use esp_hal::parl_io::ParlIo;
use esp_hal::parl_io::ParlIoDmaChannel;
use esp_hal::parl_io::ParlIoInterrupt;
use esp_hal::parl_io::SampleEdge;
use esp_hal::parl_io::TxConfig;
use esp_hal::parl_io::TxPins;
use esp_hal::peripherals::PARL_IO;
use crate::Hub75Backend;
use crate::Hub75Config;
use crate::Hub75DmaDescriptors;
use crate::Hub75Error;
use crate::Hub75Pins;
use crate::Hub75Pins8;
#[cfg(not(esp32c5))]
use crate::Hub75Pins16;
use crate::framebuffer::WordSize;
use crate::isr::BcmBuf;
#[cfg(esp32c5)]
fn select_dma_eof_source() {
unsafe {
PARL_IO::steal()
.register_block()
.tx_genrl_cfg()
.modify(|_, w| w.tx_eof_gen_sel().set_bit());
}
}
#[cfg_attr(not(feature = "circular-dma"), allow(dead_code))]
pub(crate) fn clear_frame_interrupt() {
unsafe {
PARL_IO::steal()
.register_block()
.int_clr()
.write(|w| w.tx_eof().clear_bit_by_one());
}
}
impl<FB, P, CH> Hub75Backend<FB, P, CH> for PARL_IO<'static>
where
FB: crate::framebuffer::FrameBuffer + 'static,
P: Hub75Pins<Word = FB::Word> + ParlIoPins<'static>,
CH: ParlIoDmaChannel<'static>,
{
fn construct<const N: usize>(
self,
hub75_pins: P,
channel: CH,
tx_descriptors: &'static mut Hub75DmaDescriptors<FB, N>,
config: Hub75Config,
) -> Result<(), Hub75Error> {
let (pins, clock_pin) = hub75_pins.convert_pins();
let mut parl_io_dev = ParlIo::new(self, channel)?;
parl_io_dev.set_interrupt_handler(crate::isr::handler_with_priority(
crate::isr::isr,
config.interrupt_priority,
));
parl_io_dev.listen(ParlIoInterrupt::TxEof);
#[cfg(feature = "invert-clock")]
let sample_edge = SampleEdge::Normal;
#[cfg(not(feature = "invert-clock"))]
let sample_edge = SampleEdge::Invert;
#[cfg(feature = "invert-blank")]
let idle_value = 0x0000;
#[cfg(not(feature = "invert-blank"))]
let idle_value = 0x0100;
let tx_config = TxConfig::default()
.with_frequency(config.frequency)
.with_idle_value(idle_value)
.with_sample_edge(sample_edge)
.with_bit_order(BitPackOrder::Msb);
let clk_pin = ClkOutPin::new(clock_pin);
let parl_io_tx = parl_io_dev.tx.with_config(pins, clk_pin, tx_config)?;
#[cfg(esp32c5)]
select_dma_eof_source();
let buf = BcmBuf::new(tx_descriptors.as_slice());
crate::isr::init_state(parl_io_tx, buf);
Ok(())
}
}
use esp_hal::gpio::AnyPin;
#[cfg(not(esp32c5))]
use esp_hal::gpio::NoPin;
use esp_hal::parl_io::TxEightBits;
#[cfg(not(esp32c5))]
use esp_hal::parl_io::TxSixteenBits;
#[cfg(not(esp32c5))]
impl crate::Hub75Pins for Hub75Pins16<'_> {
type Word = u16;
fn word_size(&self) -> WordSize {
WordSize::Sixteen
}
}
impl crate::Hub75Pins for Hub75Pins8<'_> {
type Word = u8;
fn word_size(&self) -> WordSize {
WordSize::Eight
}
}
#[doc(hidden)]
pub trait ParlIoPins<'d> {
type Pins: TxPins + ConfigurePins + 'd;
fn convert_pins(self) -> (Self::Pins, AnyPin<'d>);
}
#[cfg(not(esp32c5))]
impl<'d> ParlIoPins<'d> for Hub75Pins16<'d> {
type Pins = TxSixteenBits<'d>;
fn convert_pins(self) -> (TxSixteenBits<'d>, AnyPin<'d>) {
let blank = self.blank.into_output_signal();
#[cfg(feature = "invert-blank")]
let blank = blank.with_output_inverter(true);
let pins = TxSixteenBits::new(
self.addr0, self.addr1, self.addr2, self.addr3, self.addr4, self.latch, NoPin, NoPin,
blank, self.red1, self.grn1, self.blu1, self.red2, self.grn2, self.blu2, NoPin,
);
(pins, self.clock)
}
}
impl<'d> ParlIoPins<'d> for Hub75Pins8<'d> {
type Pins = TxEightBits<'d>;
fn convert_pins(self) -> (TxEightBits<'d>, AnyPin<'d>) {
let blank = self.blank.into_output_signal();
#[cfg(feature = "invert-blank")]
let blank = blank.with_output_inverter(true);
let pins = TxEightBits::new(
self.red1, self.grn1, self.blu1, self.red2, self.grn2, self.blu2, self.latch, blank,
);
(pins, self.clock)
}
}