pub mod cam;
pub mod lcd;
use core::marker::PhantomData;
use crate::{
asynch::AtomicWaker,
handler,
interrupt::InterruptHandler,
lcd_cam::{cam::Cam, lcd::Lcd},
peripheral::Peripheral,
peripherals::{Interrupt, LCD_CAM},
system::{Cpu, GenericPeripheralGuard},
Async,
Blocking,
};
pub struct LcdCam<'d, Dm: crate::DriverMode> {
pub lcd: Lcd<'d, Dm>,
pub cam: Cam<'d>,
}
impl<'d> LcdCam<'d, Blocking> {
pub fn new(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self {
crate::into_ref!(lcd_cam);
let lcd_guard = GenericPeripheralGuard::new();
let cam_guard = GenericPeripheralGuard::new();
Self {
lcd: Lcd {
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
_mode: PhantomData,
_guard: lcd_guard,
},
cam: Cam {
lcd_cam,
_guard: cam_guard,
},
}
}
pub fn into_async(mut self) -> LcdCam<'d, Async> {
self.set_interrupt_handler(interrupt_handler);
LcdCam {
lcd: Lcd {
lcd_cam: self.lcd.lcd_cam,
_mode: PhantomData,
_guard: self.lcd._guard,
},
cam: self.cam,
}
}
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
for core in crate::system::Cpu::other() {
crate::interrupt::disable(core, Interrupt::LCD_CAM);
}
unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) };
unwrap!(crate::interrupt::enable(
Interrupt::LCD_CAM,
handler.priority()
));
}
}
impl crate::private::Sealed for LcdCam<'_, Blocking> {}
#[instability::unstable]
impl crate::interrupt::InterruptConfigurable for LcdCam<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.set_interrupt_handler(handler);
}
}
impl<'d> LcdCam<'d, Async> {
pub fn into_blocking(self) -> LcdCam<'d, Blocking> {
crate::interrupt::disable(Cpu::current(), Interrupt::LCD_CAM);
LcdCam {
lcd: Lcd {
lcd_cam: self.lcd.lcd_cam,
_mode: PhantomData,
_guard: self.lcd._guard,
},
cam: self.cam,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BitOrder {
#[default]
Native = 0,
Inverted = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ByteOrder {
#[default]
Native = 0,
Inverted = 1,
}
pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new();
#[handler]
fn interrupt_handler() {
if Instance::is_lcd_done_set() {
Instance::unlisten_lcd_done();
LCD_DONE_WAKER.wake()
}
}
pub(crate) struct Instance;
impl Instance {
fn enable_listenlcd_done(en: bool) {
LCD_CAM::regs()
.lc_dma_int_ena()
.modify(|_, w| w.lcd_trans_done_int_ena().bit(en));
}
pub(crate) fn listen_lcd_done() {
Self::enable_listenlcd_done(true);
}
pub(crate) fn unlisten_lcd_done() {
Self::enable_listenlcd_done(false);
}
pub(crate) fn is_lcd_done_set() -> bool {
LCD_CAM::regs()
.lc_dma_int_raw()
.read()
.lcd_trans_done_int_raw()
.bit()
}
}
pub(crate) struct ClockDivider {
pub div_num: usize,
pub div_b: usize,
pub div_a: usize,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ClockError {
FrequencyTooLow,
}
pub(crate) fn calculate_clkm(
desired_frequency: usize,
source_frequencies: &[usize],
) -> Result<(usize, ClockDivider), ClockError> {
let mut result_freq = 0;
let mut result = None;
for (i, &source_frequency) in source_frequencies.iter().enumerate() {
let div = calculate_closest_divider(source_frequency, desired_frequency);
if let Some(div) = div {
let freq = calculate_output_frequency(source_frequency, &div);
if result.is_none() || freq > result_freq {
result = Some((i, div));
result_freq = freq;
}
}
}
result.ok_or(ClockError::FrequencyTooLow)
}
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
let n = match divider.div_num {
0 => 256,
1 => 2,
_ => divider.div_num.min(256),
};
if divider.div_b != 0 && divider.div_a != 0 {
let source = source_frequency as u64;
let n = n as u64;
let a = divider.div_b as u64;
let b = divider.div_a as u64;
((source * a) / (n * a + b)) as _
} else {
source_frequency / n
}
}
fn calculate_closest_divider(
source_frequency: usize,
desired_frequency: usize,
) -> Option<ClockDivider> {
let div_num = source_frequency / desired_frequency;
if div_num < 2 {
return Some(ClockDivider {
div_num: 1,
div_b: 0,
div_a: 0,
});
}
if div_num > 256 {
return None;
}
let div_num = if div_num == 256 { 0 } else { div_num };
let div_fraction = {
let div_remainder = source_frequency % desired_frequency;
let gcd = hcf(div_remainder, desired_frequency);
Fraction {
numerator: div_remainder / gcd,
denominator: desired_frequency / gcd,
}
};
let divider = if div_fraction.numerator == 0 {
ClockDivider {
div_num,
div_b: 0,
div_a: 0,
}
} else {
let target = div_fraction;
let closest = farey_sequence(63).find(|curr| {
let new_curr_num = curr.numerator * target.denominator;
let new_target_num = target.numerator * curr.denominator;
new_curr_num >= new_target_num
});
let closest = unwrap!(closest, "The fraction must be between 0 and 1");
ClockDivider {
div_num,
div_b: closest.numerator,
div_a: closest.denominator,
}
};
Some(divider)
}
const fn hcf(a: usize, b: usize) -> usize {
if b != 0 {
hcf(b, a % b)
} else {
a
}
}
struct Fraction {
pub numerator: usize,
pub denominator: usize,
}
fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
let mut a = 0;
let mut b = 1;
let mut c = 1;
let mut d = denominator;
core::iter::from_fn(move || {
if a > denominator {
return None;
}
let next = Fraction {
numerator: a,
denominator: b,
};
let k = (denominator + b) / d;
(a, b, c, d) = (c, d, k * c - a, k * d - b);
Some(next)
})
}