atsamd_hal/peripherals/adc/
builder.rs1use atsamd_hal_macros::hal_cfg;
2
3#[hal_cfg("adc-d5x")]
4use crate::pac::adc0;
5
6#[hal_cfg(any("adc-d21", "adc-d11"))]
7use crate::pac::adc as adc0;
8
9#[hal_cfg(any("adc-d21", "adc-d11"))]
10pub use adc0::ctrlb::Prescalerselect as Prescaler;
11
12#[hal_cfg("adc-d5x")]
13pub use adc0::ctrla::Prescalerselect as Prescaler;
14
15pub use adc0::avgctrl::Samplenumselect as SampleCount;
16
17pub use adc0::ctrlb::Resselselect as Resolution;
18
19pub use adc0::refctrl::Refselselect as Reference;
20
21use super::{Adc, AdcInstance};
22
23#[derive(Copy, Clone, PartialEq, Eq)]
24pub enum AdcResolution {
25 _8,
26 _10,
27 _12,
28}
29
30impl From<AdcResolution> for Resolution {
31 fn from(val: AdcResolution) -> Self {
32 match val {
33 AdcResolution::_8 => Resolution::_8bit,
34 AdcResolution::_10 => Resolution::_10bit,
35 AdcResolution::_12 => Resolution::_12bit,
36 }
37 }
38}
39
40#[derive(Copy, Clone, PartialEq, Eq)]
42pub enum Accumulation {
43 Single(AdcResolution),
47 Average(SampleCount),
52 Summed(SampleCount),
58}
59
60impl Accumulation {
61 pub const fn single(res: AdcResolution) -> Self {
63 Self::Single(res)
64 }
65
66 pub const fn average(count: SampleCount) -> Self {
68 Self::Average(count)
69 }
70
71 pub const fn summed(count: SampleCount) -> Self {
73 Self::Summed(count)
74 }
75
76 pub(crate) fn resolution(&self) -> Resolution {
77 if let Self::Single(res) = self {
78 (*res).into()
79 } else {
80 Resolution::_16bit
81 }
82 }
83
84 pub(crate) fn output_resolution(&self) -> Resolution {
85 if let Self::Single(res) = self {
86 (*res).into()
87 } else if let Self::Average(_) = self {
88 Resolution::_12bit
89 } else {
90 Resolution::_16bit
91 }
92 }
93
94 pub(crate) fn samples(&self) -> u16 {
95 match self {
96 Accumulation::Single(_) => 1,
97 Accumulation::Average(samplenumselect) => 2u16.pow(*samplenumselect as u32),
99 Accumulation::Summed(samplenumselect) => 2u16.pow(*samplenumselect as u32),
100 }
101 }
102}
103
104#[derive(Debug, Copy, Clone)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum BuilderError {
107 MissingClockDiv,
109 MissingSampleClocks,
111 MissingVref,
113 AdcError(super::Error),
114}
115
116impl From<super::Error> for BuilderError {
117 fn from(value: super::Error) -> Self {
118 Self::AdcError(value)
119 }
120}
121
122#[derive(Copy, Clone)]
150pub struct AdcBuilder {
151 pub clk_divider: Option<Prescaler>,
152 pub sample_clock_cycles: Option<u8>,
153 pub accumulation: Accumulation,
154 pub vref: Option<Reference>,
155}
156
157#[derive(Copy, Clone, PartialEq)]
160pub(crate) struct AdcSettings {
161 pub clk_divider: Prescaler,
162 pub sample_clock_cycles: u8,
163 pub accumulation: Accumulation,
164 pub vref: Reference,
165}
166
167impl AdcBuilder {
168 pub fn new(accumulation_method: Accumulation) -> Self {
170 Self {
171 clk_divider: None,
172 sample_clock_cycles: None,
173 accumulation: accumulation_method,
174 vref: None,
175 }
176 }
177
178 pub(crate) fn check_params(&self) -> Result<(), BuilderError> {
179 self.clk_divider.ok_or(BuilderError::MissingClockDiv)?;
180 self.sample_clock_cycles
181 .ok_or(BuilderError::MissingSampleClocks)?;
182 self.vref.ok_or(BuilderError::MissingVref)?;
183 Ok(())
184 }
185
186 pub(crate) fn to_settings(self) -> Result<AdcSettings, BuilderError> {
187 self.check_params()?;
188 Ok(AdcSettings {
189 clk_divider: self.clk_divider.unwrap(),
190 sample_clock_cycles: self.sample_clock_cycles.unwrap(),
191 accumulation: self.accumulation,
192 vref: self.vref.unwrap(),
193 })
194 }
195
196 pub fn with_clock_divider(mut self, div: Prescaler) -> Self {
202 self.clk_divider = Some(div);
203 self
204 }
205
206 pub fn with_vref(mut self, reference: Reference) -> Self {
208 self.vref = Some(reference);
209 self
210 }
211
212 pub fn with_clock_cycles_per_sample(mut self, num: u8) -> Self {
222 self.sample_clock_cycles = Some(num.clamp(1, 63)); self
224 }
225
226 pub fn calculate_sps(&self, clock_freq: u32) -> Result<u32, BuilderError> {
228 self.check_params()?;
229
230 let div = self.clk_divider.unwrap() as u32;
231 let adc_clk_freq = clock_freq / div;
232
233 let bit_width = match self.accumulation.resolution() {
234 Resolution::_16bit => 16,
235 Resolution::_12bit => 12,
236 Resolution::_10bit => 10,
237 Resolution::_8bit => 8,
238 };
239
240 let mut clocks_per_sample = self.sample_clock_cycles.unwrap() as u32 + bit_width;
241
242 let samples = self.accumulation.samples();
243 clocks_per_sample *= samples as u32;
244 Ok(adc_clk_freq / clocks_per_sample)
245 }
246
247 #[hal_cfg("adc-d5x")]
249 #[inline]
250 pub fn enable<I: AdcInstance, PS: crate::clock::v2::pclk::PclkSourceId>(
251 self,
252 adc: I::Instance,
253 clk: crate::clock::v2::apb::ApbClk<I::ClockId>,
254 pclk: &crate::clock::v2::pclk::Pclk<I::ClockId, PS>,
255 ) -> Result<Adc<I>, BuilderError> {
256 let settings = self.to_settings()?;
257 Adc::new(adc, settings, clk, pclk).map_err(|e| e.into())
258 }
259
260 #[hal_cfg(any("adc-d11", "adc-d21"))]
261 #[inline]
262 pub fn enable<I: AdcInstance>(
263 self,
264 adc: I::Instance,
265 pm: &mut crate::pac::Pm,
266 clock: &crate::clock::AdcClock,
267 ) -> Result<Adc<I>, BuilderError> {
268 let settings = self.to_settings()?;
269 Adc::new(adc, settings, pm, clock).map_err(|e| e.into())
270 }
271}