kea_hal/adc.rs
1//! The ADC Interface
2//!
3//! The ADC is disabled at startup and must be enabled (by calling
4//! [Adc<Disabled>::enable]) before any of its registers can be accessed
5//! (read or write). Attempts to access these registers will trigger a hardware
6//! generated HardFault, which by default resets the microcontroller.
7//!
8//! The ADC can be polled for conversion completion with [Adc::is_done].
9//! Completion will trigger an ADC Interrupt if enabled. See
10//! [Adc::into_interrupt]
11//!
12//! ## Input Modes
13//!
14//! The Adc peripheral can operate in either single input or FIFO modes. Single
15//! input mode is the mode most commonly thought of when using an ADC. A
16//! multiplexer (via Adc::set_channel) is used to connect a single channel to
17//! the ADC, and when the conversion is complete the hardware makes the results
18//! available in the results register. The software must call
19//! [Adc::set_channel] again to either select a new channel or to restart the
20//! conversion on the same channel.
21//!
22//! The FIFO mode sets up a hardware buffer of selectable depth (2-8 channels).
23//! Once the buffer is filled the Adc peripheral shoves the buffer contents
24//! into the multiplexer channel by channel. Likewise, as each conversion is
25//! completed the results are buffered into the result register in the same
26//! order as the channel select buffer.
27//!
28//! Note: FIFO mode is not yet implemented in this HAL
29//!
30//! ## Conversion Modes
31//!
32//! The Adc peripheral offers 2 conversion modes, OneShot and Continuous. In
33//! OneShot mode, the conversion is started when the channel is selected (or
34//! when the channel select buffer is filled in FIFO mode). After completion no
35//! new conversion is started until the channel is set again, even if the same
36//! channel is used.
37//!
38//! In Continuous mode a new conversion is started immediately
39//! after the previous one is completed. Changing the channel interrupts the
40//! conversion and immediately begins conversion on the new channel (unless the
41//! new channel is [DummyDisable], then the conversion is allowed to complete,
42//! but no new conversion is started). In FIFO mode the input FIFO is reloaded
43//! after completion, in other words the same N values are converted on a loop.
44//!
45//! Note: Continuous mode is not yet implemented in this HAL
46//!
47//! ## Comparison Mode
48//!
49//! Note: Comparison mode is not yet implemented in this HAL
50//!
51//! Comparison mode is a hardware feature of the Adc Peripheral. If set, the
52//! conversion result is compared to the comparison value. If the result
53//! is greater than or less than (depending on configuration) the comparison
54//! value the result is moved into the result register. Otherwise, the result
55//! is discarded \[Note: Unsure if the conversion is restarted in OneShot
56//! mode\].
57//!
58//! A common use case for comparison mode is to enter a low power state with
59//! the Adc configured to use the asynchronous clock source and to generate an
60//! interrupt on completion. When the input channel crosses the comparison
61//! threshold the interrupt is triggered, waking the MCU.
62//!
63//! ## Clocking
64//!
65//! The ADC requires a clock signal (ADCK), which is generated from the bus
66//! clock, the bus clock divided by 2, the output of the OSC peripheral
67//! (OSC_OUT), or an internal asynchronous clock, which, when selected,
68//! operates in wait and stop modes. With any of these clock sources a
69//! multi-value divider is provided to further divide the incoming clock by 1
70//! (i.e. 1:1), 2, 4, or 8.
71//!
72//! The clock frequency must fall within 400kHz to 8MHz (4MHz in low power
73//! mode), This is the same for all KEA MCUs. Ideally, the HAL will only
74//! present valid options, but that is not yet implemented (pending clocks
75//! improvements to output frequencies). For now you are trusted to input the
76//! correct frequency.
77//!
78//! *Note:* When using the FIFO mode with FIFO scan mode disabled, the bus
79//! clock must be faster than half the ADC clock (ADCK). Bus clock >= ADCK / 2.
80//!
81//! ## Pin Control
82//!
83//! This functionality is implemented in the GPIO module. See [Analog]
84//! for details.
85//!
86//! ## Conversion Width
87//!
88//! The ADC can be run in 8, 10, or 12 bit modes. These modes are enumerated in
89//! [AdcResolution].
90//!
91//! ## Hardware Trigger
92//!
93//! The ADC conversions can be started by a hardware trigger. This is not
94//! implemented in all KEA chips, so implementation here will be Delayed. Use
95//! the PAC. Enable is ADC_SC2\[ADTRG\] = 1, and trigger is the ADHWT source.
96//!
97//! ## Usage
98//!
99//! ### AdcConfig struct
100//!
101//! [AdcConfig] offers public fields to allow for creation in-place. The
102//! [AdcConfig::calculate_divisor] method allows the user to specify the
103//! desired Adc Clock frequency (given the clock source frequency). The clock
104//! divider which gets the closest to that frequency is chosen.
105//!
106//! The AdcConfig structure also implements the [Default] trait.
107//!
108//! ```rust
109//! let config: AdcConfig = Default::default();
110//!
111//! config.calculate_divisor(20_u32.MHz(), 2_u32.MHz());
112//! assert!(matches!(config.clock_divisor, ClockDivisor::_8));
113//! ```
114
115use crate::hal::adc::{Channel, OneShot};
116use crate::{pac::ADC, HALExt};
117use core::{convert::Infallible, marker::PhantomData};
118use embedded_time::rate::*;
119
120/// Error Enumeration for this module
121#[derive(Debug)]
122pub enum Error {
123 /// The Channel has already been moved
124 Moved,
125}
126
127/// Analog type state for a GPIO pin.
128///
129/// This mode "gives" the pin to the ADC hardware peripheral.
130/// The ADC Peripheral can take the GPIO pins in any state. The Peripheral will
131/// reconfigure the pin to turn off any output drivers, disable input buffers
132/// (reading the pin after configuring as analog will return a zero), and
133/// disable the pullup. Electrically, an Analog pin that is not currently under
134/// conversion is effectively HighImpedence.
135///
136/// Once a pin is released from the ADC, it will return to its previous state.
137/// The previous state includes output enabled, input enabled, pullup enabled,
138/// and level (for outputs). Note to accomplish this the pin implements the
139/// outof_analog method, which is semantically different from the other type
140/// states.
141///
142/// For example, [crate::gpio::gpioa::PTA0] is configured to be a Output that is set high is
143/// converted into the analog mode with the [crate::gpio::gpioa::PTA0::into_analog] method.
144/// Once measurements from that pin are completed it will be returned to an
145/// Output that is set high by calling the [Analog::outof_analog] method.
146///
147/// ```rust
148/// let pta0 = gpioa.pta0.into_push_pull_output();
149/// pta0.set_high();
150/// let mut pta0 = pta0.into_analog(); // pta0 is hi-Z
151/// let value = adc.read(&mut pta0).unwrap_or(0);
152/// let pta0 = pta0.outof_analog(); // pta0 is push-pull output, set high.
153/// ```
154///
155/// Note: This is a hardware feature that requires effectively no clock cycles
156/// to complete. "Manually" reconfiguring the pins to HighImpedence before
157/// calling into_analog() is discouraged, but it would not hurt anything.
158pub struct Analog<Pin> {
159 pin: Pin,
160}
161
162/// Interface for ADC Peripheral.
163///
164/// Returned by calling [HALExt::split] on the pac [ADC] structure. Holds state
165/// of peripheral.
166pub struct Adc<State> {
167 peripheral: ADC,
168 _state: PhantomData<State>,
169 /// Contains the On-Chip ADC Channels, like the MCU's temperature sensor.
170 pub onchip_channels: OnChipChannels,
171}
172
173impl HALExt for ADC {
174 type T = Adc<Disabled>;
175 fn split(self) -> Adc<Disabled> {
176 Adc {
177 peripheral: self,
178 _state: PhantomData,
179 onchip_channels: OnChipChannels {
180 vss: Some(Analog {
181 pin: Vss::<Input> { _mode: PhantomData },
182 }),
183 temp_sense: Some(Analog {
184 pin: TempSense::<Input> { _mode: PhantomData },
185 }),
186 bandgap: Some(Analog {
187 pin: Bandgap::<Input> { _mode: PhantomData },
188 }),
189 vref_h: Some(Analog {
190 pin: VrefH::<Input> { _mode: PhantomData },
191 }),
192 vref_l: Some(Analog {
193 pin: VrefL::<Input> { _mode: PhantomData },
194 }),
195 },
196 }
197 }
198}
199
200/// Configuration struct for Adc peripheral.
201pub struct AdcConfig {
202 /// Determines the clock source for the ADC peripheral
203 ///
204 /// Default is [AdcClocks::Bus]
205 pub clock_source: AdcClocks,
206 /// Divides the clock source to get the ADC clock into it's usable range of
207 /// 400kHz - 8MHz (4MHz in low power mode).
208 ///
209 /// Default is [ClockDivisor::_1] (no divison)
210 pub clock_divisor: ClockDivisor,
211 /// Set the resolution of ADC conversion
212 ///
213 /// Default is [AdcResolution::_8bit]
214 pub resolution: AdcResolution,
215
216 /// Set ADC sample time.
217 ///
218 /// Default is [AdcSampleTime::Short]
219 pub sample_time: AdcSampleTime,
220
221 /// Set low power mode
222 ///
223 /// Default is false.
224 pub low_power: bool,
225}
226
227impl AdcConfig {
228 /// Calculate the ADC clock divisor
229 ///
230 /// Uses the current clock source and clock frequency to determine
231 /// the best divisor to use in order to have minimal error between
232 /// the ADC clock rate and the desired ADC clock rate.
233 ///
234 /// Note: This relies on trustworthy values for source_freq and valid
235 /// values for req_adc_freq. In the future this should know or
236 /// determine what the current clock frequency is instead of relying
237 /// on the user to provide it.
238 pub fn calculate_divisor(&mut self, source_freq: Hertz, req_adc_freq: Hertz) {
239 let denom: u8 = (source_freq.integer() / req_adc_freq.integer()) as u8;
240
241 let mut output: u8 = 1;
242 let mut err: i8 = (denom - output) as i8;
243 let mut err_old: i8 = err;
244 let max_divisor = match self.clock_source {
245 AdcClocks::Bus => 16,
246 _ => 8,
247 };
248 while output < max_divisor {
249 err = (denom - (output << 1)) as i8;
250 if err.is_negative() {
251 err = err.abs();
252 }
253 if err <= err_old {
254 output <<= 1;
255 err_old = err;
256 } else {
257 break;
258 }
259 }
260
261 // I am of the mind that this assert is okay, at least until the input
262 // clock can be known at compile time.
263 let ad_clock = source_freq.integer() / output as u32;
264 assert!(400_000 <= ad_clock);
265 assert!(
266 ad_clock
267 <= match self.low_power {
268 false => 8_000_000,
269 true => 4_000_000,
270 }
271 );
272
273 self.clock_divisor = match output {
274 1 => ClockDivisor::_1,
275 2 => ClockDivisor::_2,
276 4 => ClockDivisor::_4,
277 8 => ClockDivisor::_8,
278 _ => ClockDivisor::_16,
279 }
280 }
281
282 /// Set the divisor directly. panics if divisor isn't supported by the
283 /// clock source.
284 ///
285 /// TODO: Refactor to remove assert. Add Clock Source as a type state
286 pub fn set_divisor(&mut self, divisor: ClockDivisor) {
287 // divisor can't be 16 unless using the Bus clock
288 assert!(
289 !(!matches!(self.clock_source, AdcClocks::Bus) && matches!(divisor, ClockDivisor::_16))
290 );
291 self.clock_divisor = divisor;
292 }
293
294 /// Sets the clock source, panics if divisor isn't supported
295 ///
296 /// TODO: Refactor to remove assert. Add Clock Source as a type state
297 pub fn set_clock_source(&mut self, clock: AdcClocks) {
298 // Panic if setting the clock to anything other than Bus if the divisor
299 // is set to 16
300 assert!(
301 !matches!(clock, AdcClocks::Bus) && matches!(self.clock_divisor, ClockDivisor::_16)
302 );
303 self.clock_source = clock;
304 }
305}
306
307impl Default for AdcConfig {
308 fn default() -> AdcConfig {
309 AdcConfig {
310 clock_source: AdcClocks::Bus,
311 clock_divisor: ClockDivisor::_1,
312 resolution: AdcResolution::_12bit,
313 sample_time: AdcSampleTime::Short,
314 low_power: false,
315 }
316 }
317}
318
319/// Clock types available to the Adc peripheral
320///
321/// Dividers will be chosen appropriately to suit requested clock rate.
322pub enum AdcClocks {
323 /// Use the incoming Bus Clock
324 Bus,
325 /// jkl
326 External,
327 /// Available in Wait AND Stop Mode
328 Async,
329}
330
331/// This enum represents the availabe ADC resolutions
332///
333/// Regardless of resolution chosen, results are always right justified
334#[repr(u8)]
335pub enum AdcResolution {
336 /// 8 bit AD conversion mode
337 _8bit = 0,
338 /// 10 bit AD conversion mode
339 _10bit = 1,
340 /// 12 bit AD conversion mode
341 _12bit = 2,
342}
343
344/// Adc sample time
345pub enum AdcSampleTime {
346 /// Sample for 3.5 ADC clock (ADCK) cycles.
347 Short = 0,
348
349 /// Sample for 23.5 ADC clock (ADCK) cycles.
350 ///
351 /// Required for high impedence (>2k @ADCK > 4MHz, >5k @ ADCK < 4MHz)
352 /// inputs.
353 Long = 1,
354}
355
356/// Adc Clock Divisors
357///
358/// Note 1/16 divisor is only usable for the Bus clock
359pub enum ClockDivisor {
360 /// Source / 1, No divison
361 _1 = 0,
362 /// Source / 2
363 _2 = 1,
364 /// Source / 4
365 _4 = 2,
366 /// Source / 8
367 _8 = 3,
368 /// Source / 16
369 _16 = 4,
370}
371
372/// Enabled state
373pub struct Enabled;
374
375/// Disabled state
376pub struct Disabled;
377
378impl Adc<Enabled> {
379 /// Poll to determine if ADC conversion is complete.
380 ///
381 /// Note: This flag is cleared when the sampling mode is changed,
382 /// interrupts are enabled, [Adc::set_channel] is called, and when [Adc::result] is
383 /// called (including [Adc::try_result])
384 pub fn is_done(&self) -> bool {
385 self.peripheral.sc1.read().coco().bit()
386 }
387
388 /// Poll to determine if ADC conversion is underway
389 pub fn is_converting(&self) -> bool {
390 self.peripheral.sc2.read().adact().bit()
391 }
392
393 /// Grab the last ADC conversion result.
394 pub fn result(&self) -> u16 {
395 self.peripheral.r.read().adr().bits()
396 }
397
398 /// Poll for conversion completion, if done return the result.
399 pub fn try_result(&self) -> Option<u16> {
400 if self.is_done() {
401 Some(self.result())
402 } else {
403 None
404 }
405 }
406
407 /// Set ADC target channel.
408 ///
409 /// In Single conversion mode (OneShot), setting the channel begins the conversion. In FIFO mode
410 /// the channel is added to the FIFO buffer.
411 ///
412 /// Note: If the channel is changed while a conversion is in progress the
413 /// current conversion will be cancelled. If in FIFO mode, conversion will
414 /// resume once the FIFO channels are refilled.
415 pub fn set_channel<T: Channel<Adc<Enabled>, ID = u8>>(&self, _pin: &T) {
416 self.peripheral
417 .sc1
418 .modify(|_, w| unsafe { w.adch().bits(T::channel()) });
419 }
420
421 /// Set the ADC's configuration
422 pub fn configure(self, config: AdcConfig) -> Adc<Enabled> {
423 self.peripheral.sc3.modify(|_, w| {
424 use pac::adc::sc3::{ADICLK_A, ADIV_A, ADLSMP_A, MODE_A};
425 w.adiclk()
426 .variant(match config.clock_source {
427 AdcClocks::Bus =>
428 // If divisor is 16, use the Bus / 2 clock source, else use
429 // the 1:1 Bus clock source
430 {
431 match config.clock_divisor {
432 ClockDivisor::_16 => ADICLK_A::_01,
433 _ => ADICLK_A::_00,
434 }
435 }
436 AdcClocks::External => ADICLK_A::_10,
437 AdcClocks::Async => ADICLK_A::_11,
438 })
439 .mode()
440 .variant(match config.resolution {
441 AdcResolution::_8bit => MODE_A::_00,
442 AdcResolution::_10bit => MODE_A::_01,
443 AdcResolution::_12bit => MODE_A::_10,
444 })
445 .adlsmp()
446 .variant(match config.sample_time {
447 AdcSampleTime::Short => ADLSMP_A::_0,
448 AdcSampleTime::Long => ADLSMP_A::_1,
449 })
450 .adiv()
451 .variant(match config.clock_divisor {
452 ClockDivisor::_1 => ADIV_A::_00,
453 ClockDivisor::_2 => ADIV_A::_01,
454 ClockDivisor::_4 => ADIV_A::_10,
455 _ => ADIV_A::_11,
456 })
457 .adlpc()
458 .bit(config.low_power)
459 });
460
461 // It looks like SCGC has to be set before touching the peripheral
462 // at all, else hardfault. Go back later to confirm that if using external clock
463 // scgc can be cleared.
464 // w.adc().variant(match config.clock_source {
465 // AdcClocks::Bus => ADC_A::_1,
466 // _ => ADC_A::_0,
467 // })
468
469 Adc {
470 peripheral: self.peripheral,
471 _state: PhantomData,
472 onchip_channels: self.onchip_channels,
473 }
474 }
475}
476
477impl Adc<Disabled> {
478 /// Connects the bus clock to the adc via the SIM peripheral, allowing
479 /// read and write access to ADC registers.
480 ///
481 /// Any attempt to access ADC registers while disabled results in a
482 /// HardFault, generated by hardware.
483 ///
484 /// This also enables the bandgap voltage reference.
485 pub fn enable(self) -> Adc<Enabled> {
486 cortex_m::interrupt::free(|_| {
487 unsafe { &(*pac::SIM::ptr()) }.scgc.modify(|_, w| {
488 use pac::sim::scgc::ADC_A;
489 w.adc().variant(ADC_A::_1)
490 });
491
492 // Don't start a conversion (set channel to DummyDisable)
493 self.peripheral.sc1.modify(|_, w| w.adch()._11111());
494
495 // Bandgap. Grab directly, Currently the bandgap isn't implemented
496 // in [system::PMC]. We will eventually have to pass in the pmc
497 // peripheral handle as a variable.
498 unsafe { &(*pac::PMC::ptr()) }
499 .spmsc1
500 .modify(|_, w| w.bgbe()._1());
501 });
502
503 Adc {
504 peripheral: self.peripheral,
505 _state: PhantomData,
506 onchip_channels: self.onchip_channels,
507 }
508 }
509
510 /// Set the ADC's configuration
511 ///
512 /// This is a sugar method for calling [Adc<Disabled>::enable] followed by
513 /// [Adc<Enabled>::configure]
514 pub fn configure(self, config: AdcConfig) -> Adc<Enabled> {
515 self.enable().configure(config)
516 }
517}
518
519impl<Mode> Adc<Mode> {
520 /// Not Implemented
521 pub fn into_interrupt(self) -> Adc<Mode> {
522 unimplemented!("Interrupt is not yet implemented");
523 // Adc::<Mode> {
524 // peripheral: self.peripheral,
525 // _state: PhantomData,
526 // onchip_channels: self.onchip_channels,
527 // }
528 }
529
530 /// Not Implemented
531 pub fn into_fifo(self, _depth: u8) -> Adc<Mode> {
532 // self.peripheral
533 // .sc4
534 // .modify(|_r, w| w.afdep().bits(depth & 0x7));
535 // Adc::<Mode> {
536 // peripheral: self.peripheral,
537 // _state: PhantomData,
538 // onchip_channels: self.onchip_channels,
539 // }
540 unimplemented!("FIFO is not yet implemented");
541 }
542
543 /// Not Implemented
544 pub fn into_continuous(self) -> Adc<Mode> {
545 unimplemented!("Continuous Conversion mode not yet implemented");
546 }
547}
548
549impl OnChipChannels {
550 /// Request an instance of an on-chip [Vss] channel.
551 pub fn vss(&mut self) -> Result<Analog<Vss<Input>>, Error> {
552 self.vss.take().ok_or(Error::Moved)
553 }
554
555 /// Return the instance of [Vss]
556 pub fn return_vss(&mut self, inst: Analog<Vss<Input>>) {
557 self.vss.replace(inst);
558 }
559
560 /// Try to grab an instance of the onchip [TempSense] channel.
561 pub fn tempsense(&mut self) -> Result<Analog<TempSense<Input>>, Error> {
562 self.temp_sense.take().ok_or(Error::Moved)
563 }
564
565 /// Return the instance of [TempSense]
566 pub fn return_tempsense(&mut self, inst: Analog<TempSense<Input>>) {
567 self.temp_sense.replace(inst);
568 }
569
570 /// Try to grab an instance of the onchip [Bandgap] channel.
571 ///
572 /// The bandgap reference is a fixed 1.16V (nom, Factory trimmed to +/-
573 /// 0.02V at Vdd=5.0 at 125C) signal that is available to the ADC Module.
574 /// It can be used as a voltage reference for the ACMP and as an [Analog]
575 /// channel that can be used to (roughly) check the VDD voltage
576 pub fn bandgap(&mut self) -> Result<Analog<Bandgap<Input>>, Error> {
577 self.bandgap.take().ok_or(Error::Moved)
578 }
579
580 /// Return the instance of [Bandgap]
581 pub fn return_bandgap(&mut self, inst: Analog<Bandgap<Input>>) {
582 self.bandgap.replace(inst);
583 }
584
585 /// Try to grab an instance of the onchip Voltage Reference High ([VrefH]) channel.
586 pub fn vref_h(&mut self) -> Result<Analog<VrefH<Input>>, Error> {
587 self.vref_h.take().ok_or(Error::Moved)
588 }
589
590 /// Return the instance of [VrefH]
591 pub fn return_vref_h(&mut self, inst: Analog<VrefH<Input>>) {
592 self.vref_h.replace(inst);
593 }
594
595 /// Try to grab an instance of the onchip Voltage Reference Low ([VrefL]) channel.
596 pub fn vref_l(&mut self) -> Result<Analog<VrefL<Input>>, Error> {
597 self.vref_l.take().ok_or(Error::Moved)
598 }
599
600 /// Return the instance of [VrefL]
601 pub fn return_vref_l(&mut self, inst: Analog<VrefL<Input>>) {
602 self.vref_l.replace(inst);
603 }
604
605 /// Grab a [DummyDisable] instance. Multiple Instances possible.
606 pub fn dummy_disable(&self) -> Analog<DummyDisable<Input>> {
607 Analog {
608 pin: DummyDisable::<Input> { _mode: PhantomData },
609 }
610 }
611}
612
613/// Holds On-Chip ADC Channel inputs and provides an interface to grab and return them.
614// These have to have the Input dummy type to allow them to have the Channel
615// trait.
616pub struct OnChipChannels {
617 vss: Option<Analog<Vss<Input>>>,
618 temp_sense: Option<Analog<TempSense<Input>>>,
619 bandgap: Option<Analog<Bandgap<Input>>>,
620 vref_h: Option<Analog<VrefH<Input>>>,
621 vref_l: Option<Analog<VrefL<Input>>>,
622}
623
624/// Dummy type state for on-chip ADC input channels
625pub struct Input;
626
627/// Adc Input Channel, measures ground (should be 0?)
628pub struct Vss<Input> {
629 _mode: PhantomData<Input>,
630}
631
632/// Adc Input Channel, measures internal temperature sensor
633pub struct TempSense<Input> {
634 _mode: PhantomData<Input>,
635}
636
637/// Adc Input Channel, Bandgap internal voltage reference
638pub struct Bandgap<Input> {
639 _mode: PhantomData<Input>,
640}
641
642/// Adc Input Channel, Voltage Reference, High
643pub struct VrefH<Input> {
644 _mode: PhantomData<Input>,
645}
646
647/// Adc Input Channel, Voltage Reference, Low
648pub struct VrefL<Input> {
649 _mode: PhantomData<Input>,
650}
651
652/// Dummy Channel that temporarily disables the Adc Module.
653pub struct DummyDisable<Input> {
654 _mode: PhantomData<Input>,
655}
656macro_rules! adc_input_channels {
657 ( $($Chan:expr => $Pin:ident),+ $(,)*) => {
658 $(
659 impl<OldMode> Channel<Adc<Enabled>> for Analog<$Pin<OldMode>> {
660 type ID = u8;
661 fn channel() -> u8 { $Chan }
662 }
663 )+
664 };
665}
666
667use crate::gpio::{gpioa::*, gpiob::*};
668adc_input_channels! (
669 0_u8 => PTA0,
670 1_u8 => PTA1,
671 2_u8 => PTA6,
672 3_u8 => PTA7,
673 4_u8 => PTB0,
674 5_u8 => PTB1,
675 6_u8 => PTB2,
676 7_u8 => PTB3,
677 8_u8 => PTC0,
678 9_u8 => PTC1,
679 10_u8 => PTC2,
680 11_u8 => PTC3,
681 12_u8 => PTF4,
682 13_u8 => PTF5,
683 14_u8 => PTF6,
684 15_u8 => PTF7,
685 16_u8 => Vss,
686 22_u8 => TempSense,
687 23_u8 => Bandgap,
688 24_u8 => VrefH,
689 25_u8 => VrefL,
690 0x1F_u8 => DummyDisable,
691);
692
693macro_rules! impl_analog_pin {
694 ( $($Chan:expr => $Pin:ident),+ $(,)*) => {
695 $(
696 impl<OldMode> $Pin<OldMode> {
697 /// Convert Pin into the [Analog] state for use by the ADC.
698 ///
699 /// This implementation provides the GPIO interface a method to
700 /// give an eligible pin to the ADC peripheral for conversion
701 /// into an Analog pin. This method is only implemented in
702 /// eligible pins. The ADC peripheral disables the GPIO and
703 /// PORT control over the pin and connects it to the ADC mux
704 /// (controlled by [Adc::set_channel].
705 ///
706 /// Note: The [Analog::outof_analog] method must be used to
707 /// return the pin to a normal Input/Output typestate. The pin
708 /// will be returned in the same typestate as it was received.
709 pub fn into_analog(self) -> Analog<$Pin<OldMode>> {
710 unsafe {
711 (*ADC::ptr())
712 .apctl1
713 .modify(|r, w| w.adpc().bits(r.adpc().bits() | (1 << $Chan)));
714 }
715 Analog { pin: self }
716 }
717 }
718
719 impl<OldMode> Analog<$Pin<OldMode>> {
720 /// Return Analog state Pin to normal GPIO-state interface.
721 ///
722 /// The Pin will be in the same state that it was when it
723 /// entered the Analog type state.
724 pub fn outof_analog(self) -> $Pin<OldMode> {
725 let adc = unsafe { &(*ADC::ptr()) };
726 adc.apctl1
727 .modify(|r, w| unsafe { w.adpc().bits(r.adpc().bits() & !(1 << $Chan)) });
728 self.pin
729 }
730 }
731 )+
732 };
733}
734
735impl_analog_pin!(
736 0_u8 => PTA0,
737 1_u8 => PTA1,
738 2_u8 => PTA6,
739 3_u8 => PTA7,
740 4_u8 => PTB0,
741 5_u8 => PTB1,
742 6_u8 => PTB2,
743 7_u8 => PTB3,
744 8_u8 => PTC0,
745 9_u8 => PTC1,
746 10_u8 => PTC2,
747 11_u8 => PTC3,
748 12_u8 => PTF4,
749 13_u8 => PTF5,
750 14_u8 => PTF6,
751 15_u8 => PTF7,
752);
753
754impl<Pin> OneShot<Adc<Enabled>, u16, Pin> for Adc<Enabled>
755where
756 Pin: Channel<Adc<Enabled>, ID = u8>,
757{
758 type Error = Infallible;
759
760 fn read(&mut self, pin: &mut Pin) -> nb::Result<u16, Self::Error> {
761 self.set_channel(pin);
762 while !self.is_done() {}
763 let ret_val = Ok(self.result());
764 let disable = self.onchip_channels.dummy_disable();
765 self.set_channel(&disable);
766 ret_val
767 }
768}