use esp_hal::gpio::NoPin;
use esp_hal::lcd_cam::LcdCam;
use esp_hal::lcd_cam::LcdDmaTxChannel;
#[cfg(feature = "invert-clock")]
use esp_hal::lcd_cam::lcd::ClockMode;
#[cfg(feature = "invert-clock")]
use esp_hal::lcd_cam::lcd::Phase;
#[cfg(feature = "invert-clock")]
use esp_hal::lcd_cam::lcd::Polarity;
use esp_hal::lcd_cam::lcd::i8080;
use esp_hal::lcd_cam::lcd::i8080::I8080;
use esp_hal::peripherals::LCD_CAM;
use crate::Hub75Backend;
use crate::Hub75Config;
use crate::Hub75DmaDescriptors;
use crate::Hub75Error;
use crate::Hub75Pins;
use crate::Hub75Pins8;
use crate::Hub75Pins16;
use crate::framebuffer::WordSize;
use crate::isr::BcmBuf;
#[cfg_attr(not(feature = "circular-dma"), allow(dead_code))]
pub(crate) fn clear_frame_interrupt() {
unsafe {
LCD_CAM::steal()
.register_block()
.lc_dma_int_clr()
.write(|w| w.lcd_trans_done_int_clr().set_bit());
}
}
impl<FB, P, CH> Hub75Backend<FB, P, CH> for LCD_CAM<'static>
where
FB: crate::framebuffer::FrameBuffer + 'static,
P: Hub75Pins<Word = FB::Word> + LcdCamPins<'static>,
CH: LcdDmaTxChannel<'static>,
{
fn construct<const N: usize>(
self,
hub75_pins: P,
channel: CH,
tx_descriptors: &'static mut Hub75DmaDescriptors<FB, N>,
config: Hub75Config,
) -> Result<(), Hub75Error> {
let word_size = hub75_pins.word_size();
let mut lcd_cam_dev = LcdCam::new(self);
lcd_cam_dev.set_interrupt_handler(crate::isr::handler_with_priority(
crate::isr::isr,
config.interrupt_priority,
));
unsafe {
LCD_CAM::steal()
.register_block()
.lc_dma_int_ena()
.modify(|_, w| w.lcd_trans_done_int_ena().set_bit());
}
let lcd_config = {
let c = i8080::Config::default().with_frequency(config.frequency);
#[cfg(feature = "invert-clock")]
let c = c.with_clock_mode(ClockMode {
polarity: Polarity::IdleLow,
phase: Phase::ShiftHigh,
});
c
};
let i8080 = I8080::new(lcd_cam_dev.lcd, channel, lcd_config).map_err(Hub75Error::I8080)?;
let i8080 = hub75_pins.apply(i8080);
let buf = BcmBuf::new(tx_descriptors.as_slice());
crate::isr::init_state(i8080, buf, word_size);
Ok(())
}
}
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 LcdCamPins<'d> {
fn apply<DM: esp_hal::DriverMode>(self, i8080: I8080<'d, DM>) -> I8080<'d, DM>;
}
impl<'d> LcdCamPins<'d> for Hub75Pins16<'d> {
fn apply<DM: esp_hal::DriverMode>(self, i8080: I8080<'d, DM>) -> I8080<'d, DM> {
let blank = self.blank.into_output_signal();
#[cfg(feature = "invert-blank")]
let blank = blank.with_output_inverter(true);
i8080
.with_wrx(self.clock)
.with_data0(self.addr0)
.with_data1(self.addr1)
.with_data2(self.addr2)
.with_data3(self.addr3)
.with_data4(self.addr4)
.with_data5(self.latch)
.with_data6(NoPin)
.with_data7(NoPin)
.with_data8(blank)
.with_data9(self.red1)
.with_data10(self.grn1)
.with_data11(self.blu1)
.with_data12(self.red2)
.with_data13(self.grn2)
.with_data14(self.blu2)
.with_data15(NoPin)
}
}
impl<'d> LcdCamPins<'d> for Hub75Pins8<'d> {
fn apply<DM: esp_hal::DriverMode>(self, i8080: I8080<'d, DM>) -> I8080<'d, DM> {
let blank = self.blank.into_output_signal();
#[cfg(feature = "invert-blank")]
let blank = blank.with_output_inverter(true);
let (_, clock) = unsafe { self.clock.split() };
#[cfg(feature = "invert-clock")]
let clock = clock.with_output_inverter(true);
i8080
.with_wrx(clock)
.with_data0(self.red1)
.with_data1(self.grn1)
.with_data2(self.blu1)
.with_data3(self.red2)
.with_data4(self.grn2)
.with_data5(self.blu2)
.with_data6(self.latch)
.with_data7(blank)
}
}