1use core::{
2 marker::PhantomData,
3 sync::atomic::{AtomicBool, Ordering},
4};
5
6use super::{AdcCalScheme, AdcConfig, Attenuation};
7use crate::{
8 peripherals::{ADC1, ADC2, SENS},
9 private,
10};
11
12pub(super) const NUM_ATTENS: usize = 10;
13
14mod calibration;
15pub use self::calibration::*;
16
17static ADC2_IN_USE: AtomicBool = AtomicBool::new(false);
20
21#[derive(Debug)]
23pub enum Error {
24 Adc2InUse,
26}
27
28#[doc(hidden)]
29pub fn try_claim_adc2(_: private::Internal) -> Result<(), Error> {
31 if ADC2_IN_USE.fetch_or(true, Ordering::Relaxed) {
32 Err(Error::Adc2InUse)
33 } else {
34 Ok(())
35 }
36}
37
38#[doc(hidden)]
39pub fn release_adc2(_: private::Internal) {
41 ADC2_IN_USE.store(false, Ordering::Relaxed);
42}
43
44#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47#[allow(clippy::enum_variant_names, reason = "unit of measurement")]
48pub enum Resolution {
49 _9Bit,
51 _10Bit,
53 _11Bit,
55 #[default]
57 _12Bit,
58}
59
60#[doc(hidden)]
61pub trait RegisterAccess {
62 fn set_resolution(resolution: u8);
63
64 fn set_attenuation(channel: usize, attenuation: u8);
65
66 fn clear_dig_force();
67
68 fn set_start_force();
69
70 fn set_en_pad_force();
71
72 fn set_en_pad(channel: u8);
73
74 fn clear_start_sar();
75
76 fn set_start_sar();
77
78 fn read_done_sar() -> bool;
79
80 fn read_data_sar() -> u16;
81
82 fn instance_number() -> u8;
83}
84
85impl RegisterAccess for ADC1<'_> {
86 fn set_resolution(resolution: u8) {
87 SENS::regs()
88 .sar_start_force()
89 .modify(|_, w| unsafe { w.sar1_bit_width().bits(resolution) });
90 SENS::regs()
91 .sar_read_ctrl()
92 .modify(|_, w| unsafe { w.sar1_sample_bit().bits(resolution) });
93 }
94
95 fn set_attenuation(channel: usize, attenuation: u8) {
96 SENS::regs().sar_atten1().modify(|r, w| {
97 let new_value = (r.bits() & !(0b11 << (channel * 2)))
98 | (((attenuation & 0b11) as u32) << (channel * 2));
99
100 unsafe { w.sar1_atten().bits(new_value) }
101 });
102 }
103
104 fn clear_dig_force() {
105 SENS::regs()
106 .sar_read_ctrl()
107 .modify(|_, w| w.sar1_dig_force().clear_bit());
108 }
109
110 fn set_start_force() {
111 SENS::regs()
112 .sar_meas_start1()
113 .modify(|_, w| w.meas1_start_force().set_bit());
114 }
115
116 fn set_en_pad_force() {
117 SENS::regs()
118 .sar_meas_start1()
119 .modify(|_, w| w.sar1_en_pad_force().set_bit());
120 }
121
122 fn set_en_pad(channel: u8) {
123 SENS::regs()
124 .sar_meas_start1()
125 .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
126 }
127
128 fn clear_start_sar() {
129 SENS::regs()
130 .sar_meas_start1()
131 .modify(|_, w| w.meas1_start_sar().clear_bit());
132 }
133
134 fn set_start_sar() {
135 SENS::regs()
136 .sar_meas_start1()
137 .modify(|_, w| w.meas1_start_sar().set_bit());
138 }
139
140 fn read_done_sar() -> bool {
141 SENS::regs()
142 .sar_meas_start1()
143 .read()
144 .meas1_done_sar()
145 .bit_is_set()
146 }
147
148 fn read_data_sar() -> u16 {
149 SENS::regs()
150 .sar_meas_start1()
151 .read()
152 .meas1_data_sar()
153 .bits()
154 }
155
156 fn instance_number() -> u8 {
157 1
158 }
159}
160
161impl RegisterAccess for ADC2<'_> {
162 fn set_resolution(resolution: u8) {
163 SENS::regs()
164 .sar_start_force()
165 .modify(|_, w| unsafe { w.sar2_bit_width().bits(resolution) });
166 SENS::regs()
167 .sar_read_ctrl2()
168 .modify(|_, w| unsafe { w.sar2_sample_bit().bits(resolution) });
169 }
170
171 fn set_attenuation(channel: usize, attenuation: u8) {
172 SENS::regs().sar_atten2().modify(|r, w| {
173 let new_value = (r.bits() & !(0b11 << (channel * 2)))
174 | (((attenuation & 0b11) as u32) << (channel * 2));
175
176 unsafe { w.sar2_atten().bits(new_value) }
177 });
178 }
179
180 fn clear_dig_force() {
181 SENS::regs()
182 .sar_read_ctrl2()
183 .modify(|_, w| w.sar2_dig_force().clear_bit());
184 }
185
186 fn set_start_force() {
187 SENS::regs()
188 .sar_meas_start2()
189 .modify(|_, w| w.meas2_start_force().set_bit());
190 }
191
192 fn set_en_pad_force() {
193 SENS::regs()
194 .sar_meas_start2()
195 .modify(|_, w| w.sar2_en_pad_force().set_bit());
196 }
197
198 fn set_en_pad(channel: u8) {
199 SENS::regs()
200 .sar_meas_start2()
201 .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) });
202 }
203
204 fn clear_start_sar() {
205 SENS::regs()
206 .sar_meas_start2()
207 .modify(|_, w| w.meas2_start_sar().clear_bit());
208 }
209
210 fn set_start_sar() {
211 SENS::regs()
212 .sar_meas_start2()
213 .modify(|_, w| w.meas2_start_sar().set_bit());
214 }
215
216 fn read_done_sar() -> bool {
217 SENS::regs()
218 .sar_meas_start2()
219 .read()
220 .meas2_done_sar()
221 .bit_is_set()
222 }
223
224 fn read_data_sar() -> u16 {
225 SENS::regs()
226 .sar_meas_start2()
227 .read()
228 .meas2_data_sar()
229 .bits()
230 }
231
232 fn instance_number() -> u8 {
233 2
234 }
235}
236
237pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
239 _adc: ADC,
240 attenuations: [Option<Attenuation>; NUM_ATTENS],
241 active_channel: Option<u8>,
242 resolution_bits: u8,
243 _phantom: PhantomData<(Dm, &'d mut ())>,
244}
245
246impl<'d, ADCX> Adc<'d, ADCX, crate::Blocking>
247where
248 ADCX: RegisterAccess + 'd,
249{
250 pub fn new(adc_instance: ADCX, config: AdcConfig<ADCX>) -> Self {
258 if ADCX::instance_number() == 2 && try_claim_adc2(private::Internal).is_err() {
259 panic!(
260 "ADC2 is already in use by Radio. On ESP32, ADC2 cannot be used simultaneously with Wi-Fi or Bluetooth."
261 );
262 }
263
264 let sensors = SENS::regs();
265
266 ADCX::set_resolution(config.resolution as u8);
268
269 let attenuations = config.attenuations;
271
272 for (channel, attenuation) in attenuations.iter().enumerate() {
273 if let Some(attenuation) = attenuation {
274 ADCX::set_attenuation(channel, *attenuation as u8);
275 }
276 }
277
278 ADCX::clear_dig_force();
280 ADCX::set_start_force();
281 ADCX::set_en_pad_force();
282 sensors.sar_touch_ctrl1().modify(|_, w| {
283 w.xpd_hall_force().set_bit();
284 w.hall_phase_force().set_bit()
285 });
286
287 sensors.sar_meas_wait2().modify(|_, w| unsafe {
288 w.force_xpd_sar().bits(0b11);
290 w.force_xpd_amp().bits(0b10)
292 });
293 sensors.sar_meas_ctrl().modify(|_, w| unsafe {
294 w.amp_rst_fb_fsm().bits(0);
295 w.amp_short_ref_fsm().bits(0);
296 w.amp_short_ref_gnd_fsm().bits(0)
297 });
298 sensors.sar_meas_wait1().modify(|_, w| unsafe {
299 w.sar_amp_wait1().bits(1);
300 w.sar_amp_wait2().bits(1)
301 });
302 sensors
303 .sar_meas_wait2()
304 .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) });
305
306 sensors
309 .sar_read_ctrl()
310 .modify(|_, w| w.sar1_data_inv().set_bit());
311 sensors
312 .sar_read_ctrl2()
313 .modify(|_, w| w.sar2_data_inv().set_bit());
314
315 Adc {
316 _adc: adc_instance,
317 attenuations: config.attenuations,
318 active_channel: None,
319 resolution_bits: match config.resolution {
320 Resolution::_9Bit => 9,
321 Resolution::_10Bit => 10,
322 Resolution::_11Bit => 11,
323 Resolution::_12Bit => 12,
324 },
325 _phantom: PhantomData,
326 }
327 }
328
329 pub fn read_oneshot<PIN, CS>(
335 &mut self,
336 pin: &mut super::AdcPin<PIN, ADCX, CS>,
337 ) -> nb::Result<u16, ()>
338 where
339 PIN: super::AdcChannel,
340 CS: AdcCalScheme<ADCX>,
341 {
342 if self.attenuations[pin.pin.adc_channel() as usize].is_none() {
343 panic!(
344 "Channel {} is not configured reading!",
345 pin.pin.adc_channel()
346 );
347 }
348
349 if let Some(active_channel) = self.active_channel {
350 if active_channel != pin.pin.adc_channel() {
354 return Err(nb::Error::WouldBlock);
355 }
356 } else {
357 self.active_channel = Some(pin.pin.adc_channel());
359
360 ADCX::set_en_pad(pin.pin.adc_channel());
361
362 ADCX::clear_start_sar();
363 ADCX::set_start_sar();
364 }
365
366 let conversion_finished = ADCX::read_done_sar();
368 if !conversion_finished {
369 return Err(nb::Error::WouldBlock);
370 }
371
372 let mut converted_value = ADCX::read_data_sar() as u32;
374 converted_value <<= 12 - self.resolution_bits;
375 if converted_value > 4095 {
376 converted_value = 4095;
377 }
378
379 self.active_channel = None;
381
382 Ok(pin.cal_scheme.adc_val(converted_value as u16))
383 }
384}
385
386impl Drop for ADC2<'_> {
387 fn drop(&mut self) {
388 release_adc2(private::Internal);
389 }
390}