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