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