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
17#[cfg(all(adc_adc1, adc_adc2))]
19use portable_atomic::{AtomicU32, Ordering};
20use procmacros::handler;
21
22pub use self::calibration::*;
23use super::{AdcCalSource, AdcConfig, Attenuation};
24#[cfg(any(esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2))]
25use crate::efuse::AdcCalibUnit;
26use crate::{
27 Async,
28 Blocking,
29 asynch::AtomicWaker,
30 interrupt::{InterruptConfigurable, InterruptHandler},
31 peripherals::{APB_SARADC, Interrupt},
32 rtc_cntl::WakeLock,
33 soc::regi2c,
34 system::{GenericPeripheralGuard, Peripheral},
35};
36
37mod calibration;
38
39cfg_select! {
45 adc_adc1 => {
46 const ADC_VAL_MASK: u16 = 0xfff;
47 const ADC_CAL_CNT_MAX: u16 = 32;
48 const ADC_CAL_CHANNEL: u16 = 15;
49 }
50 _ => {}
51}
52
53cfg_select! {
56 esp32c6 => {
57 pub(super) const NUM_ATTENS: usize = 7;
58 }
59 esp32c5 => {
60 pub(super) const NUM_ATTENS: usize = 6;
61 }
62 esp32c61 => {
63 pub(super) const NUM_ATTENS: usize = 4;
64 }
65 _ => {
66 pub(super) const NUM_ATTENS: usize = 5;
67 }
68}
69
70impl<ADCX> AdcConfig<ADCX>
71where
72 ADCX: RegisterAccess,
73{
74 pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
76 where
77 ADCX: super::CalibrationAccess,
78 {
79 let mut adc_max: u16 = 0;
80 let mut adc_min: u16 = u16::MAX;
81 let mut adc_sum: u32 = 0;
82
83 ADCX::enable_vdef(true);
84
85 ADCX::config_onetime_sample(ADC_CAL_CHANNEL as u8, atten as u8);
87
88 ADCX::connect_cal(source, true);
90
91 ADCX::calibration_init();
92 for _ in 0..ADC_CAL_CNT_MAX {
93 ADCX::set_init_code(0);
94
95 ADCX::start_onetime_sample();
97
98 while !ADCX::is_done() {}
100
101 let adc = ADCX::read_data() & ADC_VAL_MASK;
102
103 ADCX::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 ADCX::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 calibration_init();
138
139 fn set_init_code(data: u16);
141}
142
143#[cfg(adc_adc1)]
144impl RegisterAccess for crate::peripherals::ADC1<'_> {
145 fn config_onetime_sample(channel: u8, attenuation: u8) {
146 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
147 w.saradc1_onetime_sample().set_bit();
148 w.onetime_channel().bits(channel);
149 w.onetime_atten().bits(attenuation)
150 });
151 }
152
153 fn start_onetime_sample() {
154 APB_SARADC::regs()
155 .onetime_sample()
156 .modify(|_, w| w.onetime_start().set_bit());
157 }
158
159 fn is_done() -> bool {
160 APB_SARADC::regs().int_raw().read().adc1_done().bit()
161 }
162
163 fn read_data() -> u16 {
164 APB_SARADC::regs()
165 .sar1data_status()
166 .read()
167 .saradc1_data()
168 .bits() as u16
169 & 0xfff
170 }
171
172 fn reset() {
173 APB_SARADC::regs()
175 .int_clr()
176 .write(|w| w.adc1_done().clear_bit_by_one());
177
178 APB_SARADC::regs()
180 .onetime_sample()
181 .modify(|_, w| w.onetime_start().clear_bit());
182 }
183
184 fn calibration_init() {
185 regi2c::ADC_SAR1_DREF.write_field(1);
188 }
189
190 fn set_init_code(data: u16) {
191 let [msb, lsb] = data.to_be_bytes();
192
193 regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
194 regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
195 }
196}
197
198#[cfg(adc_adc1)]
199impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
200 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
201 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
202 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
203
204 fn enable_vdef(enable: bool) {
205 regi2c::ADC_SAR1_DREF.write_field(enable as _);
206 }
207
208 fn connect_cal(source: AdcCalSource, enable: bool) {
209 match source {
210 AdcCalSource::Gnd => regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as _),
211 #[cfg(not(esp32h2))]
212 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_REF.write_field(enable as _),
213 #[cfg(esp32h2)]
218 AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_GND.write_field(!enable as _),
219 }
220 }
221}
222
223#[cfg(adc_adc2)]
224impl RegisterAccess for crate::peripherals::ADC2<'_> {
225 fn config_onetime_sample(channel: u8, attenuation: u8) {
226 APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
227 w.saradc2_onetime_sample().set_bit();
228 w.onetime_channel().bits(channel);
229 w.onetime_atten().bits(attenuation)
230 });
231 }
232
233 fn start_onetime_sample() {
234 APB_SARADC::regs()
235 .onetime_sample()
236 .modify(|_, w| w.onetime_start().set_bit());
237 }
238
239 fn is_done() -> bool {
240 APB_SARADC::regs().int_raw().read().adc2_done().bit()
241 }
242
243 fn read_data() -> u16 {
244 APB_SARADC::regs()
245 .sar2data_status()
246 .read()
247 .saradc2_data()
248 .bits() as u16
249 & 0xfff
250 }
251
252 fn reset() {
253 APB_SARADC::regs()
254 .int_clr()
255 .write(|w| w.adc2_done().clear_bit_by_one());
256
257 APB_SARADC::regs()
258 .onetime_sample()
259 .modify(|_, w| w.onetime_start().clear_bit());
260 }
261
262 fn calibration_init() {
263 regi2c::ADC_SAR2_DREF.write_field(1);
264 }
265
266 fn set_init_code(data: u16) {
267 let [msb, lsb] = data.to_be_bytes();
268
269 regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb as _);
270 regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb as _);
271 }
272}
273
274#[cfg(adc_adc2)]
275impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
276 const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
277 const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
278 const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
279
280 fn enable_vdef(enable: bool) {
281 regi2c::ADC_SAR2_DREF.write_field(enable as _);
282 }
283
284 fn connect_cal(source: AdcCalSource, enable: bool) {
285 match source {
286 AdcCalSource::Gnd => regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as _),
287 AdcCalSource::Ref => regi2c::ADC_SAR2_ENCAL_REF.write_field(enable as _),
288 }
289 }
290}
291
292pub struct Adc<'d, ADCX, Dm: crate::DriverMode> {
294 _adc: ADCX,
295 attenuations: [Option<Attenuation>; NUM_ATTENS],
296 active_channel: Option<u8>,
297 _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
298 _phantom: PhantomData<(Dm, &'d mut ())>,
299}
300
301impl<'d, ADCX> Adc<'d, ADCX, Blocking>
302where
303 ADCX: RegisterAccess + 'd,
304{
305 pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Self {
308 let guard = GenericPeripheralGuard::new();
309
310 APB_SARADC::regs().ctrl().modify(|_, w| unsafe {
311 w.start_force().set_bit();
312 w.start().set_bit();
313 w.sar_clk_gated().set_bit();
314 w.xpd_sar_force().bits(0b11)
315 });
316
317 Adc {
318 _adc: adc_instance,
319 attenuations: config.attenuations,
320 active_channel: None,
321 _guard: guard,
322 _phantom: PhantomData,
323 }
324 }
325
326 pub fn into_async(mut self) -> Adc<'d, ADCX, Async> {
328 acquire_async_adc();
329 self.set_interrupt_handler(adc_interrupt_handler);
330
331 ADCX::reset();
335
336 Adc {
337 _adc: self._adc,
338 attenuations: self.attenuations,
339 active_channel: self.active_channel,
340 _guard: self._guard,
341 _phantom: PhantomData,
342 }
343 }
344
345 pub fn read_oneshot<PIN, CS>(
351 &mut self,
352 pin: &mut super::AdcPin<PIN, ADCX, CS>,
353 ) -> nb::Result<u16, ()>
354 where
355 PIN: super::AdcChannel,
356 CS: super::AdcCalScheme<ADCX>,
357 {
358 if self.attenuations[pin.pin.adc_channel() as usize].is_none() {
359 panic!(
360 "Channel {} is not configured reading!",
361 pin.pin.adc_channel()
362 );
363 }
364
365 if let Some(active_channel) = self.active_channel {
366 if active_channel != pin.pin.adc_channel() {
370 return Err(nb::Error::WouldBlock);
371 }
372 } else {
373 self.active_channel = Some(pin.pin.adc_channel());
375
376 ADCX::calibration_init();
378 ADCX::set_init_code(pin.cal_scheme.adc_cal());
379
380 let channel = self.active_channel.unwrap();
381 let attenuation = self.attenuations[channel as usize].unwrap() as u8;
382 ADCX::config_onetime_sample(channel, attenuation);
383 ADCX::start_onetime_sample();
384
385 #[cfg(esp32c6)]
388 {
389 crate::rom::ets_delay_us(40);
390 ADCX::start_onetime_sample();
391 }
392 }
393
394 let conversion_finished = ADCX::is_done();
396 if !conversion_finished {
397 return Err(nb::Error::WouldBlock);
398 }
399
400 let converted_value = ADCX::read_data();
402 ADCX::reset();
403
404 let converted_value = pin.cal_scheme.adc_val(converted_value);
406
407 self.active_channel = None;
419
420 Ok(converted_value)
421 }
422}
423
424impl<ADCX> crate::private::Sealed for Adc<'_, ADCX, Blocking> {}
425
426impl<ADCX> InterruptConfigurable for Adc<'_, ADCX, Blocking> {
427 fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
428 for core in crate::system::Cpu::other() {
429 crate::interrupt::disable(core, InterruptSource);
430 }
431 crate::interrupt::bind_handler(InterruptSource, handler);
432 }
433}
434
435#[cfg(adc_adc1)]
436impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
437 fn init_code(atten: Attenuation) -> Option<u16> {
438 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC1, atten)
439 }
440
441 fn cal_mv(atten: Attenuation) -> u16 {
442 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC1, atten)
443 }
444
445 fn cal_code(atten: Attenuation) -> Option<u16> {
446 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC1, atten)
447 }
448
449 #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))]
450 fn cal_chan_compens(atten: Attenuation, channel: u8) -> Option<i32> {
451 crate::efuse::rtc_calib_get_chan_compens(AdcCalibUnit::ADC1, channel, atten)
452 }
453}
454
455#[cfg(adc_adc2)]
456impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
457 fn init_code(atten: Attenuation) -> Option<u16> {
458 crate::efuse::rtc_calib_init_code(AdcCalibUnit::ADC2, atten)
459 }
460
461 fn cal_mv(atten: Attenuation) -> u16 {
462 crate::efuse::rtc_calib_cal_mv(AdcCalibUnit::ADC2, atten)
463 }
464
465 fn cal_code(atten: Attenuation) -> Option<u16> {
466 crate::efuse::rtc_calib_cal_code(AdcCalibUnit::ADC2, atten)
467 }
468}
469
470impl<'d, ADCX> Adc<'d, ADCX, Async>
471where
472 ADCX: RegisterAccess + 'd,
473{
474 pub fn into_blocking(self) -> Adc<'d, ADCX, Blocking> {
476 if release_async_adc() {
477 for cpu in crate::system::Cpu::all() {
479 crate::interrupt::disable(cpu, InterruptSource);
480 }
481 }
482 Adc {
483 _adc: self._adc,
484 attenuations: self.attenuations,
485 active_channel: self.active_channel,
486 _guard: self._guard,
487 _phantom: PhantomData,
488 }
489 }
490
491 pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCX, CS>) -> u16
497 where
498 ADCX: Instance,
499 PIN: super::AdcChannel,
500 CS: super::AdcCalScheme<ADCX>,
501 {
502 let channel = pin.pin.adc_channel();
503 if self.attenuations[channel as usize].is_none() {
504 panic!("Channel {} is not configured reading!", channel);
505 }
506
507 ADCX::calibration_init();
509 ADCX::set_init_code(pin.cal_scheme.adc_cal());
510
511 let attenuation = self.attenuations[channel as usize].unwrap() as u8;
512 ADCX::config_onetime_sample(channel, attenuation);
513 ADCX::start_onetime_sample();
514
515 let adc_ready_future = AdcFuture::new(self);
517 adc_ready_future.await;
518 let converted_value = ADCX::read_data();
519
520 ADCX::reset();
531
532 pin.cal_scheme.adc_val(converted_value)
534 }
535}
536
537#[cfg(all(adc_adc1, adc_adc2))]
538static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
539
540pub(super) fn acquire_async_adc() {
541 #[cfg(all(adc_adc1, adc_adc2))]
542 ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
543}
544
545pub(super) fn release_async_adc() -> bool {
546 cfg_select! {
547 all(adc_adc1, adc_adc2) => ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1,
548 _ => true,
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<ADCX: Instance>(_instance: ADCX) {
569 ADCX::waker().wake();
570 ADCX::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<ADCX: Instance> {
644 phantom: PhantomData<ADCX>,
645 _wake_lock: WakeLock,
646}
647
648impl<ADCX: Instance> AdcFuture<ADCX> {
649 pub fn new(_self: &super::Adc<'_, ADCX, Async>) -> Self {
650 Self {
651 phantom: PhantomData,
652 _wake_lock: WakeLock::new(),
653 }
654 }
655}
656
657impl<ADCX: Instance + super::RegisterAccess> core::future::Future for AdcFuture<ADCX> {
658 type Output = ();
659
660 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
661 if ADCX::is_done() {
662 ADCX::clear_interrupt();
663 Poll::Ready(())
664 } else {
665 ADCX::waker().register(cx.waker());
666 ADCX::listen();
667 Poll::Pending
668 }
669 }
670}
671
672impl<ADCX: Instance> Drop for AdcFuture<ADCX> {
673 fn drop(&mut self) {
674 ADCX::unlisten();
675 }
676}