1use core::marker::PhantomData;
2
3cfg_select! {
4 any(esp32c6, esp32c61) => {
5 use Interrupt::APB_SARADC as InterruptSource;
6 }
7 _ => {
8 use Interrupt::APB_ADC as InterruptSource;
9 }
10}
11
12use core::{
13 pin::Pin,
14 task::{Context, Poll},
15};
16
17use procmacros::handler;
18
19pub use self::calibration::*;
20use super::{AdcConfig, Attenuation, Error};
21use crate::{
22 Async,
23 Blocking,
24 asynch::AtomicWaker,
25 efuse::AdcCalibUnit,
26 interrupt::{InterruptConfigurable, InterruptHandler},
27 peripherals::{APB_SARADC, Interrupt},
28 rtc_cntl::WakeLock,
29 soc::regi2c,
30 system::{GenericPeripheralGuard, Peripheral},
31};
32
33mod calibration;
34
35const ADC_VAL_MASK: u16 = 0xfff;
41
42pub(super) const NUM_ATTENS: usize = property!("adc.channel_count");
43
44impl<ADCX> AdcConfig<ADCX>
45where
46 ADCX: RegisterAccess,
47{
48 pub fn adc_calibrate(atten: Attenuation) -> u16
50 where
51 ADCX: super::CalibrationAccess,
52 {
53 let _guard = GenericPeripheralGuard::<{ Peripheral::ApbSarAdc as u8 }>::new();
56 let _clock = FunctionClockGuard::new();
57 let sar_power = SarPowerGuard::new();
58 init_hardware();
59 sar_power.force_on();
60
61 ADCX::enable_vdef(true);
62
63 ADCX::setup_calibration(atten);
65
66 ADCX::connect_gnd(true);
68
69 ADCX::calibration_init();
70 let cal_val = super::search_init_code::<ADCX>(read_cal_channel::<ADCX>);
71 ADCX::reset();
72
73 ADCX::connect_gnd(false);
75
76 cal_val
77 }
78}
79
80fn read_cal_channel<ADCX: RegisterAccess>() -> u16 {
85 ADCX::clear_done();
87
88 ADCX::set_onetime_start(false);
89 crate::rom::ets_delay_us(5);
90 ADCX::set_onetime_start(true);
91
92 while !ADCX::is_done() {}
93 settle_after_done();
94
95 ADCX::read_data() & ADC_VAL_MASK
96}
97
98fn init_hardware() {
103 #[cfg(esp32h2)]
106 const DIV: (u8, u8, u8) = (18, 5, 1);
107 #[cfg(not(esp32h2))]
108 const DIV: (u8, u8, u8) = (15, 1, 0);
109
110 let (div_num, div_b, div_a) = DIV;
111
112 #[cfg(not(adc_pcr_clock))]
115 APB_SARADC::regs().clkm_conf().modify(|_, w| unsafe {
116 w.clkm_div_num().bits(div_num);
117 w.clkm_div_b().bits(div_b);
118 w.clkm_div_a().bits(div_a)
119 });
120
121 #[cfg(adc_pcr_clock)]
122 crate::peripherals::PCR::regs()
123 .saradc_clkm_conf()
124 .modify(|_, w| unsafe {
125 w.saradc_clkm_div_num().bits(div_num);
126 w.saradc_clkm_div_b().bits(div_b);
127 w.saradc_clkm_div_a().bits(div_a)
128 });
129
130 APB_SARADC::regs().ctrl().modify(|_, w| unsafe {
131 w.start_force().clear_bit();
135 w.start().clear_bit();
136 w.sar_clk_gated().set_bit();
137 #[cfg(not(adc_pcr_sar_clk_div))]
138 w.sar_clk_div().bits(1);
139 w.xpd_sar_force().bits(0b11)
140 });
141
142 #[cfg(adc_pcr_sar_clk_div)]
145 crate::peripherals::PCR::regs()
146 .sar_clk_div()
147 .modify(|_, w| unsafe { w.sar1_clk_div_num().bits(1) });
148}
149
150struct FunctionClockGuard;
151
152impl FunctionClockGuard {
153 fn new() -> Self {
154 crate::clock::ll::ClockTree::with(|clocks| {
155 #[cfg(soc_clock_node_adc_function_clock_is_configurable)]
156 crate::clock::ll::AdcInstance::ApbSaradc
157 .configure_function_clock(clocks, Default::default());
158 crate::clock::ll::AdcInstance::ApbSaradc.request_function_clock(clocks);
159 });
160 Self
161 }
162}
163
164impl Drop for FunctionClockGuard {
165 fn drop(&mut self) {
166 crate::clock::ll::ClockTree::with(|clocks| {
167 crate::clock::ll::AdcInstance::ApbSaradc.release_function_clock(clocks);
168 });
169 }
170}
171
172struct SarPowerGuard;
183
184cfg_select! {
185 adc_sar_power_override => {
186 static SAR_POWER_REFS: esp_sync::NonReentrantMutex<u8> =
187 esp_sync::NonReentrantMutex::new(0);
188
189 impl SarPowerGuard {
190 fn new() -> Self {
191 SAR_POWER_REFS.with(|refs| *refs += 1);
192 Self
193 }
194
195 fn force_on(&self) {
200 SAR_POWER_REFS.with(|_| force_sar_power(true));
201 }
202 }
203
204 impl Drop for SarPowerGuard {
205 fn drop(&mut self) {
206 SAR_POWER_REFS.with(|refs| {
207 *refs -= 1;
208 if *refs == 0 {
209 force_sar_power(false);
210 }
211 });
212 }
213 }
214
215 fn force_sar_power(force: bool) {
226 const PWDET_CONF: *mut u32 = cfg_select! {
228 esp32c61 => 0x600A_0808 as *mut u32,
229 _ => 0x600A_0810 as *mut u32,
230 };
231 const SAR_POWER_FORCE: u32 = 1 << 24;
232 const SAR_POWER_CNTL: u32 = 1 << 23;
233
234 let clk_conf1 = crate::peripherals::MODEM_SYSCON::regs().clk_conf1();
235 let fe_apb_clock_enabled = clk_conf1.read().clk_fe_apb_en().bit();
236 clk_conf1.modify(|_, w| w.clk_fe_apb_en().set_bit());
237
238 unsafe {
239 let conf = PWDET_CONF.read_volatile();
240 let conf = if force {
241 conf | SAR_POWER_FORCE | SAR_POWER_CNTL
242 } else {
243 conf & !SAR_POWER_FORCE
244 };
245 PWDET_CONF.write_volatile(conf);
246 }
247
248 clk_conf1.modify(|_, w| w.clk_fe_apb_en().bit(fe_apb_clock_enabled));
249 }
250 }
251 _ => {
252 impl SarPowerGuard {
253 fn new() -> Self {
254 Self
255 }
256
257 fn force_on(&self) {}
258 }
259 }
260}
261
262fn start_onetime_sample<ADCX: RegisterAccess>(sar_power: &SarPowerGuard) {
267 sar_power.force_on();
268 ADCX::set_onetime_start(true);
269}
270
271#[inline]
278fn settle_after_done() {
279 #[cfg(esp32h2)]
280 crate::rom::ets_delay_us(5);
281}
282
283#[doc(hidden)]
284pub trait RegisterAccess {
285 fn config_onetime_sample(channel: u8, attenuation: u8);
287
288 fn set_onetime_start(enable: bool);
293
294 fn is_done() -> bool;
296
297 fn read_data() -> u16;
299
300 fn clear_done();
302
303 fn reset();
305
306 fn calibration_init();
308
309 fn set_init_code(data: u16);
311}
312
313impl RegisterAccess for crate::peripherals::ADC1<'_> {
314 fn config_onetime_sample(channel: u8, attenuation: u8) {
315 #[cfg(esp32c6)]
316 let was_armed = APB_SARADC::regs()
317 .onetime_sample()
318 .read()
319 .saradc1_onetime_sample()
320 .bit();
321
322 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
323 w.saradc2_onetime_sample().clear_bit();
326 w.saradc1_onetime_sample().set_bit();
327 w.onetime_channel().bits(channel);
328 w.onetime_atten().bits(attenuation)
329 });
330
331 #[cfg(esp32c6)]
334 if !was_armed {
335 crate::rom::ets_delay_us(50);
336 }
337 }
338
339 fn set_onetime_start(enable: bool) {
340 APB_SARADC::regs()
341 .onetime_sample()
342 .modify(|_, w| w.onetime_start().bit(enable));
343 }
344
345 fn is_done() -> bool {
346 APB_SARADC::regs().int_raw().read().adc1_done().bit()
347 }
348
349 fn read_data() -> u16 {
350 APB_SARADC::regs()
351 .sar1data_status()
352 .read()
353 .saradc1_data()
354 .bits() as u16
355 & 0xfff
356 }
357
358 fn clear_done() {
359 APB_SARADC::regs()
360 .int_clr()
361 .write(|w| w.adc1_done().clear_bit_by_one());
362 }
363
364 fn reset() {
365 Self::clear_done();
366
367 APB_SARADC::regs().onetime_sample().modify(|_, w| {
371 #[cfg(not(esp32c6))]
372 {
373 w.saradc2_onetime_sample().clear_bit();
374 w.saradc1_onetime_sample().clear_bit();
375 }
376 w.onetime_start().clear_bit()
377 });
378 }
379
380 fn calibration_init() {
381 regi2c::ADC_SAR1_DREF.write_field(1);
384 }
385
386 fn set_init_code(data: u16) {
387 let [msb, lsb] = data.to_be_bytes();
388
389 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
390 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
391 }
392}
393
394impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
395 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
396 const SUPPORTS_SELF_CALIBRATION: bool = !cfg!(esp32c5);
397
398 fn enable_vdef(enable: bool) {
399 regi2c::ADC_SAR1_DREF.write_field(enable as _);
400 }
401
402 fn connect_gnd(enable: bool) {
403 regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as _);
404 }
405
406 fn setup_calibration(atten: Attenuation) {
407 Self::config_onetime_sample(0xf, atten as u8);
411 }
412}
413
414pub struct Adc<'d, ADCX, Dm: crate::DriverMode> {
416 _adc: ADCX,
417 attenuations: [Option<Attenuation>; NUM_ATTENS],
418 init_codes: [u16; super::ATTENUATION_COUNT],
420 active_channel: Option<u8>,
421 _clock: FunctionClockGuard,
422 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
423 sar_power: SarPowerGuard,
424 _phantom: PhantomData<(Dm, &'d mut ())>,
425}
426
427impl<'d, ADCX, Dm> Adc<'d, ADCX, Dm>
428where
429 ADCX: RegisterAccess + 'd,
430 Dm: crate::DriverMode,
431{
432 fn start_sample<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCX, CS>) -> Result<(), Error>
435 where
436 PIN: super::AdcChannel,
437 CS: super::AdcCalScheme<ADCX>,
438 {
439 let channel = pin.pin.adc_channel();
440 let attenuation = super::channel_attenuation(&self.attenuations, channel)?;
441
442 ADCX::calibration_init();
443 ADCX::set_init_code(self.init_codes[attenuation as usize]);
444
445 ADCX::config_onetime_sample(channel, attenuation as u8);
446 start_onetime_sample::<ADCX>(&self.sar_power);
447
448 Ok(())
449 }
450}
451
452impl<'d, ADCX> Adc<'d, ADCX, Blocking>
453where
454 ADCX: RegisterAccess + 'd,
455{
456 pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Result<Self, Error>
458 where
459 ADCX: super::AdcCalEfuse + super::CalibrationAccess,
460 {
461 let guard = GenericPeripheralGuard::new();
462 let clock = FunctionClockGuard::new();
463 let sar_power = SarPowerGuard::new();
464
465 init_hardware();
466
467 let init_codes = super::hw_init_codes::<ADCX>(&config.attenuations);
468
469 ADCX::reset();
472
473 Ok(Adc {
474 _adc: adc_instance,
475 attenuations: config.attenuations,
476 init_codes,
477 active_channel: None,
478 _guard: guard,
479 _clock: clock,
480 sar_power,
481 _phantom: PhantomData,
482 })
483 }
484
485 pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
487 self.set_interrupt_handler(adc_interrupt_handler);
488
489 ADCX::reset();
493
494 Adc {
495 _adc: self._adc,
496 attenuations: self.attenuations,
497 init_codes: self.init_codes,
498 active_channel: self.active_channel,
499 _guard: self._guard,
500 _clock: self._clock,
501 sar_power: self.sar_power,
502 _phantom: PhantomData,
503 }
504 }
505
506 pub fn read_oneshot<PIN, CS>(
517 &mut self,
518 pin: &mut super::AdcPin<PIN, ADCX, CS>,
519 ) -> nb::Result<u16, Error>
520 where
521 PIN: super::AdcChannel,
522 CS: super::AdcCalScheme<ADCX>,
523 {
524 let channel = pin.pin.adc_channel();
525
526 if let Some(active_channel) = self.active_channel {
527 if active_channel != channel {
531 return Err(nb::Error::WouldBlock);
532 }
533 } else {
534 self.start_sample(pin).map_err(nb::Error::Other)?;
536 self.active_channel = Some(channel);
537 }
538
539 let conversion_finished = ADCX::is_done();
541 if !conversion_finished {
542 return Err(nb::Error::WouldBlock);
543 }
544 settle_after_done();
545
546 let converted_value = ADCX::read_data();
548 ADCX::reset();
549
550 let converted_value = pin.cal_scheme.adc_val(converted_value);
552
553 self.active_channel = None;
555
556 Ok(converted_value)
557 }
558}
559
560impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
561
562impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
563 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
564 for core in crate::system::Cpu::other() {
565 crate::interrupt::disable(core, InterruptSource);
566 }
567 crate::interrupt::bind_handler(InterruptSource, handler);
568 }
569}
570
571impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
572 fn init_code(atten: Attenuation) -> Option<u16> {
573 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
574 }
575
576 fn cal_mv(atten: Attenuation) -> Option<u16> {
577 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
578 }
579
580 fn cal_code(atten: Attenuation) -> Option<u16> {
581 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
582 }
583
584 #[cfg(adc_channel_compensation)]
585 fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
586 crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC1, channel, atten)
587 }
588}
589
590impl<'d, ADCX> Adc<'d, ADCX, Async>
591where
592 ADCX: RegisterAccess + 'd,
593{
594 pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
596 for cpu in crate::system::Cpu::all() {
599 crate::interrupt::disable(cpu, InterruptSource);
600 }
601 Adc {
602 _adc: self._adc,
603 attenuations: self.attenuations,
604 init_codes: self.init_codes,
605 active_channel: self.active_channel,
606 _guard: self._guard,
607 _clock: self._clock,
608 sar_power: self.sar_power,
609 _phantom: PhantomData,
610 }
611 }
612
613 pub async fn read_oneshot<PIN, CS>(
624 &mut self,
625 pin: &mut super::AdcPin<PIN, ADCX, CS>,
626 ) -> Result<u16, Error>
627 where
628 ADCX: Instance,
629 PIN: super::AdcChannel,
630 CS: super::AdcCalScheme<ADCX>,
631 {
632 self.start_sample(pin)?;
633
634 let adc_ready_future = AdcFuture::new(self);
636 adc_ready_future.await;
637 settle_after_done();
638
639 let converted_value = ADCX::read_data();
640
641 ADCX::reset();
642
643 Ok(pin.cal_scheme.adc_val(converted_value))
645 }
646}
647
648#[handler]
649pub(crate) fn adc_interrupt_handler() {
650 let saradc = APB_SARADC::regs();
651 let interrupt_status = saradc.int_st().read();
652
653 if interrupt_status.adc1_done().bit_is_set() {
654 unsafe { handle_async(crate::peripherals::ADC1::steal()) }
655 }
656}
657
658fn handle_async<ADCX: Instance>(_instance: ADCX) {
659 ADCX::waker().wake();
660 ADCX::unlisten();
661}
662
663pub trait Instance: crate::private::Sealed {
665 fn listen();
667
668 fn unlisten();
670
671 fn clear_interrupt();
673
674 fn waker() -> &'static AtomicWaker;
676}
677
678impl Instance for crate::peripherals::ADC1<'_> {
679 fn listen() {
680 APB_SARADC::regs()
681 .int_ena()
682 .modify(|_, w| w.adc1_done().set_bit());
683 }
684
685 fn unlisten() {
686 APB_SARADC::regs()
687 .int_ena()
688 .modify(|_, w| w.adc1_done().clear_bit());
689 }
690
691 fn clear_interrupt() {
692 APB_SARADC::regs()
693 .int_clr()
694 .write(|w| w.adc1_done().clear_bit_by_one());
695 }
696
697 fn waker() -> &'static AtomicWaker {
698 static WAKER: AtomicWaker = AtomicWaker::new();
699
700 &WAKER
701 }
702}
703
704#[must_use = "futures do nothing unless you `.await` or poll them"]
705pub(crate) struct AdcFuture<ADCX: Instance> {
706 phantom: PhantomData<ADCX>,
707 _wake_lock: WakeLock,
708}
709
710impl<ADCX: Instance> AdcFuture<ADCX> {
711 pub fn new(_self: &super::Adc<'_, ADCX, Async>) -> Self {
712 Self {
713 phantom: PhantomData,
714 _wake_lock: WakeLock::new(),
715 }
716 }
717}
718
719impl<ADCX: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCX> {
720 type Output = ();
721
722 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
723 if ADCX::is_done() {
724 ADCX::clear_interrupt();
725 Poll::Ready(())
726 } else {
727 ADCX::waker().register(cx.waker());
728 ADCX::listen();
729 Poll::Pending
730 }
731 }
732}
733
734impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
735 fn drop(&mut self) {
736 ADCX::unlisten();
737 }
738}