1use core::{
2 marker::PhantomData,
3 pin::Pin,
4 task::{Context, Poll},
5};
6
7use Interrupt::LP_ADC as InterruptSource;
9use portable_atomic::{AtomicU32, Ordering};
11use procmacros::handler;
12
13pub use self::calibration::*;
14use super::{AdcCalScheme, AdcCalSource, AdcChannel, AdcConfig, AdcPin, Attenuation};
15use crate::{
16 Async,
17 Blocking,
18 asynch::AtomicWaker,
19 efuse::AdcCalibUnit,
20 interrupt::{InterruptConfigurable, InterruptHandler},
21 peripherals::{Interrupt, LP_ADC, LP_PERI},
22 rtc_cntl::WakeLock,
23 soc::regi2c,
24 system::{GenericPeripheralGuard, Peripheral},
25};
26
27mod calibration;
28
29pub(super) const NUM_ATTENS: usize = 8;
32
33const ADC_VAL_MASK: u16 = 0xfff;
34const ADC_CAL_CNT_MAX: u16 = 32;
35const ADC_CAL_CHANNEL: u16 = 15;
36
37const FORCE_XPD_SAR_PU: u8 = 3;
39
40impl<ADCX> AdcConfig<ADCX>
41where
42 ADCX: RegisterAccess,
43{
44 pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
46 where
47 ADCX: super::CalibrationAccess,
48 {
49 let mut adc_max: u16 = 0;
50 let mut adc_min: u16 = u16::MAX;
51 let mut adc_sum: u32 = 0;
52
53 ADCX::enable_vdef(true);
54
55 ADCX::set_en_pad(ADCX::ADC_CAL_CHANNEL as u8);
57 ADCX::set_attenuation(ADCX::ADC_CAL_CHANNEL as usize, atten as u8);
58
59 ADCX::connect_cal(source, true);
61
62 ADCX::calibration_init();
63 ADCX::set_init_code(0);
64
65 for _ in 0..ADCX::ADC_CAL_CNT_MAX {
66 ADCX::start_sample();
68
69 while !ADCX::is_done() {}
71
72 let adc = ADCX::read_data() & ADCX::ADC_VAL_MASK;
73
74 ADCX::reset();
75
76 adc_sum += adc as u32;
77 adc_max = adc.max(adc_max);
78 adc_min = adc.min(adc_min);
79 }
80
81 let cal_val =
82 (adc_sum - adc_max as u32 - adc_min as u32) as u16 / (ADCX::ADC_CAL_CNT_MAX - 2);
83
84 ADCX::connect_cal(source, false);
86
87 cal_val
88 }
89}
90
91#[doc(hidden)]
92pub trait RegisterAccess {
93 fn set_attenuation(channel: usize, attenuation: u8);
94
95 fn set_rtc_controller();
97
98 fn set_en_pad(channel: u8);
99
100 fn clear_start_sample();
101
102 fn start_sample();
103
104 fn is_done() -> bool;
106
107 fn read_data() -> u16;
109
110 fn power_up();
112
113 fn calibration_init();
115
116 fn set_init_code(data: u16);
118
119 fn reset();
121}
122
123#[cfg(adc_adc1)]
124impl RegisterAccess for crate::peripherals::ADC1<'_> {
125 fn set_attenuation(channel: usize, attenuation: u8) {
126 LP_ADC::regs().atten1().modify(|r, w| {
127 let new_value = (r.bits() & !(0b11 << (channel * 2)))
128 | (((attenuation & 0b11) as u32) << (channel * 2));
129
130 unsafe { w.sar1_atten().bits(new_value) }
131 });
132 }
133
134 fn set_rtc_controller() {
135 LP_ADC::regs()
136 .meas1_mux()
137 .modify(|_, w| w.sar1_dig_force().clear_bit());
138 LP_ADC::regs().meas1_ctrl2().modify(|_, w| {
139 w.meas1_start_force().set_bit();
140 w.sar1_en_pad_force().set_bit()
141 });
142 }
143
144 fn set_en_pad(channel: u8) {
145 LP_ADC::regs()
146 .meas1_ctrl2()
147 .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
148 }
149
150 fn clear_start_sample() {
151 LP_ADC::regs()
152 .meas1_ctrl2()
153 .modify(|_, w| w.meas1_start_sar().clear_bit());
154 }
155
156 fn start_sample() {
157 LP_ADC::regs()
158 .meas1_ctrl2()
159 .modify(|_, w| w.meas1_start_sar().set_bit());
160 }
161
162 fn is_done() -> bool {
163 LP_ADC::regs()
164 .meas1_ctrl2()
165 .read()
166 .meas1_done_sar()
167 .bit_is_set()
168 }
169
170 fn read_data() -> u16 {
171 LP_ADC::regs().meas1_ctrl2().read().meas1_data_sar().bits()
172 }
173
174 fn power_up() {
175 LP_ADC::regs()
176 .force_wpd_sar()
177 .modify(|_, w| unsafe { w.force_xpd_sar1().bits(FORCE_XPD_SAR_PU) });
178 }
179
180 fn calibration_init() {
181 regi2c::ADC_SAR1_DREF.write_field(4);
183 }
184
185 fn set_init_code(data: u16) {
186 let [msb, lsb] = data.to_be_bytes();
187
188 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
189 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
190 }
191
192 fn reset() {
193 LP_ADC::regs()
196 .int_clr()
197 .write(|w| w.cocpu_saradc1_int_clr().set_bit());
198
199 LP_ADC::regs()
200 .meas1_ctrl2()
201 .modify(|_, w| w.meas1_start_sar().clear_bit());
202 }
203}
204
205#[cfg(adc_adc1)]
206impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
207 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
208 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
209 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
210
211 fn enable_vdef(enable: bool) {
212 regi2c::ADC_SAR1_DREF.write_field(enable as u8);
213 }
214
215 fn connect_cal(source: AdcCalSource, enable: bool) {
216 match source {
217 AdcCalSource::Gnd => regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as u8),
218 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_REF.write_field(enable as u8),
219 }
220 }
221}
222
223#[cfg(adc_adc2)]
229const ADC2_PAD_OFFSET: u8 = 2;
230
231#[cfg(adc_adc2)]
232impl RegisterAccess for crate::peripherals::ADC2<'_> {
233 fn set_attenuation(channel: usize, attenuation: u8) {
234 let pad = channel + ADC2_PAD_OFFSET as usize;
235 LP_ADC::regs().atten2().modify(|r, w| {
236 let new_value =
237 (r.bits() & !(0b11 << (pad * 2))) | (((attenuation & 0b11) as u32) << (pad * 2));
238
239 unsafe { w.sar2_atten().bits(new_value) }
240 });
241 }
242
243 fn set_rtc_controller() {
244 LP_ADC::regs()
245 .meas2_mux()
246 .modify(|_, w| w.sar2_rtc_force().set_bit());
247 LP_ADC::regs().meas2_ctrl2().modify(|_, w| {
248 w.meas2_start_force().set_bit();
249 w.sar2_en_pad_force().set_bit()
250 });
251 }
252
253 fn set_en_pad(channel: u8) {
254 LP_ADC::regs()
255 .meas2_ctrl2()
256 .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << (channel + ADC2_PAD_OFFSET)) });
257 }
258
259 fn clear_start_sample() {
260 LP_ADC::regs()
261 .meas2_ctrl2()
262 .modify(|_, w| w.meas2_start_sar().clear_bit());
263 }
264
265 fn start_sample() {
266 LP_ADC::regs()
267 .meas2_ctrl2()
268 .modify(|_, w| w.meas2_start_sar().set_bit());
269 }
270
271 fn is_done() -> bool {
272 LP_ADC::regs()
273 .meas2_ctrl2()
274 .read()
275 .meas2_done_sar()
276 .bit_is_set()
277 }
278
279 fn read_data() -> u16 {
280 LP_ADC::regs().meas2_ctrl2().read().meas2_data_sar().bits()
281 }
282
283 fn power_up() {
284 LP_ADC::regs()
285 .force_wpd_sar()
286 .modify(|_, w| unsafe { w.force_xpd_sar2().bits(FORCE_XPD_SAR_PU) });
287 }
288
289 fn calibration_init() {
290 regi2c::ADC_SAR2_DREF.write_field(4);
291 }
292
293 fn set_init_code(data: u16) {
294 let [msb, lsb] = data.to_be_bytes();
295
296 regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb);
297 regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb);
298 }
299
300 fn reset() {
301 LP_ADC::regs()
304 .int_clr()
305 .write(|w| w.cocpu_saradc2_int_clr().set_bit());
306
307 LP_ADC::regs()
308 .meas2_ctrl2()
309 .modify(|_, w| w.meas2_start_sar().clear_bit());
310 }
311}
312
313#[cfg(adc_adc2)]
314impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
315 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
316 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
317 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
318
319 fn enable_vdef(enable: bool) {
320 regi2c::ADC_SAR2_DREF.write_field(enable as u8);
321 }
322
323 fn connect_cal(source: AdcCalSource, enable: bool) {
324 match source {
325 AdcCalSource::Gnd => regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as u8),
326 AdcCalSource::Ref => regi2c::ADC_SAR2_ENCAL_REF.write_field(enable as u8),
327 }
328 }
329}
330
331#[cfg(adc_adc1)]
332impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
333 fn init_code(atten: Attenuation) -> Option<u16> {
334 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
335 }
336
337 fn cal_mv(atten: Attenuation) -> u16 {
338 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
339 }
340
341 fn cal_code(atten: Attenuation) -> Option<u16> {
342 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
343 }
344}
345
346#[cfg(adc_adc2)]
347impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
348 fn init_code(atten: Attenuation) -> Option<u16> {
349 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC2, atten)
350 }
351
352 fn cal_mv(atten: Attenuation) -> u16 {
353 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC2, atten)
354 }
355
356 fn cal_code(atten: Attenuation) -> Option<u16> {
357 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC2, atten)
358 }
359}
360
361pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
363 _adc: ADC,
364 active_channel: Option<u8>,
365 last_init_code: u16,
366 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
367 _phantom: PhantomData<(Dm, &'d mut ())>,
368}
369
370impl<ADCX, Dm> Adc<'_, ADCX, Dm>
371where
372 ADCX: RegisterAccess,
373 Dm: crate::DriverMode,
374{
375 fn start_sample<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>)
376 where
377 PIN: AdcChannel,
378 CS: AdcCalScheme<ADCX>,
379 {
380 let init_code = pin.cal_scheme.adc_cal();
382 if self.last_init_code != init_code {
383 ADCX::calibration_init();
384 ADCX::set_init_code(init_code);
385 self.last_init_code = init_code;
386 }
387
388 ADCX::set_en_pad(pin.pin.adc_channel());
389
390 ADCX::clear_start_sample();
391 ADCX::start_sample();
392 }
393}
394
395impl<'d, ADCX> Adc<'d, ADCX, Blocking>
396where
397 ADCX: RegisterAccess + 'd,
398{
399 pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Self {
402 let guard = GenericPeripheralGuard::new();
403
404 LP_PERI::regs()
406 .clk_en()
407 .modify(|_, w| w.ck_en_lp_adc().set_bit());
408
409 for (channel, attenuation) in config.attenuations.iter().enumerate() {
410 if let Some(attenuation) = attenuation {
411 ADCX::set_attenuation(channel, *attenuation as u8);
412 }
413 }
414
415 ADCX::set_rtc_controller();
416 ADCX::power_up();
417
418 Adc {
419 _adc: adc_instance,
420 active_channel: None,
421 last_init_code: 0,
422 _guard: guard,
423 _phantom: PhantomData,
424 }
425 }
426
427 pub fn read_blocking<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> u16
430 where
431 PIN: AdcChannel,
432 CS: AdcCalScheme<ADCX>,
433 {
434 self.start_sample(pin);
435
436 while !ADCX::is_done() {}
438
439 let converted_value = ADCX::read_data();
441 ADCX::reset();
442
443 pin.cal_scheme.adc_val(converted_value)
445 }
446
447 pub fn read_oneshot<PIN, CS>(
453 &mut self,
454 pin: &mut super::AdcPin<PIN, ADCX, CS>,
455 ) -> nb::Result<u16, ()>
456 where
457 PIN: super::AdcChannel,
458 CS: super::AdcCalScheme<ADCX>,
459 {
460 if let Some(active_channel) = self.active_channel {
461 if active_channel != pin.pin.adc_channel() {
465 return Err(nb::Error::WouldBlock);
466 }
467 } else {
468 self.active_channel = Some(pin.pin.adc_channel());
470
471 self.start_sample(pin);
472 }
473
474 let conversion_finished = ADCX::is_done();
476 if !conversion_finished {
477 return Err(nb::Error::WouldBlock);
478 }
479
480 let converted_value = ADCX::read_data();
482 ADCX::reset();
483
484 let converted_value = pin.cal_scheme.adc_val(converted_value);
486
487 self.active_channel = None;
489
490 Ok(converted_value)
491 }
492
493 pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
495 acquire_async_adc();
496 self.set_interrupt_handler(adc_interrupt_handler);
497
498 ADCX::reset();
500
501 Adc {
502 _adc: self._adc,
503 active_channel: self.active_channel,
504 last_init_code: self.last_init_code,
505 _guard: self._guard,
506 _phantom: PhantomData,
507 }
508 }
509}
510
511impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
512
513impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
514 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
515 for core in crate::system::Cpu::other() {
516 crate::interrupt::disable(core, InterruptSource);
517 }
518 crate::interrupt::bind_handler(InterruptSource, handler);
519 }
520}
521
522impl<'d, ADCX> Adc<'d, ADCX, Async>
523where
524 ADCX: RegisterAccess + 'd,
525{
526 pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
528 if release_async_adc() {
529 for cpu in crate::system::Cpu::all() {
531 crate::interrupt::disable(cpu, InterruptSource);
532 }
533 }
534 Adc {
535 _adc: self._adc,
536 active_channel: self.active_channel,
537 last_init_code: self.last_init_code,
538 _guard: self._guard,
539 _phantom: PhantomData,
540 }
541 }
542
543 pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCX, CS>) -> u16
549 where
550 ADCX: Instance,
551 PIN: super::AdcChannel,
552 CS: super::AdcCalScheme<ADCX>,
553 {
554 self.start_sample(pin);
555
556 AdcFuture::<ADCX>::new(self).await;
557
558 let converted_value = ADCX::read_data();
559 ADCX::reset();
560
561 pin.cal_scheme.adc_val(converted_value)
563 }
564}
565
566static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
567
568fn acquire_async_adc() {
569 ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
570}
571
572fn release_async_adc() -> bool {
573 ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
574}
575
576#[handler]
577pub(crate) fn adc_interrupt_handler() {
578 let interrupt_status = LP_ADC::regs().int_st().read();
579
580 #[cfg(adc_adc1)]
581 if interrupt_status.cocpu_saradc1_int_st().bit_is_set() {
582 unsafe { handle_async(crate::peripherals::ADC1::steal()) }
583 }
584
585 #[cfg(adc_adc2)]
586 if interrupt_status.cocpu_saradc2_int_st().bit_is_set() {
587 unsafe { handle_async(crate::peripherals::ADC2::steal()) }
588 }
589}
590
591fn handle_async<ADCX: Instance>(_instance: ADCX) {
592 ADCX::waker().wake();
593 ADCX::unlisten();
594}
595
596pub trait Instance: crate::private::Sealed {
598 fn listen();
600
601 fn unlisten();
603
604 fn clear_interrupt();
606
607 fn waker() -> &'static AtomicWaker;
609}
610
611#[cfg(adc_adc1)]
612impl Instance for crate::peripherals::ADC1<'_> {
613 fn listen() {
614 LP_ADC::regs()
615 .int_ena_w1ts()
616 .write(|w| w.cocpu_saradc1_int_ena_w1ts().set_bit());
617 }
618
619 fn unlisten() {
620 LP_ADC::regs()
621 .int_ena_w1tc()
622 .write(|w| w.cocpu_saradc1_int_ena_w1tc().set_bit());
623 }
624
625 fn clear_interrupt() {
626 LP_ADC::regs()
627 .int_clr()
628 .write(|w| w.cocpu_saradc1_int_clr().set_bit());
629 }
630
631 fn waker() -> &'static AtomicWaker {
632 static WAKER: AtomicWaker = AtomicWaker::new();
633
634 &WAKER
635 }
636}
637
638#[cfg(adc_adc2)]
639impl Instance for crate::peripherals::ADC2<'_> {
640 fn listen() {
641 LP_ADC::regs()
642 .int_ena_w1ts()
643 .write(|w| w.cocpu_saradc2_int_ena_w1ts().set_bit());
644 }
645
646 fn unlisten() {
647 LP_ADC::regs()
648 .int_ena_w1tc()
649 .write(|w| w.cocpu_saradc2_int_ena_w1tc().set_bit());
650 }
651
652 fn clear_interrupt() {
653 LP_ADC::regs()
654 .int_clr()
655 .write(|w| w.cocpu_saradc2_int_clr().set_bit());
656 }
657
658 fn waker() -> &'static AtomicWaker {
659 static WAKER: AtomicWaker = AtomicWaker::new();
660
661 &WAKER
662 }
663}
664
665#[must_use = "futures do nothing unless you `.await` or poll them"]
666pub(crate) struct AdcFuture<ADCX: Instance> {
667 phantom: PhantomData<ADCX>,
668 _wake_lock: WakeLock,
669}
670
671impl<ADCX: Instance> AdcFuture<ADCX> {
672 pub fn new(_self: &super::Adc<'_, ADCX, Async>) -> Self {
673 ADCX::listen();
674 Self {
675 phantom: PhantomData,
676 _wake_lock: WakeLock::new(),
677 }
678 }
679}
680
681impl<ADCX: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCX> {
682 type Output = ();
683
684 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
685 ADCX::waker().register(cx.waker());
686 if ADCX::is_done() {
687 ADCX::clear_interrupt();
688 Poll::Ready(())
689 } else {
690 Poll::Pending
691 }
692 }
693}
694
695impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
696 fn drop(&mut self) {
697 ADCX::unlisten();
698 }
699}