1use core::marker::PhantomData;
2
3cfg_if::cfg_if! {
4 if #[cfg(esp32c6)] {
5 use Interrupt::APB_SARADC as InterruptSource;
6 } else {
7 use Interrupt::APB_ADC as InterruptSource;
8 }
9}
10
11use core::{
12 pin::Pin,
13 task::{Context, Poll},
14};
15
16#[cfg(all(adc_adc1, adc_adc2))]
18use portable_atomic::{AtomicU32, Ordering};
19use procmacros::handler;
20
21pub use self::calibration::*;
22use super::{AdcCalSource, AdcConfig, Attenuation};
23#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))]
24use crate::efuse::Efuse;
25use crate::{
26 Async,
27 Blocking,
28 asynch::AtomicWaker,
29 interrupt::{InterruptConfigurable, InterruptHandler},
30 peripherals::{APB_SARADC, Interrupt},
31 soc::regi2c,
32 system::{GenericPeripheralGuard, Peripheral},
33};
34
35mod calibration;
36
37cfg_if::cfg_if! {
44 if #[cfg(adc_adc1)] {
45 const ADC_VAL_MASK: u16 = 0xfff;
46 const ADC_CAL_CNT_MAX: u16 = 32;
47 const ADC_CAL_CHANNEL: u16 = 15;
48 }
49}
50
51cfg_if::cfg_if! {
54 if #[cfg(esp32c6)] {
55 pub(super) const NUM_ATTENS: usize = 7;
56 } else {
57 pub(super) const NUM_ATTENS: usize = 5;
58 }
59}
60
61#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64#[allow(clippy::enum_variant_names, reason = "peripheral is unstable")]
65pub enum Resolution {
66 #[default]
68 Resolution12Bit,
69}
70
71impl<ADCI> AdcConfig<ADCI>
72where
73 ADCI: RegisterAccess,
74{
75 pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
77 where
78 ADCI: super::CalibrationAccess,
79 {
80 let mut adc_max: u16 = 0;
81 let mut adc_min: u16 = u16::MAX;
82 let mut adc_sum: u32 = 0;
83
84 ADCI::enable_vdef(true);
85
86 ADCI::config_onetime_sample(ADC_CAL_CHANNEL as u8, atten as u8);
88
89 ADCI::connect_cal(source, true);
91
92 for _ in 0..ADC_CAL_CNT_MAX {
93 ADCI::set_init_code(0);
94
95 ADCI::start_onetime_sample();
97
98 while !ADCI::is_done() {}
100
101 let adc = ADCI::read_data() & ADC_VAL_MASK;
102
103 ADCI::reset();
104
105 adc_sum += adc as u32;
106 adc_max = adc.max(adc_max);
107 adc_min = adc.min(adc_min);
108 }
109
110 let cal_val = (adc_sum - adc_max as u32 - adc_min as u32) as u16 / (ADC_CAL_CNT_MAX - 2);
111
112 ADCI::connect_cal(source, false);
114
115 cal_val
116 }
117}
118
119#[doc(hidden)]
120pub trait RegisterAccess {
121 fn config_onetime_sample(channel: u8, attenuation: u8);
123
124 fn start_onetime_sample();
126
127 fn is_done() -> bool;
129
130 fn read_data() -> u16;
132
133 fn reset();
135
136 fn set_init_code(data: u16);
138}
139
140#[cfg(adc_adc1)]
141impl RegisterAccess for crate::peripherals::ADC1<'_> {
142 fn config_onetime_sample(channel: u8, attenuation: u8) {
143 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
144 w.saradc1_onetime_sample().set_bit();
145 w.onetime_channel().bits(channel);
146 w.onetime_atten().bits(attenuation)
147 });
148 }
149
150 fn start_onetime_sample() {
151 APB_SARADC::regs()
152 .onetime_sample()
153 .modify(|_, w| w.onetime_start().set_bit());
154 }
155
156 fn is_done() -> bool {
157 APB_SARADC::regs().int_raw().read().adc1_done().bit()
158 }
159
160 fn read_data() -> u16 {
161 APB_SARADC::regs()
162 .sar1data_status()
163 .read()
164 .saradc1_data()
165 .bits() as u16
166 & 0xfff
167 }
168
169 fn reset() {
170 APB_SARADC::regs()
172 .int_clr()
173 .write(|w| w.adc1_done().clear_bit_by_one());
174
175 APB_SARADC::regs()
177 .onetime_sample()
178 .modify(|_, w| w.onetime_start().clear_bit());
179 }
180
181 fn set_init_code(data: u16) {
182 let [msb, lsb] = data.to_be_bytes();
183
184 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
185 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
186 }
187}
188
189#[cfg(adc_adc1)]
190impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
191 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
192 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
193 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
194
195 fn enable_vdef(enable: bool) {
196 regi2c::ADC_SAR1_DREF.write_field(enable as _);
197 }
198
199 fn connect_cal(source: AdcCalSource, enable: bool) {
200 match source {
201 AdcCalSource::Gnd => regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as _),
202 #[cfg(not(esp32h2))]
203 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_REF.write_field(enable as _),
204 #[cfg(esp32h2)]
209 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_GND.write_field(!enable as _),
210 }
211 }
212}
213
214#[cfg(adc_adc2)]
215impl RegisterAccess for crate::peripherals::ADC2<'_> {
216 fn config_onetime_sample(channel: u8, attenuation: u8) {
217 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
218 w.saradc2_onetime_sample().set_bit();
219 w.onetime_channel().bits(channel);
220 w.onetime_atten().bits(attenuation)
221 });
222 }
223
224 fn start_onetime_sample() {
225 APB_SARADC::regs()
226 .onetime_sample()
227 .modify(|_, w| w.onetime_start().set_bit());
228 }
229
230 fn is_done() -> bool {
231 APB_SARADC::regs().int_raw().read().adc2_done().bit()
232 }
233
234 fn read_data() -> u16 {
235 APB_SARADC::regs()
236 .sar2data_status()
237 .read()
238 .saradc2_data()
239 .bits() as u16
240 & 0xfff
241 }
242
243 fn reset() {
244 APB_SARADC::regs()
245 .int_clr()
246 .write(|w| w.adc2_done().clear_bit_by_one());
247
248 APB_SARADC::regs()
249 .onetime_sample()
250 .modify(|_, w| w.onetime_start().clear_bit());
251 }
252
253 fn set_init_code(data: u16) {
254 let [msb, lsb] = data.to_be_bytes();
255
256 regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb as _);
257 regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb as _);
258 }
259}
260
261#[cfg(adc_adc2)]
262impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
263 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
264 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
265 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
266
267 fn enable_vdef(enable: bool) {
268 regi2c::ADC_SAR2_DREF.write_field(enable as _);
269 }
270
271 fn connect_cal(source: AdcCalSource, enable: bool) {
272 match source {
273 AdcCalSource::Gnd => regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as _),
274 AdcCalSource::Ref => regi2c::ADC_SAR2_ENCAL_REF.write_field(enable as _),
275 }
276 }
277}
278
279pub struct Adc<'d, ADCI, Dm: crate::DriverMode> {
281 _adc: ADCI,
282 attenuations: [Option<Attenuation>; NUM_ATTENS],
283 active_channel: Option<u8>,
284 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
285 _phantom: PhantomData<(Dm, &'d mut ())>,
286}
287
288impl<'d, ADCI> Adc<'d, ADCI, Blocking>
289where
290 ADCI: RegisterAccess + 'd,
291{
292 pub fn new(adc_instance: ADCI, config: AdcConfig<ADCI>) -> Self {
295 let guard = GenericPeripheralGuard::new();
296
297 APB_SARADC::regs().ctrl().modify(|_, w| unsafe {
298 w.start_force().set_bit();
299 w.start().set_bit();
300 w.sar_clk_gated().set_bit();
301 w.xpd_sar_force().bits(0b11)
302 });
303
304 Adc {
305 _adc: adc_instance,
306 attenuations: config.attenuations,
307 active_channel: None,
308 _guard: guard,
309 _phantom: PhantomData,
310 }
311 }
312
313 pub fn into_async(mut self) -> Adc<'d, ADCI, Async> {
315 acquire_async_adc();
316 self.set_interrupt_handler(adc_interrupt_handler);
317
318 ADCI::reset();
322
323 Adc {
324 _adc: self._adc,
325 attenuations: self.attenuations,
326 active_channel: self.active_channel,
327 _guard: self._guard,
328 _phantom: PhantomData,
329 }
330 }
331
332 pub fn read_oneshot<PIN, CS>(
338 &mut self,
339 pin: &mut super::AdcPin<PIN, ADCI, CS>,
340 ) -> nb::Result<u16, ()>
341 where
342 PIN: super::AdcChannel,
343 CS: super::AdcCalScheme<ADCI>,
344 {
345 if self.attenuations[PIN::CHANNEL as usize].is_none() {
346 panic!("Channel {} is not configured reading!", PIN::CHANNEL);
347 }
348
349 if let Some(active_channel) = self.active_channel {
350 if active_channel != PIN::CHANNEL {
354 return Err(nb::Error::WouldBlock);
355 }
356 } else {
357 self.active_channel = Some(PIN::CHANNEL);
359
360 ADCI::set_init_code(pin.cal_scheme.adc_cal());
362
363 let channel = self.active_channel.unwrap();
364 let attenuation = self.attenuations[channel as usize].unwrap() as u8;
365 ADCI::config_onetime_sample(channel, attenuation);
366 ADCI::start_onetime_sample();
367
368 #[cfg(esp32c6)]
371 {
372 crate::rom::ets_delay_us(40);
373 ADCI::start_onetime_sample();
374 }
375 }
376
377 let conversion_finished = ADCI::is_done();
379 if !conversion_finished {
380 return Err(nb::Error::WouldBlock);
381 }
382
383 let converted_value = ADCI::read_data();
385 ADCI::reset();
386
387 let converted_value = pin.cal_scheme.adc_val(converted_value);
389
390 self.active_channel = None;
402
403 Ok(converted_value)
404 }
405}
406
407impl<ADCI> crate::private::Sealed for Adc<'_, ADCI, Blocking> {}
408
409impl<ADCI> InterruptConfigurable for Adc<'_, ADCI, Blocking> {
410 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
411 for core in crate::system::Cpu::other() {
412 crate::interrupt::disable(core, InterruptSource);
413 }
414 unsafe { crate::interrupt::bind_interrupt(InterruptSource, handler.handler()) };
415 unwrap!(crate::interrupt::enable(
416 InterruptSource,
417 handler.priority()
418 ));
419 }
420}
421
422#[cfg(adc_adc1)]
423impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
424 fn init_code(atten: Attenuation) -> Option<u16> {
425 Efuse::rtc_calib_init_code(1, atten)
426 }
427
428 fn cal_mv(atten: Attenuation) -> u16 {
429 Efuse::rtc_calib_cal_mv(1, atten)
430 }
431
432 fn cal_code(atten: Attenuation) -> Option<u16> {
433 Efuse::rtc_calib_cal_code(1, atten)
434 }
435}
436
437#[cfg(adc_adc2)]
438impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
439 fn init_code(atten: Attenuation) -> Option<u16> {
440 Efuse::rtc_calib_init_code(2, atten)
441 }
442
443 fn cal_mv(atten: Attenuation) -> u16 {
444 Efuse::rtc_calib_cal_mv(2, atten)
445 }
446
447 fn cal_code(atten: Attenuation) -> Option<u16> {
448 Efuse::rtc_calib_cal_code(2, atten)
449 }
450}
451
452#[cfg(esp32c2)]
453mod adc_implementation {
454 crate::analog::adc::impl_adc_interface! {
455 ADC1 [
456 (GPIO0<'_>, 0),
457 (GPIO1<'_>, 1),
458 (GPIO2<'_>, 2),
459 (GPIO3<'_>, 3),
460 (GPIO4<'_>, 4),
461 ]
462 }
463}
464
465#[cfg(esp32c3)]
466mod adc_implementation {
467 crate::analog::adc::impl_adc_interface! {
468 ADC1 [
469 (GPIO0<'_>, 0),
470 (GPIO1<'_>, 1),
471 (GPIO2<'_>, 2),
472 (GPIO3<'_>, 3),
473 (GPIO4<'_>, 4),
474 ]
475 }
476
477 crate::analog::adc::impl_adc_interface! {
478 ADC2 [
479 (GPIO5<'_>, 0),
480 ]
481 }
482}
483
484#[cfg(esp32c6)]
485mod adc_implementation {
486 crate::analog::adc::impl_adc_interface! {
487 ADC1 [
488 (GPIO0<'_>, 0),
489 (GPIO1<'_>, 1),
490 (GPIO2<'_>, 2),
491 (GPIO3<'_>, 3),
492 (GPIO4<'_>, 4),
493 (GPIO5<'_>, 5),
494 (GPIO6<'_>, 6),
495 ]
496 }
497}
498
499#[cfg(esp32h2)]
500mod adc_implementation {
501 crate::analog::adc::impl_adc_interface! {
502 ADC1 [
503 (GPIO1<'_>, 0),
504 (GPIO2<'_>, 1),
505 (GPIO3<'_>, 2),
506 (GPIO4<'_>, 3),
507 (GPIO5<'_>, 4),
508 ]
509 }
510}
511
512impl<'d, ADCI> Adc<'d, ADCI, Async>
513where
514 ADCI: RegisterAccess + 'd,
515{
516 pub fn into_blocking(self) -> Adc<'d, ADCI, Blocking> {
518 if release_async_adc() {
519 for cpu in crate::system::Cpu::all() {
521 crate::interrupt::disable(cpu, InterruptSource);
522 }
523 }
524 Adc {
525 _adc: self._adc,
526 attenuations: self.attenuations,
527 active_channel: self.active_channel,
528 _guard: self._guard,
529 _phantom: PhantomData,
530 }
531 }
532
533 pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCI, CS>) -> u16
539 where
540 ADCI: Instance,
541 PIN: super::AdcChannel,
542 CS: super::AdcCalScheme<ADCI>,
543 {
544 let channel = PIN::CHANNEL;
545 if self.attenuations[channel as usize].is_none() {
546 panic!("Channel {} is not configured reading!", channel);
547 }
548
549 ADCI::set_init_code(pin.cal_scheme.adc_cal());
551
552 let attenuation = self.attenuations[channel as usize].unwrap() as u8;
553 ADCI::config_onetime_sample(channel, attenuation);
554 ADCI::start_onetime_sample();
555
556 let adc_ready_future = AdcFuture::new(self);
558 adc_ready_future.await;
559 let converted_value = ADCI::read_data();
560
561 ADCI::reset();
572
573 pin.cal_scheme.adc_val(converted_value)
575 }
576}
577
578#[cfg(all(adc_adc1, adc_adc2))]
579static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
580
581pub(super) fn acquire_async_adc() {
582 #[cfg(all(adc_adc1, adc_adc2))]
583 ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
584}
585
586pub(super) fn release_async_adc() -> bool {
587 cfg_if::cfg_if! {
588 if #[cfg(all(adc_adc1, adc_adc2))] {
589 ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
590 } else {
591 true
592 }
593 }
594}
595
596#[handler]
597pub(crate) fn adc_interrupt_handler() {
598 let saradc = APB_SARADC::regs();
599 let interrupt_status = saradc.int_st().read();
600
601 #[cfg(adc_adc1)]
602 if interrupt_status.adc1_done().bit_is_set() {
603 unsafe { handle_async(crate::peripherals::ADC1::steal()) }
604 }
605
606 #[cfg(adc_adc2)]
607 if interrupt_status.adc2_done().bit_is_set() {
608 unsafe { handle_async(crate::peripherals::ADC2::steal()) }
609 }
610}
611
612fn handle_async<ADCI: Instance>(_instance: ADCI) {
613 ADCI::waker().wake();
614 ADCI::disable_interrupt();
615}
616
617pub trait Instance: crate::private::Sealed {
619 fn enable_interrupt();
621
622 fn disable_interrupt();
624
625 fn clear_interrupt();
627
628 fn waker() -> &'static AtomicWaker;
630}
631
632#[cfg(adc_adc1)]
633impl Instance for crate::peripherals::ADC1<'_> {
634 fn enable_interrupt() {
635 APB_SARADC::regs()
636 .int_ena()
637 .modify(|_, w| w.adc1_done().set_bit());
638 }
639
640 fn disable_interrupt() {
641 APB_SARADC::regs()
642 .int_ena()
643 .modify(|_, w| w.adc1_done().clear_bit());
644 }
645
646 fn clear_interrupt() {
647 APB_SARADC::regs()
648 .int_clr()
649 .write(|w| w.adc1_done().clear_bit_by_one());
650 }
651
652 fn waker() -> &'static AtomicWaker {
653 static WAKER: AtomicWaker = AtomicWaker::new();
654
655 &WAKER
656 }
657}
658
659#[cfg(adc_adc2)]
660impl Instance for crate::peripherals::ADC2<'_> {
661 fn enable_interrupt() {
662 APB_SARADC::regs()
663 .int_ena()
664 .modify(|_, w| w.adc2_done().set_bit());
665 }
666
667 fn disable_interrupt() {
668 APB_SARADC::regs()
669 .int_ena()
670 .modify(|_, w| w.adc2_done().clear_bit());
671 }
672
673 fn clear_interrupt() {
674 APB_SARADC::regs()
675 .int_clr()
676 .write(|w| w.adc2_done().clear_bit_by_one());
677 }
678
679 fn waker() -> &'static AtomicWaker {
680 static WAKER: AtomicWaker = AtomicWaker::new();
681
682 &WAKER
683 }
684}
685
686#[must_use = "futures do nothing unless you `.await` or poll them"]
687pub(crate) struct AdcFuture<ADCI: Instance> {
688 phantom: PhantomData<ADCI>,
689}
690
691impl<ADCI: Instance> AdcFuture<ADCI> {
692 pub fn new(_self: &super::Adc<'_, ADCI, Async>) -> Self {
693 Self {
694 phantom: PhantomData,
695 }
696 }
697}
698
699impl<ADCI: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCI> {
700 type Output = ();
701
702 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
703 if ADCI::is_done() {
704 ADCI::clear_interrupt();
705 Poll::Ready(())
706 } else {
707 ADCI::waker().register(cx.waker());
708 ADCI::enable_interrupt();
709 Poll::Pending
710 }
711 }
712}
713
714impl<ADCI: Instance> Drop for AdcFuture<ADCI> {
715 fn drop(&mut self) {
716 ADCI::disable_interrupt();
717 }
718}