#![cfg_attr(docsrs, procmacros::doc_replace)]
use core::{
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
use crate::{
Blocking,
dma::{ChannelRx, DmaError, DmaPeripheral, DmaRxBuffer, PeripheralRxChannel, RxChannelFor},
gpio::{
InputConfig,
InputSignal,
OutputConfig,
OutputSignal,
interconnect::{PeripheralInput, PeripheralOutput},
},
lcd_cam::{BitOrder, ByteOrder, ClockError, calculate_clkm},
pac,
peripherals::LCD_CAM,
soc::clocks::ClockTree,
system::{self, GenericPeripheralGuard},
time::Rate,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EofMode {
ByteLen(u16),
VsyncSignal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum VsyncFilterThreshold {
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum VhdeMode {
VsyncHsync,
De,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigError {
Clock(ClockError),
LineInterrupt,
}
pub struct Cam<'d> {
pub(crate) lcd_cam: LCD_CAM<'d>,
pub(super) _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>,
}
pub struct Camera<'d> {
lcd_cam: LCD_CAM<'d>,
rx_channel: ChannelRx<Blocking, PeripheralRxChannel<LCD_CAM<'d>>>,
_guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>,
}
impl<'d> Camera<'d> {
pub fn new(
cam: Cam<'d>,
channel: impl RxChannelFor<LCD_CAM<'d>>,
config: Config,
) -> Result<Self, ConfigError> {
let rx_channel = ChannelRx::new(channel.degrade());
let mut this = Self {
lcd_cam: cam.lcd_cam,
rx_channel,
_guard: cam._guard,
};
this.apply_config(&config)?;
Ok(this)
}
fn regs(&self) -> &pac::lcd_cam::RegisterBlock {
self.lcd_cam.register_block()
}
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
let (i, divider) = ClockTree::with(|clocks| {
calculate_clkm(
config.frequency.as_hz() as _,
&[
crate::soc::clocks::xtal_clk_frequency(clocks) as usize,
crate::soc::clocks::pll_d2_frequency(clocks) as usize,
crate::soc::clocks::crypto_pwm_clk_frequency(clocks) as usize,
],
)
})
.map_err(ConfigError::Clock)?;
if let Some(value) = config.line_interrupt
&& value > 0b0111_1111
{
return Err(ConfigError::LineInterrupt);
}
self.regs().cam_ctrl().write(|w| {
unsafe {
w.cam_clk_sel().bits((i + 1) as _);
w.cam_clkm_div_num().bits(divider.div_num as _);
w.cam_clkm_div_b().bits(divider.div_b as _);
w.cam_clkm_div_a().bits(divider.div_a as _);
if let Some(threshold) = config.vsync_filter_threshold {
w.cam_vsync_filter_thres().bits(threshold as _);
}
w.cam_byte_order()
.bit(config.byte_order != ByteOrder::default());
w.cam_bit_order()
.bit(config.bit_order != BitOrder::default());
w.cam_vs_eof_en()
.bit(matches!(config.eof_mode, EofMode::VsyncSignal));
w.cam_line_int_en().bit(config.line_interrupt.is_some());
w.cam_stop_en().clear_bit()
}
});
self.regs().cam_ctrl1().write(|w| unsafe {
w.cam_2byte_en().bit(config.enable_2byte_mode);
w.cam_vh_de_mode_en()
.bit(matches!(config.vh_de_mode, VhdeMode::VsyncHsync));
if let EofMode::ByteLen(value) = config.eof_mode {
w.cam_rec_data_bytelen().bits(value);
}
if let Some(value) = config.line_interrupt {
w.cam_line_int_num().bits(value);
}
w.cam_vsync_filter_en()
.bit(config.vsync_filter_threshold.is_some());
w.cam_clk_inv().bit(config.invert_pixel_clock);
w.cam_de_inv().bit(config.invert_h_enable);
w.cam_hsync_inv().bit(config.invert_hsync);
w.cam_vsync_inv().bit(config.invert_vsync)
});
self.regs()
.cam_rgb_yuv()
.write(|w| w.cam_conv_bypass().clear_bit());
self.regs()
.cam_ctrl()
.modify(|_, w| w.cam_update().set_bit());
Ok(())
}
}
impl<'d> Camera<'d> {
pub fn with_master_clock(self, mclk: impl PeripheralOutput<'d>) -> Self {
let mclk = mclk.into();
mclk.apply_output_config(&OutputConfig::default());
mclk.set_output_enable(true);
OutputSignal::CAM_CLK.connect_to(&mclk);
self
}
pub fn with_pixel_clock(self, pclk: impl PeripheralInput<'d>) -> Self {
let pclk = pclk.into();
pclk.apply_input_config(&InputConfig::default());
pclk.set_input_enable(true);
InputSignal::CAM_PCLK.connect_to(&pclk);
self
}
pub fn with_vsync(self, pin: impl PeripheralInput<'d>) -> Self {
let pin = pin.into();
pin.apply_input_config(&InputConfig::default());
pin.set_input_enable(true);
InputSignal::CAM_V_SYNC.connect_to(&pin);
self
}
pub fn with_hsync(self, pin: impl PeripheralInput<'d>) -> Self {
let pin = pin.into();
pin.apply_input_config(&InputConfig::default());
pin.set_input_enable(true);
InputSignal::CAM_H_SYNC.connect_to(&pin);
self
}
pub fn with_h_enable(self, pin: impl PeripheralInput<'d>) -> Self {
let pin = pin.into();
pin.apply_input_config(&InputConfig::default());
pin.set_input_enable(true);
InputSignal::CAM_H_ENABLE.connect_to(&pin);
self
}
fn with_data_pin(self, signal: InputSignal, pin: impl PeripheralInput<'d>) -> Self {
let pin = pin.into();
pin.apply_input_config(&InputConfig::default());
pin.set_input_enable(true);
signal.connect_to(&pin);
self
}
pub fn with_data0(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_0, pin)
}
pub fn with_data1(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_1, pin)
}
pub fn with_data2(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_2, pin)
}
pub fn with_data3(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_3, pin)
}
pub fn with_data4(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_4, pin)
}
pub fn with_data5(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_5, pin)
}
pub fn with_data6(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_6, pin)
}
pub fn with_data7(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_7, pin)
}
pub fn with_data8(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_8, pin)
}
pub fn with_data9(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_9, pin)
}
pub fn with_data10(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_10, pin)
}
pub fn with_data11(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_11, pin)
}
pub fn with_data12(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_12, pin)
}
pub fn with_data13(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_13, pin)
}
pub fn with_data14(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_14, pin)
}
pub fn with_data15(self, pin: impl PeripheralInput<'d>) -> Self {
self.with_data_pin(InputSignal::CAM_DATA_15, pin)
}
pub fn receive<BUF: DmaRxBuffer>(
mut self,
mut buf: BUF,
) -> Result<CameraTransfer<'d, BUF>, (DmaError, Self, BUF)> {
self.regs()
.cam_ctrl1()
.modify(|_, w| w.cam_reset().set_bit());
self.regs()
.cam_ctrl1()
.modify(|_, w| w.cam_reset().clear_bit());
self.regs()
.cam_ctrl1()
.modify(|_, w| w.cam_afifo_reset().set_bit());
self.regs()
.cam_ctrl1()
.modify(|_, w| w.cam_afifo_reset().clear_bit());
let result = unsafe {
self.rx_channel
.prepare_transfer(DmaPeripheral::LcdCam, &mut buf)
.and_then(|_| self.rx_channel.start_transfer())
};
if let Err(e) = result {
return Err((e, self, buf));
}
self.regs().cam_ctrl().modify(|_, w| {
w.cam_stop_en().set_bit();
w.cam_update().set_bit()
});
self.regs()
.cam_ctrl1()
.modify(|_, w| w.cam_start().set_bit());
Ok(CameraTransfer {
camera: ManuallyDrop::new(self),
buffer_view: ManuallyDrop::new(buf.into_view()),
})
}
}
pub struct CameraTransfer<'d, BUF: DmaRxBuffer> {
camera: ManuallyDrop<Camera<'d>>,
buffer_view: ManuallyDrop<BUF::View>,
}
impl<'d, BUF: DmaRxBuffer> CameraTransfer<'d, BUF> {
pub fn is_done(&self) -> bool {
self.camera
.regs()
.cam_ctrl1()
.read()
.cam_start()
.bit_is_clear()
}
pub fn stop(mut self) -> (Camera<'d>, BUF::Final) {
self.stop_peripherals();
let (camera, view) = self.release();
(camera, BUF::from_view(view))
}
pub fn wait(mut self) -> (Result<(), DmaError>, Camera<'d>, BUF::Final) {
while !self.is_done() {}
self.camera.rx_channel.stop_transfer();
let (camera, view) = self.release();
let result = if camera.rx_channel.has_error() {
Err(DmaError::DescriptorError)
} else {
Ok(())
};
(result, camera, BUF::from_view(view))
}
fn release(mut self) -> (Camera<'d>, BUF::View) {
let result = unsafe {
let camera = ManuallyDrop::take(&mut self.camera);
let view = ManuallyDrop::take(&mut self.buffer_view);
(camera, view)
};
core::mem::forget(self);
result
}
fn stop_peripherals(&mut self) {
self.camera
.regs()
.cam_ctrl1()
.modify(|_, w| w.cam_start().clear_bit());
self.camera.rx_channel.stop_transfer();
}
}
impl<BUF: DmaRxBuffer> Deref for CameraTransfer<'_, BUF> {
type Target = BUF::View;
fn deref(&self) -> &Self::Target {
&self.buffer_view
}
}
impl<BUF: DmaRxBuffer> DerefMut for CameraTransfer<'_, BUF> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer_view
}
}
impl<BUF: DmaRxBuffer> Drop for CameraTransfer<'_, BUF> {
fn drop(&mut self) {
self.stop_peripherals();
unsafe {
ManuallyDrop::drop(&mut self.camera);
ManuallyDrop::drop(&mut self.buffer_view);
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Config {
frequency: Rate,
enable_2byte_mode: bool,
byte_order: ByteOrder,
bit_order: BitOrder,
vh_de_mode: VhdeMode,
vsync_filter_threshold: Option<VsyncFilterThreshold>,
eof_mode: EofMode,
line_interrupt: Option<u8>,
invert_vsync: bool,
invert_hsync: bool,
invert_h_enable: bool,
invert_pixel_clock: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
frequency: Rate::from_mhz(20),
enable_2byte_mode: false,
byte_order: Default::default(),
bit_order: Default::default(),
vh_de_mode: VhdeMode::De,
vsync_filter_threshold: None,
eof_mode: EofMode::VsyncSignal,
line_interrupt: None,
invert_vsync: false,
invert_hsync: false,
invert_h_enable: false,
invert_pixel_clock: false,
}
}
}