atsamd_hal/peripherals/adc/d11/
mod.rs1use super::{
2 ADC_SETTINGS_INTERNAL_READ, ADC_SETTINGS_INTERNAL_READ_D21_TEMP, Accumulation, Adc,
3 AdcInstance, AdcSettings, CpuVoltageSource, Error, Flags, PrimaryAdc, SampleCount,
4};
5
6#[cfg(feature = "async")]
7use super::{FutureAdc, async_api};
8
9use crate::{calibration, pac};
10use pac::Peripherals;
11use pac::Sysctrl;
12use pac::adc::inputctrl::Gainselect;
13pub mod pin;
14
15pub struct Adc0 {
17 _adc: pac::Adc,
18}
19
20impl PrimaryAdc for Adc0 {}
21
22impl AdcInstance for Adc0 {
23 type Instance = pac::Adc;
24
25 #[cfg(feature = "async")]
26 type Interrupt = crate::async_hal::interrupts::ADC;
27
28 #[inline]
29 fn peripheral_reg_block(p: &mut Peripherals) -> &pac::adc::RegisterBlock {
30 &p.adc
31 }
32
33 #[inline]
34 fn enable_pm(pm: &mut pac::Pm) {
35 pm.apbcmask().modify(|_, w| w.adc_().set_bit());
36 }
37
38 #[inline]
39 fn calibrate(instance: &Self::Instance) {
40 instance.calib().write(|w| unsafe {
41 w.bias_cal().bits(calibration::adc_bias_cal());
42 w.linearity_cal().bits(calibration::adc_linearity_cal())
43 });
44 }
45
46 #[cfg(feature = "async")]
47 #[inline]
48 fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
49 use super::async_api;
50 &async_api::ADC_WAKERS[0]
51 }
52}
53
54impl<I: AdcInstance> Adc<I> {
55 #[inline]
56 pub(crate) fn configure(&mut self, cfg: AdcSettings) {
58 if cfg != self.cfg {
59 self.discard = true;
61 }
62 self.power_down();
63 self.sync();
64 I::calibrate(&self.adc);
65 self.sync();
66 self.adc
67 .ctrlb()
68 .modify(|_, w| w.prescaler().variant(cfg.clk_divider));
69 self.sync();
70 self.adc
71 .ctrlb()
72 .modify(|_, w| w.ressel().variant(cfg.accumulation.resolution()));
73 self.sync();
74
75 self.adc
76 .sampctrl()
77 .modify(|_, w| unsafe { w.samplen().bits(cfg.sample_clock_cycles.saturating_sub(1)) }); self.sync();
79 self.adc.inputctrl().modify(|_, w| {
80 w.muxneg().gnd();
81 w.gain().variant(Gainselect::Div2)
82 }); self.sync();
84 let (sample_cnt, adjres) = match cfg.accumulation {
85 Accumulation::Single(_) => (SampleCount::_1, 0),
87 Accumulation::Average(cnt) => (cnt, core::cmp::min(cnt as u8, 0x04)),
91 Accumulation::Summed(cnt) => (cnt, 0),
94 };
95 self.adc.avgctrl().write(|w| {
97 w.samplenum().variant(sample_cnt);
98 unsafe { w.adjres().bits(adjres) }
99 });
100 self.sync();
101 self.set_reference(cfg.vref);
102 self.sync();
103 self.adc.ctrla().modify(|_, w| w.enable().set_bit());
104 self.sync();
105 self.cfg = cfg;
106 self.power_up();
107 }
108
109 #[inline]
110 pub(super) fn sync(&self) {
111 while self.adc.status().read().syncbusy().bit_is_set() {
112 core::hint::spin_loop();
113 }
114 }
115
116 #[inline]
117 pub(super) fn power_up(&mut self) {
118 self.adc.ctrla().modify(|_, w| w.enable().set_bit());
119 self.sync();
120 }
121
122 #[inline]
123 #[allow(dead_code)]
124 pub(super) fn power_down(&mut self) {
125 self.adc.ctrla().modify(|_, w| w.enable().clear_bit());
126 self.sync();
127 }
128
129 #[inline]
130 pub(super) fn start_conversion(&mut self) {
131 self.adc.swtrig().modify(|_, w| w.start().set_bit());
132 self.sync();
133 }
134
135 #[inline]
136 pub(super) fn enable_freerunning(&mut self) {
137 self.adc.ctrlb().modify(|_, w| w.freerun().set_bit());
138 self.sync();
139 }
140
141 #[inline]
142 pub(super) fn disable_freerunning(&mut self) {
143 self.adc.ctrlb().modify(|_, w| w.freerun().clear_bit());
144 self.sync();
145 }
146
147 #[inline]
148 pub(super) fn read_flags(&self) -> Flags {
149 let bits = self.adc.intflag().read().bits();
150 Flags::from_bits_truncate(bits)
151 }
152
153 #[cfg(feature = "async")]
154 #[inline]
156 pub(super) fn clear_flags(&mut self, flags: &Flags) {
157 unsafe {
158 self.adc.intflag().write(|w| w.bits(flags.bits()));
159 }
160 }
161
162 #[inline]
164 pub(super) fn clear_all_flags(&mut self) {
165 unsafe {
166 self.adc.intflag().write(|w| w.bits(0b1111));
167 }
168 }
169
170 #[inline]
172 pub(super) fn check_overrun(&mut self, flags: &Flags) -> Result<(), Error> {
173 if flags.contains(Flags::OVERRUN) {
174 Err(Error::BufferOverrun)
175 } else {
176 Ok(())
177 }
178 }
179
180 #[inline]
182 #[allow(dead_code)]
183 pub(super) fn enable_interrupts(&mut self, flags: Flags) {
184 unsafe { self.adc.intenset().write(|w| w.bits(flags.bits())) };
185 }
186
187 #[inline]
189 pub(super) fn disable_interrupts(&mut self, flags: Flags) {
190 unsafe { self.adc.intenclr().write(|w| w.bits(flags.bits())) };
191 }
192
193 #[inline]
194 pub(super) fn conversion_result(&self) -> u16 {
195 self.adc.result().read().result().bits()
196 }
197
198 #[inline]
199 pub(super) fn mux(&mut self, ch: u8) {
200 self.adc.inputctrl().modify(|r, w| {
201 if r.muxpos().bits() != ch {
202 self.discard = true;
203 }
204 unsafe { w.muxpos().bits(ch) }
205 });
206 self.sync()
207 }
208
209 #[inline]
210 fn cpu_raw_to_temp(&self, reading: u16) -> f32 {
211 let room_temp = calibration::room_temp();
214 let adc_room = calibration::room_temp_adc_val() as f32;
215
216 let hot_temp = calibration::hot_temp();
217 let adc_hot = calibration::hot_temp_adc_val() as f32;
218
219 let room_int1v = 1.0 - (calibration::room_int1v_val() as f32 / 1000.0);
220 let hot_int1v = 1.0 - (calibration::hot_int1v_val() as f32 / 1000.0);
221
222 let v_adc_room = (adc_room * room_int1v) / 4095.0;
223 let v_adc_hot = (adc_hot * hot_int1v) / 4095.0;
224
225 let v_adc = reading as f32 / 4095.0; let coarse_temp = room_temp
228 + (((hot_temp - room_temp) / (v_adc_hot - v_adc_room)) * (v_adc - v_adc_room));
229
230 let int1v_real = room_int1v
231 + (((hot_int1v - room_int1v) * (coarse_temp - room_temp)) / (hot_temp - room_temp));
232
233 let v_adc_real = (reading as f32 * int1v_real) / 4095.0;
234
235 room_temp
236 + (((hot_temp - room_temp) / (v_adc_hot - v_adc_room)) * (v_adc_real - v_adc_room))
237 }
238}
239
240impl<I: AdcInstance + PrimaryAdc> Adc<I> {
241 #[inline]
242 pub fn read_cpu_temperature(&mut self, sysctrl: &mut Sysctrl) -> f32 {
247 let old_state = sysctrl.vref().read().tsen().bit();
248 sysctrl.vref().modify(|_, w| w.tsen().set_bit());
249
250 let adc_val = self.with_specific_settings(ADC_SETTINGS_INTERNAL_READ_D21_TEMP, |adc| {
251 adc.adc.inputctrl().modify(|_, w| w.gain()._1x());
254 adc.discard = true;
255 let res = adc.read_channel(0x18);
256 adc.adc.inputctrl().modify(|_, w| w.gain().div2());
258 adc.discard = true;
259 res
260 });
261
262 sysctrl.vref().modify(|_, w| w.tsen().variant(old_state));
264 self.cpu_raw_to_temp(adc_val)
265 }
266
267 #[inline]
268 pub fn read_cpu_voltage(&mut self, src: CpuVoltageSource) -> u16 {
269 let voltage = self.with_specific_settings(ADC_SETTINGS_INTERNAL_READ, |adc| {
270 let res = adc.read_channel(src as u8);
271 let mut res_f = adc.reading_to_f32(res) * 3.3;
272 if CpuVoltageSource::Bandgap != src {
273 res_f *= 4.0;
274 }
275 res_f
276 });
277 (voltage * 1000.0) as u16
278 }
279}
280
281#[cfg(feature = "async")]
282impl<I: AdcInstance + PrimaryAdc, F> FutureAdc<I, F>
283where
284 F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
285{
286 pub async fn read_cpu_temperature(&mut self, sysctrl: &mut Sysctrl) -> f32 {
288 let old_state = sysctrl.vref().read().tsen().bit();
289 sysctrl.vref().modify(|_, w| w.tsen().set_bit());
290
291 let old_adc_settings = self.inner.cfg;
292 self.inner.configure(ADC_SETTINGS_INTERNAL_READ);
293 self.inner.adc.inputctrl().modify(|_, w| w.gain()._1x());
294 self.inner.discard = true;
295
296 let res = self.read_channel(0x18).await;
297
298 self.inner.adc.inputctrl().modify(|_, w| w.gain().div2());
299 self.inner.configure(old_adc_settings);
300 self.inner.discard = true;
301
302 sysctrl.vref().modify(|_, w| w.tsen().variant(old_state));
304 self.inner.cpu_raw_to_temp(res)
305 }
306
307 pub async fn read_cpu_voltage(&mut self, src: CpuVoltageSource) -> u16 {
309 let old_adc_settings = self.inner.cfg;
310 self.inner.configure(ADC_SETTINGS_INTERNAL_READ);
311
312 let res = self.read_channel(src as u8).await;
313 let mut voltage = self.inner.reading_to_f32(res) * 3.3;
314 if CpuVoltageSource::Bandgap != src {
315 voltage *= 4.0;
316 }
317
318 self.inner.configure(old_adc_settings);
319 (voltage * 1000.0) as u16
320 }
321}