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, AdcChannel, AdcConfig, AdcPin, Attenuation, Error};
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;
34
35const FORCE_XPD_SAR_PU: u8 = 3;
37
38impl<ADCX> AdcConfig<ADCX>
39where
40 ADCX: RegisterAccess,
41{
42 pub fn adc_calibrate(atten: Attenuation) -> u16
44 where
45 ADCX: super::CalibrationAccess,
46 {
47 let _guard = GenericPeripheralGuard::<{ Peripheral::ApbSarAdc as u8 }>::new();
50 init_hardware::<ADCX>();
51
52 ADCX::enable_vdef(true);
53
54 ADCX::setup_calibration(atten);
56
57 ADCX::connect_gnd(true);
59
60 ADCX::calibration_init();
61 let cal_val = super::search_init_code::<ADCX>(|| {
62 ADCX::reset();
65 ADCX::start_sample();
66 while !ADCX::is_done() {}
67
68 ADCX::read_data() & ADCX::ADC_VAL_MASK
69 });
70 ADCX::reset();
71
72 ADCX::connect_gnd(false);
74
75 cal_val
76 }
77}
78
79fn init_hardware<ADCX: RegisterAccess>() {
83 LP_PERI::regs()
85 .clk_en()
86 .modify(|_, w| w.ck_en_lp_adc().set_bit());
87
88 ADCX::set_rtc_controller();
89 ADCX::set_sar_clk_div();
90 ADCX::power_up();
91}
92
93#[doc(hidden)]
94pub trait RegisterAccess {
95 fn set_attenuation(channel: usize, attenuation: u8);
96
97 fn set_rtc_controller();
99
100 fn set_en_pad(channel: u8);
101
102 fn clear_start_sample();
103
104 fn start_sample();
105
106 fn is_done() -> bool;
108
109 fn read_data() -> u16;
111
112 fn power_up();
114
115 fn set_sar_clk_div();
119
120 fn calibration_init();
122
123 fn set_init_code(data: u16);
125
126 fn reset();
128}
129
130#[cfg(adc_adc1)]
131impl RegisterAccess for crate::peripherals::ADC1<'_> {
132 fn set_attenuation(channel: usize, attenuation: u8) {
133 LP_ADC::regs().atten1().modify(|r, w| {
134 let new_value = (r.bits() & !(0b11 << (channel * 2)))
135 | (((attenuation & 0b11) as u32) << (channel * 2));
136
137 unsafe { w.sar1_atten().bits(new_value) }
138 });
139 }
140
141 fn set_rtc_controller() {
142 LP_ADC::regs()
143 .meas1_mux()
144 .modify(|_, w| w.sar1_dig_force().clear_bit());
145 LP_ADC::regs().meas1_ctrl2().modify(|_, w| {
146 w.meas1_start_force().set_bit();
147 w.sar1_en_pad_force().set_bit()
148 });
149 }
150
151 fn set_en_pad(channel: u8) {
152 LP_ADC::regs()
153 .meas1_ctrl2()
154 .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
155 }
156
157 fn clear_start_sample() {
158 LP_ADC::regs()
159 .meas1_ctrl2()
160 .modify(|_, w| w.meas1_start_sar().clear_bit());
161 }
162
163 fn start_sample() {
164 LP_ADC::regs()
165 .meas1_ctrl2()
166 .modify(|_, w| w.meas1_start_sar().set_bit());
167 }
168
169 fn is_done() -> bool {
170 LP_ADC::regs()
171 .meas1_ctrl2()
172 .read()
173 .meas1_done_sar()
174 .bit_is_set()
175 }
176
177 fn read_data() -> u16 {
178 LP_ADC::regs().meas1_ctrl2().read().meas1_data_sar().bits()
179 }
180
181 fn power_up() {
182 LP_ADC::regs()
183 .force_wpd_sar()
184 .modify(|_, w| unsafe { w.force_xpd_sar1().bits(FORCE_XPD_SAR_PU) });
185 }
186
187 fn set_sar_clk_div() {
188 LP_ADC::regs()
189 .reader1_ctrl()
190 .modify(|_, w| unsafe { w.sar1_clk_div().bits(1) });
191 }
192
193 fn calibration_init() {
194 regi2c::ADC_SAR1_DREF.write_field(4);
196 }
197
198 fn set_init_code(data: u16) {
199 let [msb, lsb] = data.to_be_bytes();
200
201 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
202 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
203 }
204
205 fn reset() {
206 LP_ADC::regs()
209 .int_clr()
210 .write(|w| w.cocpu_saradc1_int_clr().set_bit());
211
212 LP_ADC::regs()
213 .meas1_ctrl2()
214 .modify(|_, w| w.meas1_start_sar().clear_bit());
215 }
216}
217
218#[cfg(adc_adc1)]
219impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
220 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
221
222 fn enable_vdef(enable: bool) {
223 regi2c::ADC_SAR1_DREF.write_field(enable as u8);
224 }
225
226 fn connect_gnd(enable: bool) {
227 regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as u8);
228 }
229
230 fn setup_calibration(atten: Attenuation) {
231 LP_ADC::regs()
235 .meas1_ctrl2()
236 .modify(|_, w| unsafe { w.sar1_en_pad().bits(0) });
237 Self::set_attenuation(0, atten as u8);
238 }
239}
240
241#[cfg(adc_adc2)]
247const ADC2_PAD_OFFSET: u8 = 2;
248
249#[cfg(adc_adc2)]
250impl RegisterAccess for crate::peripherals::ADC2<'_> {
251 fn set_attenuation(channel: usize, attenuation: u8) {
252 let pad = channel + ADC2_PAD_OFFSET as usize;
253 LP_ADC::regs().atten2().modify(|r, w| {
254 let new_value =
255 (r.bits() & !(0b11 << (pad * 2))) | (((attenuation & 0b11) as u32) << (pad * 2));
256
257 unsafe { w.sar2_atten().bits(new_value) }
258 });
259 }
260
261 fn set_rtc_controller() {
262 LP_ADC::regs()
263 .meas2_mux()
264 .modify(|_, w| w.sar2_rtc_force().set_bit());
265 LP_ADC::regs().meas2_ctrl2().modify(|_, w| {
266 w.meas2_start_force().set_bit();
267 w.sar2_en_pad_force().set_bit()
268 });
269 }
270
271 fn set_en_pad(channel: u8) {
272 LP_ADC::regs()
273 .meas2_ctrl2()
274 .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << (channel + ADC2_PAD_OFFSET)) });
275 }
276
277 fn clear_start_sample() {
278 LP_ADC::regs()
279 .meas2_ctrl2()
280 .modify(|_, w| w.meas2_start_sar().clear_bit());
281 }
282
283 fn start_sample() {
284 LP_ADC::regs()
285 .meas2_ctrl2()
286 .modify(|_, w| w.meas2_start_sar().set_bit());
287 }
288
289 fn is_done() -> bool {
290 LP_ADC::regs()
291 .meas2_ctrl2()
292 .read()
293 .meas2_done_sar()
294 .bit_is_set()
295 }
296
297 fn read_data() -> u16 {
298 LP_ADC::regs().meas2_ctrl2().read().meas2_data_sar().bits()
299 }
300
301 fn power_up() {
302 LP_ADC::regs()
303 .force_wpd_sar()
304 .modify(|_, w| unsafe { w.force_xpd_sar2().bits(FORCE_XPD_SAR_PU) });
305 }
306
307 fn set_sar_clk_div() {
308 LP_ADC::regs()
309 .reader2_ctrl()
310 .modify(|_, w| unsafe { w.sar2_clk_div().bits(1) });
311 }
312
313 fn calibration_init() {
314 regi2c::ADC_SAR2_DREF.write_field(4);
315 }
316
317 fn set_init_code(data: u16) {
318 let [msb, lsb] = data.to_be_bytes();
319
320 regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb);
321 regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb);
322 }
323
324 fn reset() {
325 LP_ADC::regs()
328 .int_clr()
329 .write(|w| w.cocpu_saradc2_int_clr().set_bit());
330
331 LP_ADC::regs()
332 .meas2_ctrl2()
333 .modify(|_, w| w.meas2_start_sar().clear_bit());
334 }
335}
336
337#[cfg(adc_adc2)]
338impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
339 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
340
341 fn enable_vdef(enable: bool) {
342 regi2c::ADC_SAR2_DREF.write_field(enable as u8);
343 }
344
345 fn connect_gnd(enable: bool) {
346 regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as u8);
347 }
348
349 fn setup_calibration(atten: Attenuation) {
350 LP_ADC::regs()
351 .meas2_ctrl2()
352 .modify(|_, w| unsafe { w.sar2_en_pad().bits(0) });
353 Self::set_attenuation(0, atten as u8);
354 }
355}
356
357#[cfg(adc_adc1)]
358impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
359 fn init_code(atten: Attenuation) -> Option<u16> {
360 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
361 }
362
363 fn cal_mv(atten: Attenuation) -> Option<u16> {
364 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
365 }
366
367 fn cal_code(atten: Attenuation) -> Option<u16> {
368 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
369 }
370
371 fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
372 crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC1, channel.into(), atten)
373 }
374}
375
376#[cfg(adc_adc2)]
377impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
378 fn init_code(atten: Attenuation) -> Option<u16> {
379 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC2, atten)
380 }
381
382 fn cal_mv(atten: Attenuation) -> Option<u16> {
383 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC2, atten)
384 }
385
386 fn cal_code(atten: Attenuation) -> Option<u16> {
387 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC2, atten)
388 }
389
390 fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
391 crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC2, channel.into(), atten)
392 }
393}
394
395pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
397 _adc: ADC,
398 attenuations: [Option<Attenuation>; NUM_ATTENS],
399 init_codes: [u16; super::ATTENUATION_COUNT],
401 active_channel: Option<u8>,
402 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
403 _phantom: PhantomData<(Dm, &'d mut ())>,
404}
405
406impl<ADCX, Dm> Adc<'_, ADCX, Dm>
407where
408 ADCX: RegisterAccess,
409 Dm: crate::DriverMode,
410{
411 fn start_sample<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> Result<(), Error>
412 where
413 PIN: AdcChannel,
414 CS: AdcCalScheme<ADCX>,
415 {
416 let channel = pin.pin.adc_channel();
417 let attenuation = super::channel_attenuation(&self.attenuations, channel)?;
418
419 ADCX::calibration_init();
422 ADCX::set_init_code(self.init_codes[attenuation as usize]);
423
424 ADCX::set_en_pad(channel);
425
426 ADCX::clear_start_sample();
427 ADCX::start_sample();
428
429 Ok(())
430 }
431}
432
433impl<'d, ADCX> Adc<'d, ADCX, Blocking>
434where
435 ADCX: RegisterAccess + 'd,
436{
437 pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Result<Self, Error>
439 where
440 ADCX: super::AdcCalEfuse + super::CalibrationAccess,
441 {
442 let guard = GenericPeripheralGuard::new();
443
444 let attenuations = config.attenuations;
445
446 init_hardware::<ADCX>();
447
448 let init_codes = super::hw_init_codes::<ADCX>(&attenuations);
449
450 for (channel, attenuation) in attenuations.iter().enumerate() {
451 if let Some(attenuation) = attenuation {
452 ADCX::set_attenuation(channel, *attenuation as u8);
453 }
454 }
455
456 ADCX::reset();
459
460 Ok(Adc {
461 _adc: adc_instance,
462 attenuations,
463 init_codes,
464 active_channel: None,
465 _guard: guard,
466 _phantom: PhantomData,
467 })
468 }
469
470 pub fn read_blocking<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> Result<u16, Error>
478 where
479 PIN: AdcChannel,
480 CS: AdcCalScheme<ADCX>,
481 {
482 self.start_sample(pin)?;
483
484 while !ADCX::is_done() {}
486
487 let converted_value = ADCX::read_data();
489 ADCX::reset();
490
491 Ok(pin.cal_scheme.adc_val(converted_value))
493 }
494
495 pub fn read_oneshot<PIN, CS>(
506 &mut self,
507 pin: &mut super::AdcPin<PIN, ADCX, CS>,
508 ) -> nb::Result<u16, Error>
509 where
510 PIN: super::AdcChannel,
511 CS: super::AdcCalScheme<ADCX>,
512 {
513 if let Some(active_channel) = self.active_channel {
514 if active_channel != pin.pin.adc_channel() {
518 return Err(nb::Error::WouldBlock);
519 }
520 } else {
521 self.start_sample(pin).map_err(nb::Error::Other)?;
523 self.active_channel = Some(pin.pin.adc_channel());
524 }
525
526 let conversion_finished = ADCX::is_done();
528 if !conversion_finished {
529 return Err(nb::Error::WouldBlock);
530 }
531
532 let converted_value = ADCX::read_data();
534 ADCX::reset();
535
536 let converted_value = pin.cal_scheme.adc_val(converted_value);
538
539 self.active_channel = None;
541
542 Ok(converted_value)
543 }
544
545 pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
547 acquire_async_adc();
548 self.set_interrupt_handler(adc_interrupt_handler);
549
550 ADCX::reset();
552
553 Adc {
554 _adc: self._adc,
555 attenuations: self.attenuations,
556 init_codes: self.init_codes,
557 active_channel: self.active_channel,
558 _guard: self._guard,
559 _phantom: PhantomData,
560 }
561 }
562}
563
564impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
565
566impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
567 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
568 for core in crate::system::Cpu::other() {
569 crate::interrupt::disable(core, InterruptSource);
570 }
571 crate::interrupt::bind_handler(InterruptSource, handler);
572 }
573}
574
575impl<'d, ADCX> Adc<'d, ADCX, Async>
576where
577 ADCX: RegisterAccess + 'd,
578{
579 pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
581 if release_async_adc() {
582 for cpu in crate::system::Cpu::all() {
584 crate::interrupt::disable(cpu, InterruptSource);
585 }
586 }
587 Adc {
588 _adc: self._adc,
589 attenuations: self.attenuations,
590 init_codes: self.init_codes,
591 active_channel: self.active_channel,
592 _guard: self._guard,
593 _phantom: PhantomData,
594 }
595 }
596
597 pub async fn read_oneshot<PIN, CS>(
608 &mut self,
609 pin: &mut super::AdcPin<PIN, ADCX, CS>,
610 ) -> Result<u16, Error>
611 where
612 ADCX: Instance,
613 PIN: super::AdcChannel,
614 CS: super::AdcCalScheme<ADCX>,
615 {
616 self.start_sample(pin)?;
617
618 AdcFuture::<ADCX>::new(self).await;
619
620 let converted_value = ADCX::read_data();
621 ADCX::reset();
622
623 Ok(pin.cal_scheme.adc_val(converted_value))
625 }
626}
627
628static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
629
630fn acquire_async_adc() {
631 ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
632}
633
634fn release_async_adc() -> bool {
635 ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
636}
637
638#[handler]
639pub(crate) fn adc_interrupt_handler() {
640 let interrupt_status = LP_ADC::regs().int_st().read();
641
642 #[cfg(adc_adc1)]
643 if interrupt_status.cocpu_saradc1_int_st().bit_is_set() {
644 unsafe { handle_async(crate::peripherals::ADC1::steal()) }
645 }
646
647 #[cfg(adc_adc2)]
648 if interrupt_status.cocpu_saradc2_int_st().bit_is_set() {
649 unsafe { handle_async(crate::peripherals::ADC2::steal()) }
650 }
651}
652
653fn handle_async<ADCX: Instance>(_instance: ADCX) {
654 ADCX::waker().wake();
655 ADCX::unlisten();
656}
657
658pub trait Instance: crate::private::Sealed {
660 fn listen();
662
663 fn unlisten();
665
666 fn clear_interrupt();
668
669 fn waker() -> &'static AtomicWaker;
671}
672
673#[cfg(adc_adc1)]
674impl Instance for crate::peripherals::ADC1<'_> {
675 fn listen() {
676 LP_ADC::regs()
677 .int_ena_w1ts()
678 .write(|w| w.cocpu_saradc1_int_ena_w1ts().set_bit());
679 }
680
681 fn unlisten() {
682 LP_ADC::regs()
683 .int_ena_w1tc()
684 .write(|w| w.cocpu_saradc1_int_ena_w1tc().set_bit());
685 }
686
687 fn clear_interrupt() {
688 LP_ADC::regs()
689 .int_clr()
690 .write(|w| w.cocpu_saradc1_int_clr().set_bit());
691 }
692
693 fn waker() -> &'static AtomicWaker {
694 static WAKER: AtomicWaker = AtomicWaker::new();
695
696 &WAKER
697 }
698}
699
700#[cfg(adc_adc2)]
701impl Instance for crate::peripherals::ADC2<'_> {
702 fn listen() {
703 LP_ADC::regs()
704 .int_ena_w1ts()
705 .write(|w| w.cocpu_saradc2_int_ena_w1ts().set_bit());
706 }
707
708 fn unlisten() {
709 LP_ADC::regs()
710 .int_ena_w1tc()
711 .write(|w| w.cocpu_saradc2_int_ena_w1tc().set_bit());
712 }
713
714 fn clear_interrupt() {
715 LP_ADC::regs()
716 .int_clr()
717 .write(|w| w.cocpu_saradc2_int_clr().set_bit());
718 }
719
720 fn waker() -> &'static AtomicWaker {
721 static WAKER: AtomicWaker = AtomicWaker::new();
722
723 &WAKER
724 }
725}
726
727#[must_use = "futures do nothing unless you `.await` or poll them"]
728pub(crate) struct AdcFuture<ADCX: Instance> {
729 phantom: PhantomData<ADCX>,
730 _wake_lock: WakeLock,
731}
732
733impl<ADCX: Instance> AdcFuture<ADCX> {
734 pub fn new(_self: &super::Adc<'_, ADCX, Async>) -> Self {
735 ADCX::listen();
736 Self {
737 phantom: PhantomData,
738 _wake_lock: WakeLock::new(),
739 }
740 }
741}
742
743impl<ADCX: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCX> {
744 type Output = ();
745
746 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
747 ADCX::waker().register(cx.waker());
748 if ADCX::is_done() {
749 ADCX::clear_interrupt();
750 Poll::Ready(())
751 } else {
752 Poll::Pending
753 }
754 }
755}
756
757impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
758 fn drop(&mut self) {
759 ADCX::unlisten();
760 }
761}