1use core::marker::PhantomData;
3
4use crate::clock::Clocks;
5use crate::pac;
6use crate::time::Hertz;
7use num_enum::{IntoPrimitive, TryFromPrimitive};
8use vorago_shared_hal::{PeripheralSelect, enable_peripheral_clock};
9
10pub const ADC_MIN_CLK: Hertz = Hertz::from_raw(2_000_000);
11pub const ADC_MAX_CLK: Hertz = Hertz::from_raw(12_500_000);
12
13#[derive(Debug, PartialEq, Eq, Copy, Clone, TryFromPrimitive, IntoPrimitive)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15#[repr(u8)]
16pub enum ChannelSelect {
17 AnIn0 = 0,
19 AnIn1 = 1,
21 AnIn2 = 2,
23 AnIn3 = 3,
25 AnIn4 = 4,
27 AnIn5 = 5,
29 AnIn6 = 6,
31 AnIn7 = 7,
33 Dac0 = 8,
35 Dac1 = 9,
37 TempSensor = 10,
39 Bandgap1V = 11,
41 Bandgap1_5V = 12,
43 Avdd1_5 = 13,
44 Dvdd1_5 = 14,
45 Vrefp5 = 15,
47}
48
49bitflags::bitflags! {
50 #[derive(Debug)]
53 pub struct MultiChannelSelect: u16 {
54 const AnIn0 = 1;
55 const AnIn1 = 1 << 1;
56 const AnIn2 = 1 << 2;
57 const AnIn3 = 1 << 3;
58 const AnIn4 = 1 << 4;
59 const AnIn5 = 1 << 5;
60 const AnIn6 = 1 << 6;
61 const AnIn7 = 1 << 7;
62 const Dac0 = 1 << 8;
63 const Dac1 = 1 << 9;
64 const TempSensor = 1 << 10;
65 const Bandgap1V = 1 << 11;
66 const Bandgap1_5V = 1 << 12;
67 const Avdd1_5 = 1 << 13;
68 const Dvdd1_5 = 1 << 14;
69 const Vrefp5 = 1 << 15;
70 }
71}
72
73#[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75#[error("ADC empty error")]
76pub struct AdcEmptyError;
77
78#[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80#[error("invalid channel range error")]
81pub struct InvalidChannelRangeError;
82
83#[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85#[error("buffer too small")]
86pub struct BufferTooSmallError;
87
88#[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
90pub enum AdcRangeReadError {
91 #[error("invalid channel range: {0}")]
92 InvalidChannelRange(#[from] InvalidChannelRangeError),
93 #[error("buffer too small: {0}")]
94 BufferTooSmall(#[from] BufferTooSmallError),
95}
96
97#[derive(Debug, PartialEq, Eq, Copy, Clone)]
98#[cfg_attr(feature = "defmt", derive(defmt::Format))]
99pub struct ChannelValue {
100 channel: ChannelSelect,
102 value: u16,
104}
105
106impl Default for ChannelValue {
107 fn default() -> Self {
108 Self {
109 channel: ChannelSelect::AnIn0,
110 value: Default::default(),
111 }
112 }
113}
114
115impl ChannelValue {
116 #[inline]
117 pub fn value(&self) -> u16 {
118 self.value
119 }
120
121 #[inline]
122 pub fn channel(&self) -> ChannelSelect {
123 self.channel
124 }
125}
126
127pub enum ChannelTagEnabled {}
128pub enum ChannelTagDisabled {}
129
130pub struct Adc<TagEnabled = ChannelTagDisabled> {
143 adc: pac::Adc,
144 phantom: PhantomData<TagEnabled>,
145}
146
147impl Adc<ChannelTagEnabled> {}
148
149impl Adc<ChannelTagDisabled> {
150 pub fn new(adc: pac::Adc, clocks: &Clocks) -> Self {
151 Self::generic_new(adc, clocks)
152 }
153
154 pub fn trigger_and_read_single_channel(&self, ch: ChannelSelect) -> Result<u16, AdcEmptyError> {
155 self.generic_trigger_and_read_single_channel(ch)
156 .map(|v| v & 0xfff)
157 }
158
159 pub fn sweep_and_read_range(
163 &self,
164 lower_bound_idx: u8,
165 upper_bound_idx: u8,
166 rx_buf: &mut [u16],
167 ) -> Result<usize, AdcRangeReadError> {
168 self.generic_prepare_range_sweep_and_wait_until_ready(
169 lower_bound_idx,
170 upper_bound_idx,
171 rx_buf.len(),
172 )?;
173 let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits();
174 for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) {
175 rx_buf[i as usize] = self.adc.fifo_data().read().bits() as u16 & 0xfff;
176 }
177 Ok(fifo_entry_count as usize)
178 }
179
180 pub fn sweep_and_read_multiselect(
184 &self,
185 ch_select: MultiChannelSelect,
186 rx_buf: &mut [u16],
187 ) -> Result<usize, BufferTooSmallError> {
188 self.generic_prepare_multiselect_sweep_and_wait_until_ready(ch_select, rx_buf.len())?;
189 let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits();
190 for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) {
191 rx_buf[i as usize] = self.adc.fifo_data().read().bits() as u16 & 0xfff;
192 }
193 Ok(fifo_entry_count as usize)
194 }
195
196 pub fn try_read_single_value(&self) -> nb::Result<Option<u16>, ()> {
197 self.generic_try_read_single_value()
198 .map(|v| v.map(|v| v & 0xfff))
199 }
200
201 #[inline(always)]
202 pub fn channel_tag_enabled(&self) -> bool {
203 false
204 }
205}
206
207impl Adc<ChannelTagEnabled> {
208 pub fn new_with_channel_tag(adc: pac::Adc, clocks: &Clocks) -> Self {
209 let mut adc = Self::generic_new(adc, clocks);
210 adc.enable_channel_tag();
211 adc
212 }
213
214 pub fn trigger_and_read_single_channel(
215 &self,
216 ch: ChannelSelect,
217 ) -> Result<ChannelValue, AdcEmptyError> {
218 self.generic_trigger_and_read_single_channel(ch)
219 .map(|v| self.create_channel_value(v))
220 }
221
222 pub fn try_read_single_value(&self) -> nb::Result<Option<ChannelValue>, ()> {
223 self.generic_try_read_single_value()
224 .map(|v| v.map(|v| self.create_channel_value(v)))
225 }
226
227 pub fn sweep_and_read_range(
231 &self,
232 lower_bound_idx: u8,
233 upper_bound_idx: u8,
234 rx_buf: &mut [ChannelValue],
235 ) -> Result<usize, AdcRangeReadError> {
236 self.generic_prepare_range_sweep_and_wait_until_ready(
237 lower_bound_idx,
238 upper_bound_idx,
239 rx_buf.len(),
240 )?;
241 let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits();
242 for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) {
243 rx_buf[i as usize] =
244 self.create_channel_value(self.adc.fifo_data().read().bits() as u16);
245 }
246 Ok(fifo_entry_count as usize)
247 }
248
249 pub fn sweep_and_read_multiselect(
253 &self,
254 ch_select: MultiChannelSelect,
255 rx_buf: &mut [ChannelValue],
256 ) -> Result<usize, BufferTooSmallError> {
257 self.generic_prepare_multiselect_sweep_and_wait_until_ready(ch_select, rx_buf.len())?;
258 let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits();
259 for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) {
260 rx_buf[i as usize] =
261 self.create_channel_value(self.adc.fifo_data().read().bits() as u16);
262 }
263 Ok(fifo_entry_count as usize)
264 }
265
266 #[inline]
267 pub fn create_channel_value(&self, raw_value: u16) -> ChannelValue {
268 ChannelValue {
269 value: raw_value & 0xfff,
270 channel: ChannelSelect::try_from(((raw_value >> 12) & 0xf) as u8).unwrap(),
271 }
272 }
273
274 #[inline(always)]
275 pub fn channel_tag_enabled(&self) -> bool {
276 true
277 }
278}
279
280impl<TagEnabled> Adc<TagEnabled> {
281 fn generic_new(adc: pac::Adc, _clocks: &Clocks) -> Self {
282 enable_peripheral_clock(PeripheralSelect::Adc);
283 adc.ctrl().write(|w| unsafe { w.bits(0) });
284 let adc = Self {
285 adc,
286 phantom: PhantomData,
287 };
288 adc.clear_fifo();
289 adc
290 }
291
292 #[inline(always)]
293 fn enable_channel_tag(&mut self) {
294 self.adc.ctrl().modify(|_, w| w.chan_tag_en().set_bit());
295 }
296
297 #[inline(always)]
298 fn disable_channel_tag(&mut self) {
299 self.adc.ctrl().modify(|_, w| w.chan_tag_en().clear_bit());
300 }
301
302 #[inline(always)]
303 pub fn clear_fifo(&self) {
304 self.adc.fifo_clr().write(|w| unsafe { w.bits(1) });
305 }
306
307 pub fn generic_try_read_single_value(&self) -> nb::Result<Option<u16>, ()> {
308 if self.adc.status().read().adc_busy().bit_is_set() {
309 return Err(nb::Error::WouldBlock);
310 }
311 if self.adc.status().read().fifo_entry_cnt().bits() == 0 {
312 return Ok(None);
313 }
314 Ok(Some(self.adc.fifo_data().read().bits() as u16))
315 }
316
317 fn generic_trigger_single_channel(&self, ch: ChannelSelect) {
318 self.adc.ctrl().modify(|_, w| {
319 w.ext_trig_en().clear_bit();
320 unsafe {
321 w.conv_cnt().bits(0);
323 w.chan_en().bits(1 << ch as u8)
324 }
325 });
326 self.clear_fifo();
327
328 self.adc.ctrl().modify(|_, w| w.manual_trig().set_bit());
329 }
330
331 fn generic_prepare_range_sweep_and_wait_until_ready(
332 &self,
333 lower_bound_idx: u8,
334 upper_bound_idx: u8,
335 buf_len: usize,
336 ) -> Result<(), AdcRangeReadError> {
337 if (lower_bound_idx > 15 || upper_bound_idx > 15) || lower_bound_idx > upper_bound_idx {
338 return Err(InvalidChannelRangeError.into());
339 }
340 let ch_count = upper_bound_idx - lower_bound_idx + 1;
341 if buf_len < ch_count as usize {
342 return Err(BufferTooSmallError.into());
343 }
344 let mut ch_select = 0;
345 for i in lower_bound_idx..upper_bound_idx + 1 {
346 ch_select |= 1 << i;
347 }
348 self.generic_trigger_sweep(ch_select);
349 while self.adc.status().read().adc_busy().bit_is_set() {
350 cortex_m::asm::nop();
351 }
352 Ok(())
353 }
354
355 fn generic_prepare_multiselect_sweep_and_wait_until_ready(
356 &self,
357 ch_select: MultiChannelSelect,
358 buf_len: usize,
359 ) -> Result<(), BufferTooSmallError> {
360 let ch_select = ch_select.bits();
361 let ch_count = ch_select.count_ones();
362 if buf_len < ch_count as usize {
363 return Err(BufferTooSmallError);
364 }
365 self.generic_trigger_sweep(ch_select);
366 while self.adc.status().read().adc_busy().bit_is_set() {
367 cortex_m::asm::nop();
368 }
369 Ok(())
370 }
371
372 fn generic_trigger_sweep(&self, ch_select: u16) {
373 let ch_num = ch_select.count_ones() as u8;
374 assert!(ch_num > 0);
375 self.adc.ctrl().modify(|_, w| {
376 w.ext_trig_en().clear_bit();
377 unsafe {
378 w.conv_cnt().bits(0);
380 w.chan_en().bits(ch_select);
381 w.sweep_en().set_bit()
382 }
383 });
384 self.clear_fifo();
385
386 self.adc.ctrl().modify(|_, w| w.manual_trig().set_bit());
387 }
388
389 fn generic_trigger_and_read_single_channel(
390 &self,
391 ch: ChannelSelect,
392 ) -> Result<u16, AdcEmptyError> {
393 self.generic_trigger_single_channel(ch);
394 nb::block!(self.generic_try_read_single_value())
395 .unwrap()
396 .ok_or(AdcEmptyError)
397 }
398}
399
400impl From<Adc<ChannelTagDisabled>> for Adc<ChannelTagEnabled> {
401 fn from(value: Adc<ChannelTagDisabled>) -> Self {
402 let mut adc = Self {
403 adc: value.adc,
404 phantom: PhantomData,
405 };
406 adc.enable_channel_tag();
407 adc
408 }
409}
410
411impl From<Adc<ChannelTagEnabled>> for Adc<ChannelTagDisabled> {
412 fn from(value: Adc<ChannelTagEnabled>) -> Self {
413 let mut adc = Self {
414 adc: value.adc,
415 phantom: PhantomData,
416 };
417 adc.disable_channel_tag();
418 adc
419 }
420}