1use core::{
2 marker::PhantomData,
3 pin::Pin,
4 task::{Context, Poll},
5};
6
7use portable_atomic::{AtomicU32, Ordering};
8use procmacros::{handler, ram};
9
10pub use self::calibration::*;
11use super::{AdcCalScheme, AdcCalSource, AdcChannel, AdcConfig, AdcPin, Attenuation};
12use crate::{
13 Async,
14 Blocking,
15 asynch::AtomicWaker,
16 efuse::AdcCalibUnit,
17 interrupt::{InterruptConfigurable, InterruptHandler},
18 peripherals::{APB_SARADC, Interrupt, LPWR, SENS},
19 rtc_cntl::WakeLock,
20 soc::regi2c,
21 system::{GenericPeripheralGuard, Peripheral},
22};
23
24mod calibration;
25
26pub(super) const NUM_ATTENS: usize = 10;
27
28cfg_select! {
29 esp32s2 => {
30 const ADC_VAL_MASK: u16 = 0x1fff;
31 const ADC_CAL_CNT_MAX: u16 = 32;
32 const ADC_CAL_CHANNEL: u16 = 15;
33 }
34 esp32s3 => {
35 const ADC_VAL_MASK: u16 = 0xfff;
36 const ADC_CAL_CNT_MAX: u16 = 32;
37 const ADC_CAL_CHANNEL: u16 = 15;
38 }
39}
40
41impl<ADCX> AdcConfig<ADCX>
42where
43 ADCX: RegisterAccess,
44{
45 pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
47 where
48 ADCX: super::CalibrationAccess,
49 {
50 let mut adc_max: u16 = 0;
51 let mut adc_min: u16 = u16::MAX;
52 let mut adc_sum: u32 = 0;
53
54 ADCX::enable_vdef(true);
55
56 ADCX::set_en_pad(ADCX::ADC_CAL_CHANNEL as u8);
58 ADCX::set_attenuation(ADCX::ADC_CAL_CHANNEL as usize, atten as u8);
59
60 ADCX::connect_cal(source, true);
62
63 ADCX::calibration_init();
64 ADCX::set_init_code(0);
65
66 for _ in 0..ADCX::ADC_CAL_CNT_MAX {
67 ADCX::start_sample();
69
70 while !ADCX::is_done() {}
72
73 let adc = ADCX::read_data() & ADCX::ADC_VAL_MASK;
74
75 ADCX::reset();
76
77 adc_sum += adc as u32;
78 adc_max = adc.max(adc_max);
79 adc_min = adc.min(adc_min);
80 }
81
82 let cal_val =
83 (adc_sum - adc_max as u32 - adc_min as u32) as u16 / (ADCX::ADC_CAL_CNT_MAX - 2);
84
85 ADCX::connect_cal(source, false);
87
88 cal_val
89 }
90}
91
92#[doc(hidden)]
93pub trait RegisterAccess {
94 fn set_attenuation(channel: usize, attenuation: u8);
95
96 fn clear_dig_force();
97
98 fn set_start_force();
99
100 fn set_en_pad_force();
101
102 fn set_en_pad(channel: u8);
103
104 fn clear_start_sample();
105
106 fn start_sample();
107
108 fn is_done() -> bool;
110
111 fn read_data() -> u16;
113
114 fn calibration_init();
116
117 fn set_init_code(data: u16);
119
120 fn reset();
122}
123
124impl RegisterAccess for crate::peripherals::ADC1<'_> {
125 fn set_attenuation(channel: usize, attenuation: u8) {
126 SENS::regs().sar_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 clear_dig_force() {
135 SENS::regs()
136 .sar_meas1_mux()
137 .modify(|_, w| w.sar1_dig_force().clear_bit());
138 }
139
140 fn set_start_force() {
141 SENS::regs()
142 .sar_meas1_ctrl2()
143 .modify(|_, w| w.meas1_start_force().set_bit());
144 }
145
146 fn set_en_pad_force() {
147 SENS::regs()
148 .sar_meas1_ctrl2()
149 .modify(|_, w| w.sar1_en_pad_force().set_bit());
150 }
151
152 fn set_en_pad(channel: u8) {
153 SENS::regs()
154 .sar_meas1_ctrl2()
155 .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
156 }
157
158 fn clear_start_sample() {
159 SENS::regs()
160 .sar_meas1_ctrl2()
161 .modify(|_, w| w.meas1_start_sar().clear_bit());
162 }
163
164 fn start_sample() {
165 while meas1_busy() {}
168
169 SENS::regs()
170 .sar_meas1_ctrl2()
171 .modify(|_, w| w.meas1_start_sar().set_bit());
172 }
173
174 fn is_done() -> bool {
175 SENS::regs()
176 .sar_meas1_ctrl2()
177 .read()
178 .meas1_done_sar()
179 .bit_is_set()
180 }
181
182 fn read_data() -> u16 {
183 SENS::regs()
184 .sar_meas1_ctrl2()
185 .read()
186 .meas1_data_sar()
187 .bits()
188 }
189
190 #[cfg(any(esp32s2, esp32s3))]
191 fn calibration_init() {
192 regi2c::ADC_SAR1_DREF.write_field(4);
195 }
196
197 fn set_init_code(data: u16) {
198 let [msb, lsb] = data.to_be_bytes();
199
200 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
201 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
202 }
203
204 fn reset() {
205 let adc = APB_SARADC::regs();
206 let sensors = SENS::regs();
207
208 adc.int_clr().write(|w| w.adc1_done().clear_bit_by_one());
209 LPWR::regs()
210 .int_clr()
211 .write(|w| w.saradc1().clear_bit_by_one());
212
213 sensors
214 .sar_meas1_ctrl2()
215 .modify(|_, w| w.meas1_start_sar().clear_bit());
216 }
217}
218
219fn meas1_busy() -> bool {
220 let status = SENS::regs().sar_slave_addr1().read();
221 cfg_select! {
222 esp32s3 => status.sar_saradc_meas_status().bits() != 0,
223 _ => status.meas_status().bits() != 0,
224 }
225}
226
227impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
228 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
229 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
230 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
231
232 fn enable_vdef(enable: bool) {
233 regi2c::ADC_SAR1_DREF.write_field(enable as u8);
234 }
235
236 fn connect_cal(source: AdcCalSource, enable: bool) {
237 match source {
238 AdcCalSource::Gnd => regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as u8),
239 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_REF.write_field(enable as u8),
240 }
241 }
242}
243
244impl RegisterAccess for crate::peripherals::ADC2<'_> {
245 fn set_attenuation(channel: usize, attenuation: u8) {
246 SENS::regs().sar_atten2().modify(|r, w| {
247 let new_value = (r.bits() & !(0b11 << (channel * 2)))
248 | (((attenuation & 0b11) as u32) << (channel * 2));
249
250 unsafe { w.sar2_atten().bits(new_value) }
251 });
252 }
253
254 fn clear_dig_force() {
255 SENS::regs()
256 .sar_meas2_mux()
257 .modify(|_, w| w.sar2_rtc_force().set_bit());
258
259 APB_SARADC::regs()
260 .arb_ctrl()
261 .modify(|_, w| w.rtc_force().set_bit());
262 }
263
264 fn set_start_force() {
265 SENS::regs()
266 .sar_meas2_ctrl2()
267 .modify(|_, w| w.meas2_start_force().set_bit());
268 }
269
270 fn set_en_pad_force() {
271 SENS::regs()
272 .sar_meas2_ctrl2()
273 .modify(|_, w| w.sar2_en_pad_force().set_bit());
274 }
275
276 fn set_en_pad(channel: u8) {
277 SENS::regs()
278 .sar_meas2_ctrl2()
279 .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) });
280 }
281
282 fn clear_start_sample() {
283 SENS::regs()
284 .sar_meas2_ctrl2()
285 .modify(|_, w| w.meas2_start_sar().clear_bit());
286 }
287
288 fn start_sample() {
289 SENS::regs()
290 .sar_meas2_ctrl2()
291 .modify(|_, w| w.meas2_start_sar().set_bit());
292 }
293
294 fn is_done() -> bool {
295 SENS::regs()
296 .sar_meas2_ctrl2()
297 .read()
298 .meas2_done_sar()
299 .bit_is_set()
300 }
301
302 fn read_data() -> u16 {
303 SENS::regs()
304 .sar_meas2_ctrl2()
305 .read()
306 .meas2_data_sar()
307 .bits()
308 }
309
310 #[cfg(any(esp32s2, esp32s3))]
311 fn calibration_init() {
312 regi2c::ADC_SAR2_DREF.write_field(4);
313 }
314
315 fn set_init_code(data: u16) {
316 let [msb, lsb] = data.to_be_bytes();
317
318 regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb);
319 regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb);
320 }
321
322 fn reset() {
323 let adc = APB_SARADC::regs();
324 let sensors = SENS::regs();
325
326 adc.int_clr().write(|w| w.adc2_done().clear_bit_by_one());
327 LPWR::regs()
328 .int_clr()
329 .write(|w| w.saradc2().clear_bit_by_one());
330
331 sensors
332 .sar_meas2_ctrl2()
333 .modify(|_, w| w.meas2_start_sar().clear_bit());
334 }
335}
336
337impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
338 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
339 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
340 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
341
342 fn enable_vdef(enable: bool) {
343 regi2c::ADC_SAR2_DREF.write_field(enable as u8);
344 }
345
346 fn connect_cal(source: AdcCalSource, enable: bool) {
347 match source {
348 AdcCalSource::Gnd => regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as u8),
349 AdcCalSource::Ref => regi2c::ADC_SAR2_ENCAL_REF.write_field(enable as u8),
350 }
351 }
352}
353
354pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
356 _adc: ADC,
357 active_channel: Option<u8>,
358 last_init_code: u16,
359 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
360 _phantom: PhantomData<(Dm, &'d mut ())>,
361}
362
363impl<'d, ADCX> Adc<'d, ADCX, Blocking>
364where
365 ADCX: RegisterAccess + 'd,
366{
367 pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Self {
370 let guard = GenericPeripheralGuard::new();
371 let sensors = SENS::regs();
372
373 let attenuations = config.attenuations;
375
376 for (channel, attenuation) in attenuations.iter().enumerate() {
377 if let Some(attenuation) = attenuation {
378 ADCX::set_attenuation(channel, *attenuation as u8);
379 }
380 }
381
382 ADCX::clear_dig_force();
384 ADCX::set_start_force();
385 ADCX::set_en_pad_force();
386 sensors.sar_hall_ctrl().modify(|_, w| {
387 w.xpd_hall_force().set_bit();
388 w.hall_phase_force().set_bit()
389 });
390
391 #[cfg(esp32s2)]
393 sensors
394 .sar_meas1_ctrl1()
395 .modify(|_, w| w.rtc_saradc_clkgate_en().set_bit());
396
397 #[cfg(esp32s3)]
398 sensors
399 .sar_peri_clk_gate_conf()
400 .modify(|_, w| w.saradc_clk_en().set_bit());
401
402 sensors.sar_power_xpd_sar().modify(|_, w| unsafe {
403 w.sarclk_en().set_bit();
404 w.force_xpd_sar().bits(0b11)
405 });
406
407 sensors
409 .sar_meas1_ctrl1()
410 .modify(|_, w| unsafe { w.force_xpd_amp().bits(0b11) });
411 sensors.sar_amp_ctrl3().modify(|_, w| unsafe {
412 w.amp_rst_fb_fsm().bits(0);
413 w.amp_short_ref_fsm().bits(0);
414 w.amp_short_ref_gnd_fsm().bits(0)
415 });
416 sensors.sar_amp_ctrl1().modify(|_, w| unsafe {
417 w.sar_amp_wait1().bits(1);
418 w.sar_amp_wait2().bits(1)
419 });
420 sensors
421 .sar_amp_ctrl2()
422 .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) });
423
424 Adc {
425 _adc: adc_instance,
426 active_channel: None,
427 last_init_code: 0,
428 _guard: guard,
429 _phantom: PhantomData,
430 }
431 }
432
433 pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
435 acquire_async_adc();
436 self.set_interrupt_handler(adc_interrupt_handler);
437
438 ADCX::reset();
441
442 Adc {
443 _adc: self._adc,
444 active_channel: self.active_channel,
445 last_init_code: self.last_init_code,
446 _guard: self._guard,
447 _phantom: PhantomData,
448 }
449 }
450
451 pub fn read_blocking<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> u16
454 where
455 PIN: AdcChannel,
456 CS: AdcCalScheme<ADCX>,
457 {
458 self.start_sample(pin);
459
460 while !ADCX::is_done() {}
462
463 let converted_value = ADCX::read_data();
465 ADCX::reset();
466
467 pin.cal_scheme.adc_val(converted_value)
469 }
470
471 pub fn read_oneshot<PIN, CS>(
477 &mut self,
478 pin: &mut super::AdcPin<PIN, ADCX, CS>,
479 ) -> nb::Result<u16, ()>
480 where
481 PIN: super::AdcChannel,
482 CS: super::AdcCalScheme<ADCX>,
483 {
484 if let Some(active_channel) = self.active_channel {
485 if active_channel != pin.pin.adc_channel() {
489 return Err(nb::Error::WouldBlock);
490 }
491 } else {
492 self.active_channel = Some(pin.pin.adc_channel());
494
495 self.start_sample(pin);
496 }
497
498 let conversion_finished = ADCX::is_done();
500 if !conversion_finished {
501 return Err(nb::Error::WouldBlock);
502 }
503
504 let converted_value = ADCX::read_data();
506 ADCX::reset();
507
508 let converted_value = pin.cal_scheme.adc_val(converted_value);
510
511 self.active_channel = None;
513
514 Ok(converted_value)
515 }
516}
517
518fn adc_interrupt_sources() -> [Interrupt; 2] {
519 [Interrupt::APB_ADC, Interrupt::RTC_CORE]
523}
524
525impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
526
527impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
528 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
529 for interrupt in adc_interrupt_sources() {
530 for core in crate::system::Cpu::other() {
531 crate::interrupt::disable(core, interrupt);
532 }
533 crate::interrupt::bind_handler(interrupt, handler);
534 }
535 }
536}
537
538impl<'d, ADCX, Dm> Adc<'d, ADCX, Dm>
539where
540 ADCX: RegisterAccess + 'd,
541 Dm: crate::DriverMode,
542{
543 fn start_sample<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>)
544 where
545 PIN: AdcChannel,
546 CS: AdcCalScheme<ADCX>,
547 {
548 let init_code = pin.cal_scheme.adc_cal();
550 if self.last_init_code != init_code {
551 ADCX::calibration_init();
552 ADCX::set_init_code(init_code);
553 self.last_init_code = init_code;
554 }
555
556 ADCX::set_en_pad(pin.pin.adc_channel());
557
558 ADCX::clear_start_sample();
559 ADCX::start_sample();
560 }
561}
562
563impl<'d, ADCX> Adc<'d, ADCX, Async>
564where
565 ADCX: RegisterAccess + 'd,
566{
567 pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
569 if release_async_adc() {
570 for interrupt in adc_interrupt_sources() {
572 for cpu in crate::system::Cpu::all() {
573 crate::interrupt::disable(cpu, interrupt);
574 }
575 }
576 }
577 Adc {
578 _adc: self._adc,
579 active_channel: self.active_channel,
580 last_init_code: self.last_init_code,
581 _guard: self._guard,
582 _phantom: PhantomData,
583 }
584 }
585
586 pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCX, CS>) -> u16
591 where
592 ADCX: Instance,
593 PIN: AdcChannel,
594 CS: AdcCalScheme<ADCX>,
595 {
596 self.start_sample(pin);
597
598 AdcFuture::new(self).await;
599
600 let converted_value = ADCX::read_data();
601 ADCX::reset();
602
603 pin.cal_scheme.adc_val(converted_value)
604 }
605}
606
607static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
608
609fn acquire_async_adc() {
610 ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
611}
612
613fn release_async_adc() -> bool {
614 ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
615}
616
617#[handler]
618#[ram]
619fn adc_interrupt_handler() {
620 let apb_status = APB_SARADC::regs().int_st().read();
621 let rtc_status = LPWR::regs().int_st().read();
622
623 if apb_status.adc1_done().bit_is_set() || rtc_status.saradc1().bit_is_set() {
624 unsafe { handle_async(crate::peripherals::ADC1::steal()) }
625 }
626
627 if apb_status.adc2_done().bit_is_set() || rtc_status.saradc2().bit_is_set() {
628 unsafe { handle_async(crate::peripherals::ADC2::steal()) }
629 }
630}
631
632fn handle_async<ADCX: Instance>(_instance: ADCX) {
633 ADCX::clear_interrupt();
634 ADCX::unlisten();
635 ADCX::waker().wake();
636}
637
638pub trait Instance: crate::private::Sealed {
640 fn listen();
642
643 fn unlisten();
645
646 fn clear_interrupt();
648
649 fn waker() -> &'static AtomicWaker;
651}
652
653impl Instance for crate::peripherals::ADC1<'_> {
654 fn listen() {
655 APB_SARADC::regs()
656 .int_ena()
657 .modify(|_, w| w.adc1_done().set_bit());
658
659 SENS::regs().sar_reader1_ctrl().modify(|_, w| {
660 cfg_select! {
661 esp32s3 => w.sar_sar1_int_en().set_bit(),
662 _ => w.sar1_int_en().set_bit(),
663 }
664 });
665
666 LPWR::regs().int_ena().modify(|_, w| w.saradc1().set_bit());
667 }
668
669 fn unlisten() {
670 APB_SARADC::regs()
671 .int_ena()
672 .modify(|_, w| w.adc1_done().clear_bit());
673
674 SENS::regs().sar_reader1_ctrl().modify(|_, w| {
675 cfg_select! {
676 esp32s3 => w.sar_sar1_int_en().clear_bit(),
677 _ => w.sar1_int_en().clear_bit(),
678 }
679 });
680
681 LPWR::regs()
682 .int_ena()
683 .modify(|_, w| w.saradc1().clear_bit());
684 }
685
686 fn clear_interrupt() {
687 APB_SARADC::regs()
688 .int_clr()
689 .write(|w| w.adc1_done().clear_bit_by_one());
690 LPWR::regs()
691 .int_clr()
692 .write(|w| w.saradc1().clear_bit_by_one());
693 }
694
695 fn waker() -> &'static AtomicWaker {
696 static WAKER: AtomicWaker = AtomicWaker::new();
697
698 &WAKER
699 }
700}
701
702impl Instance for crate::peripherals::ADC2<'_> {
703 fn listen() {
704 APB_SARADC::regs()
705 .int_ena()
706 .modify(|_, w| w.adc2_done().set_bit());
707
708 SENS::regs().sar_reader2_ctrl().modify(|_, w| {
709 cfg_select! {
710 esp32s3 => w.sar_sar2_int_en().set_bit(),
711 _ => w.sar2_int_en().set_bit(),
712 }
713 });
714
715 LPWR::regs().int_ena().modify(|_, w| w.saradc2().set_bit());
716 }
717
718 fn unlisten() {
719 APB_SARADC::regs()
720 .int_ena()
721 .modify(|_, w| w.adc2_done().clear_bit());
722
723 SENS::regs().sar_reader2_ctrl().modify(|_, w| {
724 cfg_select! {
725 esp32s3 => w.sar_sar2_int_en().clear_bit(),
726 _ => w.sar2_int_en().clear_bit(),
727 }
728 });
729
730 LPWR::regs()
731 .int_ena()
732 .modify(|_, w| w.saradc2().clear_bit());
733 }
734
735 fn clear_interrupt() {
736 APB_SARADC::regs()
737 .int_clr()
738 .write(|w| w.adc2_done().clear_bit_by_one());
739 LPWR::regs()
740 .int_clr()
741 .write(|w| w.saradc2().clear_bit_by_one());
742 }
743
744 fn waker() -> &'static AtomicWaker {
745 static WAKER: AtomicWaker = AtomicWaker::new();
746
747 &WAKER
748 }
749}
750
751#[must_use = "futures do nothing unless you `.await` or poll them"]
752struct AdcFuture<ADCX: Instance> {
753 phantom: PhantomData<ADCX>,
754 _wake_lock: WakeLock,
755}
756
757impl<ADCX: Instance> AdcFuture<ADCX> {
758 fn new(_self: &Adc<'_, ADCX, Async>) -> Self {
759 ADCX::listen();
760 Self {
761 phantom: PhantomData,
762 _wake_lock: WakeLock::new(),
763 }
764 }
765}
766
767impl<ADCX: Instance + RegisterAccess> core::future::Future for AdcFuture<ADCX> {
768 type Output = ();
769
770 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
771 ADCX::waker().register(cx.waker());
772 if ADCX::is_done() {
773 ADCX::clear_interrupt();
774 Poll::Ready(())
775 } else {
776 Poll::Pending
777 }
778 }
779}
780
781impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
782 fn drop(&mut self) {
783 ADCX::unlisten();
784 }
785}
786
787#[cfg(any(esp32s2, esp32s3))]
788impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
789 fn init_code(atten: Attenuation) -> Option<u16> {
790 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
791 }
792
793 fn cal_mv(atten: Attenuation) -> u16 {
794 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
795 }
796
797 fn cal_code(atten: Attenuation) -> Option<u16> {
798 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
799 }
800}
801
802#[cfg(any(esp32s2, esp32s3))]
803impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
804 fn init_code(atten: Attenuation) -> Option<u16> {
805 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC2, atten)
806 }
807
808 fn cal_mv(atten: Attenuation) -> u16 {
809 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC2, atten)
810 }
811
812 fn cal_code(atten: Attenuation) -> Option<u16> {
813 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC2, atten)
814 }
815}