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, esp32c5, esp32c6, esp32h2))]
24use crate::efuse::AdcCalibUnit;
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! {
43 if #[cfg(adc_adc1)] {
44 const ADC_VAL_MASK: u16 = 0xfff;
45 const ADC_CAL_CNT_MAX: u16 = 32;
46 const ADC_CAL_CHANNEL: u16 = 15;
47 }
48}
49
50cfg_if::cfg_if! {
53 if #[cfg(esp32c6)] {
54 pub(super) const NUM_ATTENS: usize = 7;
55 } else if #[cfg(esp32c5)] {
56 pub(super) const NUM_ATTENS: usize = 6;
57 } else {
58 pub(super) const NUM_ATTENS: usize = 5;
59 }
60}
61
62impl<ADCI> AdcConfig<ADCI>
63where
64 ADCI: RegisterAccess,
65{
66 pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
68 where
69 ADCI: super::CalibrationAccess,
70 {
71 let mut adc_max: u16 = 0;
72 let mut adc_min: u16 = u16::MAX;
73 let mut adc_sum: u32 = 0;
74
75 ADCI::enable_vdef(true);
76
77 ADCI::config_onetime_sample(ADC_CAL_CHANNEL as u8, atten as u8);
79
80 ADCI::connect_cal(source, true);
82
83 ADCI::calibration_init();
84 for _ in 0..ADC_CAL_CNT_MAX {
85 ADCI::set_init_code(0);
86
87 ADCI::start_onetime_sample();
89
90 while !ADCI::is_done() {}
92
93 let adc = ADCI::read_data() & ADC_VAL_MASK;
94
95 ADCI::reset();
96
97 adc_sum += adc as u32;
98 adc_max = adc.max(adc_max);
99 adc_min = adc.min(adc_min);
100 }
101
102 let cal_val = (adc_sum - adc_max as u32 - adc_min as u32) as u16 / (ADC_CAL_CNT_MAX - 2);
103
104 ADCI::connect_cal(source, false);
106
107 cal_val
108 }
109}
110
111#[doc(hidden)]
112pub trait RegisterAccess {
113 fn config_onetime_sample(channel: u8, attenuation: u8);
115
116 fn start_onetime_sample();
118
119 fn is_done() -> bool;
121
122 fn read_data() -> u16;
124
125 fn reset();
127
128 fn calibration_init();
130
131 fn set_init_code(data: u16);
133}
134
135#[cfg(adc_adc1)]
136impl RegisterAccess for crate::peripherals::ADC1<'_> {
137 fn config_onetime_sample(channel: u8, attenuation: u8) {
138 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
139 w.saradc1_onetime_sample().set_bit();
140 w.onetime_channel().bits(channel);
141 w.onetime_atten().bits(attenuation)
142 });
143 }
144
145 fn start_onetime_sample() {
146 APB_SARADC::regs()
147 .onetime_sample()
148 .modify(|_, w| w.onetime_start().set_bit());
149 }
150
151 fn is_done() -> bool {
152 APB_SARADC::regs().int_raw().read().adc1_done().bit()
153 }
154
155 fn read_data() -> u16 {
156 APB_SARADC::regs()
157 .sar1data_status()
158 .read()
159 .saradc1_data()
160 .bits() as u16
161 & 0xfff
162 }
163
164 fn reset() {
165 APB_SARADC::regs()
167 .int_clr()
168 .write(|w| w.adc1_done().clear_bit_by_one());
169
170 APB_SARADC::regs()
172 .onetime_sample()
173 .modify(|_, w| w.onetime_start().clear_bit());
174 }
175
176 #[cfg(any(esp32c2, esp32c3, esp32c5, esp32c6, esp32h2))]
180 fn calibration_init() {
181 regi2c::ADC_SAR1_DREF.write_field(1);
184 }
185
186 fn set_init_code(data: u16) {
187 let [msb, lsb] = data.to_be_bytes();
188
189 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
190 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
191 }
192}
193
194#[cfg(adc_adc1)]
195impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
196 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
197 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
198 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
199
200 fn enable_vdef(enable: bool) {
201 regi2c::ADC_SAR1_DREF.write_field(enable as _);
202 }
203
204 fn connect_cal(source: AdcCalSource, enable: bool) {
205 match source {
206 AdcCalSource::Gnd => regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as _),
207 #[cfg(not(esp32h2))]
208 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_REF.write_field(enable as _),
209 #[cfg(esp32h2)]
214 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_GND.write_field(!enable as _),
215 }
216 }
217}
218
219#[cfg(adc_adc2)]
220impl RegisterAccess for crate::peripherals::ADC2<'_> {
221 fn config_onetime_sample(channel: u8, attenuation: u8) {
222 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
223 w.saradc2_onetime_sample().set_bit();
224 w.onetime_channel().bits(channel);
225 w.onetime_atten().bits(attenuation)
226 });
227 }
228
229 fn start_onetime_sample() {
230 APB_SARADC::regs()
231 .onetime_sample()
232 .modify(|_, w| w.onetime_start().set_bit());
233 }
234
235 fn is_done() -> bool {
236 APB_SARADC::regs().int_raw().read().adc2_done().bit()
237 }
238
239 fn read_data() -> u16 {
240 APB_SARADC::regs()
241 .sar2data_status()
242 .read()
243 .saradc2_data()
244 .bits() as u16
245 & 0xfff
246 }
247
248 fn reset() {
249 APB_SARADC::regs()
250 .int_clr()
251 .write(|w| w.adc2_done().clear_bit_by_one());
252
253 APB_SARADC::regs()
254 .onetime_sample()
255 .modify(|_, w| w.onetime_start().clear_bit());
256 }
257
258 #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))]
259 fn calibration_init() {
260 regi2c::ADC_SAR2_DREF.write_field(1);
261 }
262
263 fn set_init_code(data: u16) {
264 let [msb, lsb] = data.to_be_bytes();
265
266 regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb as _);
267 regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb as _);
268 }
269}
270
271#[cfg(adc_adc2)]
272impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
273 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
274 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
275 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
276
277 fn enable_vdef(enable: bool) {
278 regi2c::ADC_SAR2_DREF.write_field(enable as _);
279 }
280
281 fn connect_cal(source: AdcCalSource, enable: bool) {
282 match source {
283 AdcCalSource::Gnd => regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as _),
284 AdcCalSource::Ref => regi2c::ADC_SAR2_ENCAL_REF.write_field(enable as _),
285 }
286 }
287}
288
289pub struct Adc<'d, ADCI, Dm: crate::DriverMode> {
291 _adc: ADCI,
292 attenuations: [Option<Attenuation>; NUM_ATTENS],
293 active_channel: Option<u8>,
294 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
295 _phantom: PhantomData<(Dm, &'d mut ())>,
296}
297
298impl<'d, ADCI> Adc<'d, ADCI, Blocking>
299where
300 ADCI: RegisterAccess + 'd,
301{
302 pub fn new(adc_instance: ADCI, config: AdcConfig<ADCI>) -> Self {
305 let guard = GenericPeripheralGuard::new();
306
307 APB_SARADC::regs().ctrl().modify(|_, w| unsafe {
308 w.start_force().set_bit();
309 w.start().set_bit();
310 w.sar_clk_gated().set_bit();
311 w.xpd_sar_force().bits(0b11)
312 });
313
314 Adc {
315 _adc: adc_instance,
316 attenuations: config.attenuations,
317 active_channel: None,
318 _guard: guard,
319 _phantom: PhantomData,
320 }
321 }
322
323 pub fn into_async(mut self) -> Adc<'d, ADCI, Async> {
325 acquire_async_adc();
326 self.set_interrupt_handler(adc_interrupt_handler);
327
328 ADCI::reset();
332
333 Adc {
334 _adc: self._adc,
335 attenuations: self.attenuations,
336 active_channel: self.active_channel,
337 _guard: self._guard,
338 _phantom: PhantomData,
339 }
340 }
341
342 pub fn read_oneshot<PIN, CS>(
348 &mut self,
349 pin: &mut super::AdcPin<PIN, ADCI, CS>,
350 ) -> nb::Result<u16, ()>
351 where
352 PIN: super::AdcChannel,
353 CS: super::AdcCalScheme<ADCI>,
354 {
355 if self.attenuations[pin.pin.adc_channel() as usize].is_none() {
356 panic!(
357 "Channel {} is not configured reading!",
358 pin.pin.adc_channel()
359 );
360 }
361
362 if let Some(active_channel) = self.active_channel {
363 if active_channel != pin.pin.adc_channel() {
367 return Err(nb::Error::WouldBlock);
368 }
369 } else {
370 self.active_channel = Some(pin.pin.adc_channel());
372
373 ADCI::calibration_init();
375 ADCI::set_init_code(pin.cal_scheme.adc_cal());
376
377 let channel = self.active_channel.unwrap();
378 let attenuation = self.attenuations[channel as usize].unwrap() as u8;
379 ADCI::config_onetime_sample(channel, attenuation);
380 ADCI::start_onetime_sample();
381
382 #[cfg(esp32c6)]
385 {
386 crate::rom::ets_delay_us(40);
387 ADCI::start_onetime_sample();
388 }
389 }
390
391 let conversion_finished = ADCI::is_done();
393 if !conversion_finished {
394 return Err(nb::Error::WouldBlock);
395 }
396
397 let converted_value = ADCI::read_data();
399 ADCI::reset();
400
401 let converted_value = pin.cal_scheme.adc_val(converted_value);
403
404 self.active_channel = None;
416
417 Ok(converted_value)
418 }
419}
420
421impl<ADCI> crate::private::Sealed for Adc<'_, ADCI, Blocking> {}
422
423impl<ADCI> InterruptConfigurable for Adc<'_, ADCI, Blocking> {
424 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
425 for core in crate::system::Cpu::other() {
426 crate::interrupt::disable(core, InterruptSource);
427 }
428 crate::interrupt::bind_handler(InterruptSource, handler);
429 }
430}
431
432#[cfg(adc_adc1)]
433impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
434 fn init_code(atten: Attenuation) -> Option<u16> {
435 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
436 }
437
438 fn cal_mv(atten: Attenuation) -> u16 {
439 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
440 }
441
442 fn cal_code(atten: Attenuation) -> Option<u16> {
443 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
444 }
445
446 #[cfg(esp32c5)]
447 fn cal_chan_compens(atten: Attenuation, channel: u16) -> Option<i32> {
448 crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC1, channel, atten)
449 }
450}
451
452#[cfg(adc_adc2)]
453impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
454 fn init_code(atten: Attenuation) -> Option<u16> {
455 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC2, atten)
456 }
457
458 fn cal_mv(atten: Attenuation) -> u16 {
459 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC2, atten)
460 }
461
462 fn cal_code(atten: Attenuation) -> Option<u16> {
463 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC2, atten)
464 }
465}
466
467impl<'d, ADCI> Adc<'d, ADCI, Async>
468where
469 ADCI: RegisterAccess + 'd,
470{
471 pub fn into_blocking(self) -> Adc<'d, ADCI, Blocking> {
473 if release_async_adc() {
474 for cpu in crate::system::Cpu::all() {
476 crate::interrupt::disable(cpu, InterruptSource);
477 }
478 }
479 Adc {
480 _adc: self._adc,
481 attenuations: self.attenuations,
482 active_channel: self.active_channel,
483 _guard: self._guard,
484 _phantom: PhantomData,
485 }
486 }
487
488 pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCI, CS>) -> u16
494 where
495 ADCI: Instance,
496 PIN: super::AdcChannel,
497 CS: super::AdcCalScheme<ADCI>,
498 {
499 let channel = pin.pin.adc_channel();
500 if self.attenuations[channel as usize].is_none() {
501 panic!("Channel {} is not configured reading!", channel);
502 }
503
504 ADCI::calibration_init();
506 ADCI::set_init_code(pin.cal_scheme.adc_cal());
507
508 let attenuation = self.attenuations[channel as usize].unwrap() as u8;
509 ADCI::config_onetime_sample(channel, attenuation);
510 ADCI::start_onetime_sample();
511
512 let adc_ready_future = AdcFuture::new(self);
514 adc_ready_future.await;
515 let converted_value = ADCI::read_data();
516
517 ADCI::reset();
528
529 pin.cal_scheme.adc_val(converted_value)
531 }
532}
533
534#[cfg(all(adc_adc1, adc_adc2))]
535static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
536
537pub(super) fn acquire_async_adc() {
538 #[cfg(all(adc_adc1, adc_adc2))]
539 ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
540}
541
542pub(super) fn release_async_adc() -> bool {
543 cfg_if::cfg_if! {
544 if #[cfg(all(adc_adc1, adc_adc2))] {
545 ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
546 } else {
547 true
548 }
549 }
550}
551
552#[handler]
553pub(crate) fn adc_interrupt_handler() {
554 let saradc = APB_SARADC::regs();
555 let interrupt_status = saradc.int_st().read();
556
557 #[cfg(adc_adc1)]
558 if interrupt_status.adc1_done().bit_is_set() {
559 unsafe { handle_async(crate::peripherals::ADC1::steal()) }
560 }
561
562 #[cfg(adc_adc2)]
563 if interrupt_status.adc2_done().bit_is_set() {
564 unsafe { handle_async(crate::peripherals::ADC2::steal()) }
565 }
566}
567
568fn handle_async<ADCI: Instance>(_instance: ADCI) {
569 ADCI::waker().wake();
570 ADCI::unlisten();
571}
572
573pub trait Instance: crate::private::Sealed {
575 fn listen();
577
578 fn unlisten();
580
581 fn clear_interrupt();
583
584 fn waker() -> &'static AtomicWaker;
586}
587
588#[cfg(adc_adc1)]
589impl Instance for crate::peripherals::ADC1<'_> {
590 fn listen() {
591 APB_SARADC::regs()
592 .int_ena()
593 .modify(|_, w| w.adc1_done().set_bit());
594 }
595
596 fn unlisten() {
597 APB_SARADC::regs()
598 .int_ena()
599 .modify(|_, w| w.adc1_done().clear_bit());
600 }
601
602 fn clear_interrupt() {
603 APB_SARADC::regs()
604 .int_clr()
605 .write(|w| w.adc1_done().clear_bit_by_one());
606 }
607
608 fn waker() -> &'static AtomicWaker {
609 static WAKER: AtomicWaker = AtomicWaker::new();
610
611 &WAKER
612 }
613}
614
615#[cfg(adc_adc2)]
616impl Instance for crate::peripherals::ADC2<'_> {
617 fn listen() {
618 APB_SARADC::regs()
619 .int_ena()
620 .modify(|_, w| w.adc2_done().set_bit());
621 }
622
623 fn unlisten() {
624 APB_SARADC::regs()
625 .int_ena()
626 .modify(|_, w| w.adc2_done().clear_bit());
627 }
628
629 fn clear_interrupt() {
630 APB_SARADC::regs()
631 .int_clr()
632 .write(|w| w.adc2_done().clear_bit_by_one());
633 }
634
635 fn waker() -> &'static AtomicWaker {
636 static WAKER: AtomicWaker = AtomicWaker::new();
637
638 &WAKER
639 }
640}
641
642#[must_use = "futures do nothing unless you `.await` or poll them"]
643pub(crate) struct AdcFuture<ADCI: Instance> {
644 phantom: PhantomData<ADCI>,
645}
646
647impl<ADCI: Instance> AdcFuture<ADCI> {
648 pub fn new(_self: &super::Adc<'_, ADCI, Async>) -> Self {
649 Self {
650 phantom: PhantomData,
651 }
652 }
653}
654
655impl<ADCI: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCI> {
656 type Output = ();
657
658 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
659 if ADCI::is_done() {
660 ADCI::clear_interrupt();
661 Poll::Ready(())
662 } else {
663 ADCI::waker().register(cx.waker());
664 ADCI::listen();
665 Poll::Pending
666 }
667 }
668}
669
670impl<ADCI: Instance> Drop for AdcFuture<ADCI> {
671 fn drop(&mut self) {
672 ADCI::unlisten();
673 }
674}