1pub mod cam;
9pub mod lcd;
10
11use core::marker::PhantomData;
12
13use crate::{
14 Async,
15 Blocking,
16 asynch::AtomicWaker,
17 handler,
18 interrupt::InterruptHandler,
19 lcd_cam::{cam::Cam, lcd::Lcd},
20 peripherals::{Interrupt, LCD_CAM},
21 system::{Cpu, GenericPeripheralGuard},
22};
23
24pub struct LcdCam<'d, Dm: crate::DriverMode> {
26 pub lcd: Lcd<'d, Dm>,
28 pub cam: Cam<'d>,
30}
31
32impl<'d> LcdCam<'d, Blocking> {
33 pub fn new(lcd_cam: LCD_CAM<'d>) -> Self {
35 let lcd_guard = GenericPeripheralGuard::new();
36 let cam_guard = GenericPeripheralGuard::new();
37
38 Self {
39 lcd: Lcd {
40 lcd_cam: unsafe { lcd_cam.clone_unchecked() },
41 _mode: PhantomData,
42 _guard: lcd_guard,
43 },
44 cam: Cam {
45 lcd_cam,
46 _guard: cam_guard,
47 },
48 }
49 }
50
51 pub fn into_async(mut self) -> LcdCam<'d, Async> {
53 self.set_interrupt_handler(interrupt_handler);
54 LcdCam {
55 lcd: Lcd {
56 lcd_cam: self.lcd.lcd_cam,
57 _mode: PhantomData,
58 _guard: self.lcd._guard,
59 },
60 cam: self.cam,
61 }
62 }
63
64 #[instability::unstable]
69 pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
70 for core in crate::system::Cpu::other() {
71 crate::interrupt::disable(core, Interrupt::LCD_CAM);
72 }
73 unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) };
74 unwrap!(crate::interrupt::enable(
75 Interrupt::LCD_CAM,
76 handler.priority()
77 ));
78 }
79}
80
81impl crate::private::Sealed for LcdCam<'_, Blocking> {}
82#[instability::unstable]
85impl crate::interrupt::InterruptConfigurable for LcdCam<'_, Blocking> {
86 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
87 self.set_interrupt_handler(handler);
88 }
89}
90
91impl<'d> LcdCam<'d, Async> {
92 pub fn into_blocking(self) -> LcdCam<'d, Blocking> {
94 crate::interrupt::disable(Cpu::current(), Interrupt::LCD_CAM);
95 LcdCam {
96 lcd: Lcd {
97 lcd_cam: self.lcd.lcd_cam,
98 _mode: PhantomData,
99 _guard: self.lcd._guard,
100 },
101 cam: self.cam,
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Default)]
108#[cfg_attr(feature = "defmt", derive(defmt::Format))]
109pub enum BitOrder {
110 #[default]
112 Native = 0,
113 Inverted = 1,
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Default)]
119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120pub enum ByteOrder {
121 #[default]
123 Native = 0,
124 Inverted = 1,
126}
127
128pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new();
129
130#[handler]
131fn interrupt_handler() {
132 if Instance::is_lcd_done_set() {
134 Instance::unlisten_lcd_done();
135 LCD_DONE_WAKER.wake()
136 }
137}
138
139pub(crate) struct Instance;
140
141impl Instance {
145 fn enable_listenlcd_done(en: bool) {
146 LCD_CAM::regs()
147 .lc_dma_int_ena()
148 .modify(|_, w| w.lcd_trans_done_int_ena().bit(en));
149 }
150
151 pub(crate) fn listen_lcd_done() {
152 Self::enable_listenlcd_done(true);
153 }
154
155 pub(crate) fn unlisten_lcd_done() {
156 Self::enable_listenlcd_done(false);
157 }
158
159 pub(crate) fn is_lcd_done_set() -> bool {
160 LCD_CAM::regs()
161 .lc_dma_int_raw()
162 .read()
163 .lcd_trans_done_int_raw()
164 .bit()
165 }
166}
167pub(crate) struct ClockDivider {
168 pub div_num: usize,
173
174 pub div_b: usize,
176
177 pub div_a: usize,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq)]
183#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184pub enum ClockError {
185 FrequencyTooLow,
187}
188
189pub(crate) fn calculate_clkm(
190 desired_frequency: usize,
191 source_frequencies: &[usize],
192) -> Result<(usize, ClockDivider), ClockError> {
193 let mut result_freq = 0;
194 let mut result = None;
195
196 for (i, &source_frequency) in source_frequencies.iter().enumerate() {
197 let div = calculate_closest_divider(source_frequency, desired_frequency);
198 if let Some(div) = div {
199 let freq = calculate_output_frequency(source_frequency, &div);
200 if result.is_none() || freq > result_freq {
201 result = Some((i, div));
202 result_freq = freq;
203 }
204 }
205 }
206
207 result.ok_or(ClockError::FrequencyTooLow)
208}
209
210fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
211 let n = match divider.div_num {
212 0 => 256,
213 1 => 2,
214 _ => divider.div_num.min(256),
215 };
216
217 if divider.div_b != 0 && divider.div_a != 0 {
218 let source = source_frequency as u64;
225 let n = n as u64;
226 let a = divider.div_b as u64;
227 let b = divider.div_a as u64;
228
229 ((source * a) / (n * a + b)) as _
230 } else {
231 source_frequency / n
232 }
233}
234
235fn calculate_closest_divider(
236 source_frequency: usize,
237 desired_frequency: usize,
238) -> Option<ClockDivider> {
239 let div_num = source_frequency / desired_frequency;
240 if div_num < 2 {
241 return Some(ClockDivider {
244 div_num: 1,
245 div_b: 0,
246 div_a: 0,
247 });
248 }
249 if div_num > 256 {
250 return None;
252 }
253
254 let div_num = if div_num == 256 { 0 } else { div_num };
255
256 let div_fraction = {
257 let div_remainder = source_frequency % desired_frequency;
258 let gcd = hcf(div_remainder, desired_frequency);
259 Fraction {
260 numerator: div_remainder / gcd,
261 denominator: desired_frequency / gcd,
262 }
263 };
264
265 let divider = if div_fraction.numerator == 0 {
266 ClockDivider {
267 div_num,
268 div_b: 0,
269 div_a: 0,
270 }
271 } else {
272 let target = div_fraction;
273 let closest = farey_sequence(63).find(|curr| {
274 let new_curr_num = curr.numerator * target.denominator;
277 let new_target_num = target.numerator * curr.denominator;
278 new_curr_num >= new_target_num
279 });
280
281 let closest = unwrap!(closest, "The fraction must be between 0 and 1");
282
283 ClockDivider {
284 div_num,
285 div_b: closest.numerator,
286 div_a: closest.denominator,
287 }
288 };
289 Some(divider)
290}
291
292const fn hcf(a: usize, b: usize) -> usize {
294 if b != 0 { hcf(b, a % b) } else { a }
295}
296
297struct Fraction {
298 pub numerator: usize,
299 pub denominator: usize,
300}
301
302fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
304 let mut a = 0;
305 let mut b = 1;
306 let mut c = 1;
307 let mut d = denominator;
308 core::iter::from_fn(move || {
309 if a > denominator {
310 return None;
311 }
312 let next = Fraction {
313 numerator: a,
314 denominator: b,
315 };
316 let k = (denominator + b) / d;
317 (a, b, c, d) = (c, d, k * c - a, k * d - b);
318 Some(next)
319 })
320}