attiny_hal/
adc.rs

1#![allow(non_camel_case_types)]
2//! Analog-to-Digital Converter
3//!
4//! # Example
5//!
6//! For full source code, please refer to the ATmega ADC example:
7//! [`atmega2560-adc.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-adc.rs)
8//!
9//! ```
10//! let dp = attiny_hal::Peripherals::take().unwrap();
11//! let pins = attiny_hal::pins!(dp);
12//!
13//! let mut adc = Adc::new(dp.ADC, Default::default());
14//!
15//! let channels: [attiny_hal::adc::Channel; 4] = [
16//!     pins.pa0.into_analog_input(&mut adc).into_channel(),
17//!     pins.pa1.into_analog_input(&mut adc).into_channel(),
18//!     pins.pa2.into_analog_input(&mut adc).into_channel(),
19//!     pins.pa3.into_analog_input(&mut adc).into_channel(),
20//! ];
21//!
22//! for (index, channel) in channels.iter().enumerate() {
23//!     let value = adc.read_blocking(channel);
24//!     ufmt::uwrite!(&mut serial, "CH{}: {} ", index, value).unwrap();
25//! }
26//! ```
27
28use crate::port;
29pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider};
30
31/// Select the voltage reference for the ADC peripheral
32///
33/// The internal voltage reference options may not be used if an external reference voltage is
34/// being applied to the AREF pin.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36#[repr(u8)]
37pub enum ReferenceVoltage {
38    /// Voltage applied to AREF pin.
39    #[cfg(any(feature = "attiny85", feature = "attiny167",))]
40    Aref,
41    /// Default reference voltage (default).
42    AVcc,
43    /// Internal 1.1V reference.
44    Internal1_1,
45    /// Internal 2.56V reference.
46    #[cfg(any(feature = "attiny85", feature = "attiny167",))]
47    Internal2_56,
48}
49
50impl Default for ReferenceVoltage {
51    fn default() -> Self {
52        Self::AVcc
53    }
54}
55
56/// Configuration for the ADC peripheral.
57#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
58pub struct AdcSettings {
59    pub clock_divider: ClockDivider,
60    pub ref_voltage: ReferenceVoltage,
61}
62
63/// Check the [`avr_hal_generic::adc::Adc`] documentation.
64pub type Adc<CLOCK> = avr_hal_generic::adc::Adc<crate::Attiny, crate::pac::ADC, CLOCK>;
65
66/// Check the [`avr_hal_generic::adc::Channel`] documentation.
67pub type Channel = avr_hal_generic::adc::Channel<crate::Attiny, crate::pac::ADC>;
68
69/// Additional channels
70///
71/// Some channels are not directly connected to pins.  This module provides types which can be used
72/// to access them.
73///
74/// # Example
75/// ```
76/// let dp = attiny_hal::Peripherals::take().unwrap();
77/// let mut adc = attiny_hal::Adc::new(dp.ADC, Default::default());
78///
79/// let value = adc.read_blocking(&channel::Vbg);
80/// ```
81pub mod channel {
82    #[cfg(feature = "attiny167")]
83    pub struct AVcc_4;
84    pub struct Vbg;
85    pub struct Gnd;
86    pub struct Temperature;
87}
88
89fn apply_clock(peripheral: &crate::pac::ADC, settings: AdcSettings) {
90    peripheral.adcsra.write(|w| {
91        w.aden().set_bit();
92        match settings.clock_divider {
93            ClockDivider::Factor2 => w.adps().prescaler_2(),
94            ClockDivider::Factor4 => w.adps().prescaler_4(),
95            ClockDivider::Factor8 => w.adps().prescaler_8(),
96            ClockDivider::Factor16 => w.adps().prescaler_16(),
97            ClockDivider::Factor32 => w.adps().prescaler_32(),
98            ClockDivider::Factor64 => w.adps().prescaler_64(),
99            ClockDivider::Factor128 => w.adps().prescaler_128(),
100        }
101    });
102}
103
104#[cfg(feature = "attiny85")]
105avr_hal_generic::impl_adc! {
106    hal: crate::Attiny,
107    peripheral: crate::pac::ADC,
108    settings: AdcSettings,
109    apply_settings: |peripheral, settings| {
110        apply_clock(peripheral, settings);
111        peripheral.admux.write(|w| match settings.ref_voltage {
112            ReferenceVoltage::Aref => w.refs().aref(),
113            ReferenceVoltage::AVcc => w.refs().vcc(),
114            ReferenceVoltage::Internal1_1 => w.refs().internal().refs2().clear_bit(),
115            ReferenceVoltage::Internal2_56 => w.refs().internal().refs2().set_bit(),
116        });
117    },
118    channel_id: crate::pac::adc::admux::MUX_A,
119    set_channel: |peripheral, id| {
120        peripheral.admux.modify(|_, w| w.mux().variant(id));
121    },
122    pins: {
123        port::PB5: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d),
124        port::PB2: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d),
125        port::PB4: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d),
126        port::PB3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d),
127    },
128    channels: {
129        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
130        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
131        channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS,
132    },
133}
134
135#[cfg(feature = "attiny88")]
136avr_hal_generic::impl_adc! {
137    hal: crate::Attiny,
138    peripheral: crate::pac::ADC,
139    settings: AdcSettings,
140    apply_settings: |peripheral, settings| {
141        apply_clock(peripheral, settings);
142        peripheral.admux.write(|w| match settings.ref_voltage {
143            ReferenceVoltage::AVcc => w.refs0().avcc(),
144            ReferenceVoltage::Internal1_1 => w.refs0().internal(),
145        });
146    },
147    channel_id: crate::pac::adc::admux::MUX_A,
148    set_channel: |peripheral, id| {
149        peripheral.admux.modify(|_, w| w.mux().variant(id));
150    },
151    pins: {
152        port::PC0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d),
153        port::PC1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d),
154        port::PC2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d),
155        port::PC3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d),
156        port::PC4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d),
157        port::PC5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d),
158        port::PA0: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d),
159        port::PA1: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d),
160    },
161    channels: {
162        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
163        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
164        channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS,
165    },
166}
167
168#[cfg(feature = "attiny167")]
169avr_hal_generic::impl_adc! {
170    hal: crate::Attiny,
171    peripheral: crate::pac::ADC,
172    settings: AdcSettings,
173    apply_settings: |peripheral, settings| {
174        apply_clock(peripheral, settings);
175        peripheral.amiscr.write(|w| match settings.ref_voltage {
176            ReferenceVoltage::Aref => w.arefen().set_bit(),
177            _ => w.arefen().clear_bit(),
178        });
179        peripheral.admux.write(|w| match settings.ref_voltage {
180            ReferenceVoltage::Aref => w.refs().avcc(),
181            ReferenceVoltage::AVcc => w.refs().avcc(),
182            ReferenceVoltage::Internal1_1 => w.refs().internal_11(),
183            ReferenceVoltage::Internal2_56 => w.refs().internal_256(),
184        });
185    },
186    channel_id: crate::pac::adc::admux::MUX_A,
187    set_channel: |peripheral, id| {
188        peripheral.admux.modify(|_, w| w.mux().variant(id));
189    },
190    pins: {
191        port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d),
192        port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d),
193        port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d),
194        port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d),
195        port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d),
196        port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d),
197        port::PA6: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d),
198        port::PA7: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d),
199        port::PB5: (crate::pac::adc::admux::MUX_A::ADC8, didr1::adc8d),
200        port::PB6: (crate::pac::adc::admux::MUX_A::ADC9, didr1::adc9d),
201        port::PB7: (crate::pac::adc::admux::MUX_A::ADC10, didr1::adc10d),
202    },
203    channels: {
204        channel::AVcc_4: crate::pac::adc::admux::MUX_A::ADC_AVCC_4,
205        channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG,
206        channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND,
207        channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS,
208    },
209}