atmega_hal/
adc.rs

1//! Analog-to-Digital Converter
2//!
3//! # Example
4//!
5//! Complete example source code can be found in the repository:
6//! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs)
7//!
8//! ```
9//! let dp = atmega_hal::Peripherals::take().unwrap();
10//! let pins = atmega_hal::pins!(dp);
11//!
12//! let mut adc = Adc::new(dp.ADC, Default::default());
13//!
14//! let channels: [atmega_hal::adc::Channel; 4] = [
15//!     pins.pf0.into_analog_input(&mut adc).into_channel(),
16//!     pins.pf1.into_analog_input(&mut adc).into_channel(),
17//!     pins.pf2.into_analog_input(&mut adc).into_channel(),
18//!     pins.pf3.into_analog_input(&mut adc).into_channel(),
19//! ];
20//!
21//! for (index, channel) in channels.iter().enumerate() {
22//!     let value = adc.read_blocking(channel);
23//!     ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap();
24//! }
25//! ```
26
27use crate::port;
28pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider};
29
30/// Select the voltage reference for the ADC peripheral
31///
32/// The internal voltage reference options may not be used if an external reference voltage is
33/// being applied to the AREF pin.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[repr(u8)]
36pub enum ReferenceVoltage {
37    /// Voltage applied to AREF pin.
38    Aref,
39    /// Default reference voltage (default).
40    AVcc,
41    /// Internal reference voltage.
42    Internal,
43}
44
45impl Default for ReferenceVoltage {
46    fn default() -> Self {
47        Self::AVcc
48    }
49}
50
51/// Configuration for the ADC peripheral.
52#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
53pub struct AdcSettings {
54    pub clock_divider: ClockDivider,
55    pub ref_voltage: ReferenceVoltage,
56}
57
58fn apply_settings(peripheral: &crate::pac::ADC, settings: AdcSettings) {
59    peripheral.adcsra.write(|w| {
60        w.aden().set_bit();
61        match settings.clock_divider {
62            ClockDivider::Factor2 => w.adps().prescaler_2(),
63            ClockDivider::Factor4 => w.adps().prescaler_4(),
64            ClockDivider::Factor8 => w.adps().prescaler_8(),
65            ClockDivider::Factor16 => w.adps().prescaler_16(),
66            ClockDivider::Factor32 => w.adps().prescaler_32(),
67            ClockDivider::Factor64 => w.adps().prescaler_64(),
68            ClockDivider::Factor128 => w.adps().prescaler_128(),
69        }
70    });
71    peripheral.admux.write(|w| match settings.ref_voltage {
72        ReferenceVoltage::Aref => w.refs().aref(),
73        ReferenceVoltage::AVcc => w.refs().avcc(),
74        ReferenceVoltage::Internal => w.refs().internal(),
75    });
76}
77
78/// Check the [`avr_hal_generic::adc::Adc`] documentation.
79pub type Adc<CLOCK> = avr_hal_generic::adc::Adc<crate::Atmega, crate::pac::ADC, CLOCK>;
80
81/// Check the [`avr_hal_generic::adc::Channel`] documentation.
82pub type Channel = avr_hal_generic::adc::Channel<crate::Atmega, crate::pac::ADC>;
83
84/// Additional channels
85///
86/// Some channels are not directly connected to pins.  This module provides types which can be used
87/// to access them.
88///
89/// # Example
90/// ```
91/// let dp = atmega_hal::Peripherals::take().unwrap();
92/// let mut adc = atmega_hal::Adc::new(dp.ADC, Default::default());
93///
94/// let value = adc.read_blocking(&channel::Vbg);
95/// ```
96pub mod channel {
97    #[cfg(all(
98        any(
99            feature = "atmega168",
100            feature = "atmega32a",
101            feature = "atmega328p",
102            feature = "atmega328pb",
103            feature = "atmega48p",
104            feature = "atmega128a",
105            feature = "atmega1284p",
106            feature = "atmega8",
107            feature = "atmega88p"
108        ),
109        feature = "enable-extra-adc",
110    ))]
111    pub struct ADC6;
112    #[cfg(all(
113        any(
114            feature = "atmega168",
115            feature = "atmega32a",
116            feature = "atmega328p",
117            feature = "atmega328pb",
118            feature = "atmega48p",
119            feature = "atmega128a",
120            feature = "atmega1284p",
121            feature = "atmega8",
122            feature = "atmega88p"
123        ),
124        feature = "enable-extra-adc",
125    ))]
126    pub struct ADC7;
127    #[cfg(any(
128        feature = "atmega1280",
129        feature = "atmega16",
130        feature = "atmega168",
131        feature = "atmega2560",
132        feature = "atmega32a",
133        feature = "atmega328p",
134        feature = "atmega328pb",
135        feature = "atmega32u4",
136        feature = "atmega48p",
137        feature = "atmega128a",
138        feature = "atmega1284p",
139        feature = "atmega8",
140        feature = "atmega16",
141        feature = "atmega164pa",
142        feature = "atmega88p"
143    ))]
144    pub struct Vbg;
145    #[cfg(any(
146        feature = "atmega1280",
147        feature = "atmega168",
148        feature = "atmega2560",
149        feature = "atmega32a",
150        feature = "atmega328p",
151        feature = "atmega328pb",
152        feature = "atmega32u4",
153        feature = "atmega48p",
154        feature = "atmega128a",
155        feature = "atmega1284p",
156        feature = "atmega8",
157        feature = "atmega16",
158        feature = "atmega164pa",
159        feature = "atmega88p"
160    ))]
161    pub struct Gnd;
162    #[cfg(any(
163        feature = "atmega328p",
164        feature = "atmega328pb",
165        feature = "atmega32u4",
166        feature = "atmega48p",
167        feature = "atmega88p"
168    ))]
169    pub struct Temperature;
170}
171
172#[cfg(any(
173    feature = "atmega168",
174    feature = "atmega328p",
175    feature = "atmega328pb",
176    feature = "atmega48p",
177    feature = "atmega88p"
178))]
179avr_hal_generic::impl_adc! {
180    hal: crate::Atmega,
181    peripheral: crate::pac::ADC,
182    settings: AdcSettings,
183    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
184    channel_id: crate::pac::adc::admux::MUX_A,
185    set_channel: |peripheral, id| {
186        peripheral.admux.modify(|_, w| w.mux().variant(id));
187    },
188    pins: {
189        port::PC0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d),
190        port::PC1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d),
191        port::PC2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d),
192        port::PC3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d),
193        port::PC4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d),
194        port::PC5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d),
195    },
196    channels: {
197        #[cfg(feature = "enable-extra-adc")]
198        channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6,
199        #[cfg(feature = "enable-extra-adc")]
200        channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7,
201        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
202        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
203        #[cfg(any(feature = "atmega328p", feature = "atmega328pb", feature = "atmega48p"))]
204        channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS,
205    },
206}
207
208#[cfg(any(feature = "atmega16", feature = "atmega32a"))]
209avr_hal_generic::impl_adc! {
210    hal: crate::Atmega,
211    peripheral: crate::pac::ADC,
212    settings: AdcSettings,
213    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
214    channel_id: crate::pac::adc::admux::MUX_A,
215    set_channel: |peripheral, id| {
216        peripheral.admux.modify(|_, w| w.mux().variant(id));
217    },
218    pins: {
219        port::PA0: (crate::pac::adc::admux::MUX_A::ADC0),
220        port::PA1: (crate::pac::adc::admux::MUX_A::ADC1),
221        port::PA2: (crate::pac::adc::admux::MUX_A::ADC2),
222        port::PA3: (crate::pac::adc::admux::MUX_A::ADC3),
223        port::PA4: (crate::pac::adc::admux::MUX_A::ADC4),
224        port::PA5: (crate::pac::adc::admux::MUX_A::ADC5),
225        port::PA6: (crate::pac::adc::admux::MUX_A::ADC6),
226        port::PA7: (crate::pac::adc::admux::MUX_A::ADC7),
227    },
228    channels: {
229        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
230        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
231    },
232}
233
234#[cfg(feature = "atmega32u4")]
235avr_hal_generic::impl_adc! {
236    hal: crate::Atmega,
237    peripheral: crate::pac::ADC,
238    settings: AdcSettings,
239    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
240    channel_id: u8,
241    set_channel: |peripheral, id| {
242        peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f));
243        peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0));
244    },
245    pins: {
246        port::PF0: (0b000000, didr0::adc0d),
247        port::PF1: (0b000001, didr0::adc1d),
248        port::PF4: (0b000100, didr0::adc4d),
249        port::PF5: (0b000101, didr0::adc5d),
250        port::PF6: (0b000110, didr0::adc6d),
251        port::PF7: (0b000111, didr0::adc7d),
252        port::PD4: (0b100000, didr2::adc8d),
253        port::PD6: (0b100001, didr2::adc9d),
254        port::PD7: (0b100010, didr2::adc10d),
255        port::PB4: (0b100011, didr2::adc11d),
256        port::PB5: (0b100100, didr2::adc12d),
257        port::PB6: (0b100101, didr2::adc13d),
258    },
259    channels: {
260        channel::Vbg: 0b011110,
261        channel::Gnd: 0b011111,
262        channel::Temperature: 0b100111,
263    },
264}
265
266#[cfg(feature = "atmega128a")]
267avr_hal_generic::impl_adc! {
268    hal: crate::Atmega,
269    peripheral: crate::pac::ADC,
270    settings: AdcSettings,
271    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
272    channel_id: crate::pac::adc::admux::MUX_A,
273    set_channel: |peripheral, id| {
274        peripheral.admux.modify(|_, w| w.mux().variant(id));
275    },
276    pins: {
277        port::PF0: (crate::pac::adc::admux::MUX_A::ADC0),
278        port::PF1: (crate::pac::adc::admux::MUX_A::ADC1),
279        port::PF2: (crate::pac::adc::admux::MUX_A::ADC2),
280        port::PF3: (crate::pac::adc::admux::MUX_A::ADC3),
281        port::PF4: (crate::pac::adc::admux::MUX_A::ADC4),
282        port::PF5: (crate::pac::adc::admux::MUX_A::ADC5),
283        port::PF6: (crate::pac::adc::admux::MUX_A::ADC6),
284        port::PF7: (crate::pac::adc::admux::MUX_A::ADC7),
285    },
286    channels: {
287        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
288        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
289    },
290}
291
292#[cfg(any(feature = "atmega2560", feature = "atmega1280"))]
293avr_hal_generic::impl_adc! {
294    hal: crate::Atmega,
295    peripheral: crate::pac::ADC,
296    settings: AdcSettings,
297    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
298    channel_id: u8,
299    set_channel: |peripheral, id| {
300        peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f));
301        peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0));
302    },
303    pins: {
304        port::PF0: (0b000000, didr0::adc0d),
305        port::PF1: (0b000001, didr0::adc1d),
306        port::PF2: (0b000010, didr0::adc2d),
307        port::PF3: (0b000011, didr0::adc3d),
308        port::PF4: (0b000100, didr0::adc4d),
309        port::PF5: (0b000101, didr0::adc5d),
310        port::PF6: (0b000110, didr0::adc6d),
311        port::PF7: (0b000111, didr0::adc7d),
312        port::PK0: (0b100000, didr2::adc8d),
313        port::PK1: (0b100001, didr2::adc9d),
314        port::PK2: (0b100010, didr2::adc10d),
315        port::PK3: (0b100011, didr2::adc11d),
316        port::PK4: (0b100100, didr2::adc12d),
317        port::PK5: (0b100101, didr2::adc13d),
318        port::PK6: (0b100110, didr2::adc14d),
319        port::PK7: (0b100111, didr2::adc15d),
320    },
321    channels: {
322        channel::Vbg: 0b011110,
323        channel::Gnd: 0b011111,
324    },
325}
326
327#[cfg(any(feature = "atmega1284p"))]
328avr_hal_generic::impl_adc! {
329    hal: crate::Atmega,
330    peripheral: crate::pac::ADC,
331    settings: AdcSettings,
332    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
333    channel_id: crate::pac::adc::admux::MUX_A,
334    set_channel: |peripheral, id| {
335        peripheral.admux.modify(|_, w| w.mux().variant(id));
336    },
337    pins: {
338        port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d),
339        port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d),
340        port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d),
341        port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d),
342        port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d),
343        port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d),
344    },
345    channels: {
346        #[cfg(feature = "enable-extra-adc")]
347        channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6,
348        #[cfg(feature = "enable-extra-adc")]
349        channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7,
350        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
351        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
352    },
353}
354
355#[cfg(any(feature = "atmega8"))]
356avr_hal_generic::impl_adc! {
357    hal: crate::Atmega,
358    peripheral: crate::pac::ADC,
359    settings: AdcSettings,
360    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
361    channel_id: crate::pac::adc::admux::MUX_A,
362    set_channel: |peripheral, id| {
363        peripheral.admux.modify(|_, w| w.mux().variant(id));
364    },
365    pins: {
366        port::PC0: (crate::pac::adc::admux::MUX_A::ADC0),
367        port::PC1: (crate::pac::adc::admux::MUX_A::ADC1),
368        port::PC2: (crate::pac::adc::admux::MUX_A::ADC2),
369        port::PC3: (crate::pac::adc::admux::MUX_A::ADC3),
370        port::PC4: (crate::pac::adc::admux::MUX_A::ADC4),
371        port::PC5: (crate::pac::adc::admux::MUX_A::ADC5),
372    },
373    channels: {
374        #[cfg(feature = "enable-extra-adc")]
375        channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6,
376        #[cfg(feature = "enable-extra-adc")]
377        channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7,
378        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
379        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
380    },
381}
382
383#[cfg(any(feature = "atmega164pa"))]
384avr_hal_generic::impl_adc! {
385    hal: crate::Atmega,
386    peripheral: crate::pac::ADC,
387    settings: AdcSettings,
388    apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) },
389    channel_id: crate::pac::adc::admux::MUX_A,
390    set_channel: |peripheral, id| {
391        peripheral.admux.modify(|_, w| w.mux().variant(id));
392    },
393    pins: {
394        port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d),
395        port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d),
396        port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d),
397        port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d),
398        port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d),
399        port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d),
400        port::PA6: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d),
401        port::PA7: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d),
402    },
403    channels: {
404        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
405        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
406    },
407}