diff --git a/avr-hal-generic/src/adc.rs b/avr-hal-generic/src/adc.rs index 608d667feb..034fbee3bb 100644 --- a/avr-hal-generic/src/adc.rs +++ b/avr-hal-generic/src/adc.rs @@ -1,11 +1,35 @@ -/// Analog-to-Digial converter +//! Analog-to-Digial Converter (ADC) +//! +//! # Basic information +//! +//! The AVR chips have ADCs, which allow the CPU to acquire information about +//! the "intensity" of a signal, in this case via voltage measurement. This is +//! in contrast to a digital input, which only acquires information about +//! whether there is signal or not. +//! +//! To do this, the converter has circuitry to transform this single continuous +//! signal into multiple discrete signals which the CPU can understand. These +//! signals map to increasing digits of a binary integer, and interpolating this +//! up-counter to a known scale yields "analog" information the chip can use. +//! +//! # Advanced information +//! +//! Due to size and resource constraints, some complexities are introduced to +//! aliviate issues in manufacturing. In this case, there's only one CPU +//! register to read all conversions, and the various ADC channels are +//! multiplexed to it via selection registers. Also, each channel can read from +//! any of a few pin choices, again via multiplexing with a selector. +//! Furthermore, we can choose to measure voltage with respect to references +//! other than the system GND. This module accounts for all these choices +//! statically with optional dynamic casting. + use core::marker::PhantomData; /// The division factor between the system clock frequency and the input clock to the AD converter. /// /// To get 10-bit precision, clock from 50kHz to 200kHz must be supplied. If you need less /// precision, you can supply a higher clock. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum ClockDivider { Factor2, @@ -14,16 +38,10 @@ pub enum ClockDivider { Factor16, Factor32, Factor64, - /// (default) + #[default] Factor128, } -impl Default for ClockDivider { - fn default() -> Self { - Self::Factor128 - } -} - /// Internal trait for the low-level ADC peripheral. /// /// **Prefer using the [`Adc`] API instead of this trait.** @@ -214,39 +232,116 @@ where } } +/// Generates implementations for the ADC traits and types plus some helper +/// types. +/// +/// # Usage +/// +/// *This is an internal macro of the library, user code does not need this.* +/// The main generator code is in the first alternative, it's fully generic to +/// what can vary between chips. For the Atmegas, which are pretty consistent, 2 +/// convinience variants are provided that expand to the first with common +/// elements filled. +/// +/// ## Adding a new implementation +/// +/// The generic variant requires the following information (should be extracted +/// from the datasheet), generally in the form of register/bit names and masks +/// to generate safe Rust types properly: +/// - Available voltage references against which the ADC will compare; +/// - Passed as variants of a `ReferenceVoltage` enum; +/// - Procedure to select a reference; +/// - Passed as a function definition in a `set_reference` item, that must +/// set register state according to an argument with type `ReferenceVoltage` +/// defined above; +/// - Available ADC channels on the multiplexer; +/// - Passed as variants to a fake `Channels` enum, from which standalone structs +/// are generated per variant; The implementation of the structs is +/// parameterized by the value assigned to the fake variant, and should +/// be chosen as either [`crate::pac`] items or bitmasks that help the +/// assignment procedure; +/// - Procedure to select a channel; +/// - Passed as a function definition in a `set_channel` item, that must set +/// register state according to an argument with type [`AdcOps::Channel`] +/// adequate to the trait implementations; +/// - Available pins and respective channel; +/// - Passed as fake constant definitions that inform the pin type (see +/// [`crate::port`]), the corresponding register and bit to enable/disable +/// it, plus the value used to distinguish it when dynamic cast (an +/// arbitrary ID of sorts). +/// +/// Helper matchers are defined for a "MegaA" kind, which only has one ADC +/// channel, and a "MegaAB" kind, which has two. These expand to calls of the +/// main one, because there are similarity patterns in the atmegas. The attinys +/// seem to have no recognizable pattern, so defining something like that would +/// be counterproductive; use the generic one unless you see the possibility to +/// merge your new chip with an existing chip. +/// +/// # Example +/// +/// ```ignore +/// #[cfg(any( +/// feature = "atmega328p", +/// // ... +/// ))] +/// avr_hal_generic::impl_adc! { +/// impl AdcProvider for pac::ADC { +/// type Hal = crate::Atmega; +/// +/// const PC0: DIDR0::ADC0D = pac::adc::admux::MUX_A::ADC0; +/// const PC1: DIDR0::ADC1D = pac::adc::admux::MUX_A::ADC1; +/// // ... +/// } +/// +/// type ChannelId = pac::adc::admux::MUX_A; // Or u8 if PAC doesn't define variants. +/// pub enum Channels { +/// channel::ADC7 = pac::adc::admux::MUX_A::ADC7, +/// channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, +/// // ... +/// } +/// } +/// ``` #[macro_export] macro_rules! impl_adc { ( - hal: $HAL:ty, - peripheral: $ADC:ty, - settings: $Settings:ty, - apply_settings: |$settings_periph_var:ident, $settings_var:ident| $apply_settings:block, - channel_id: $Channel:ty, - set_channel: |$periph_var:ident, $chan_var:ident| $set_channel:block, - pins: { - $( - $(#[$pin_attr:meta])* - $pin:ty: ($pin_channel:expr$(, $didr:ident::$didr_method:ident)?), - )+ - }, - $(channels: { - $( - $(#[$channel_attr:meta])* - $channel_ty:ty: $channel:expr, - )* - },)? + $(#[$ref_voltage_attr:meta])* pub enum ReferenceVoltage { + $($(#[$ref_voltage_variant_attr:meta])* $ref_voltage_variant:ident,)* + } + + pub fn set_reference($rself:ident, $rsettings:ident: Self::Settings) $set_reference_body:block + pub fn set_channel($cself:ident, $cchannel:ident: Self::Channel) $set_channel_body:block + + impl AdcProvider for $adc:ty { + type Hal = $hal:ty; + + $($(#[$pin_attr:meta])* + const $pin:ty$(: $pin_reg:ident::$pin_bit:ident)? = $pin_id:expr;)+ + } + + type ChannelId = $channel_type:ty; + pub enum Channels { + $($(#[$channel_attr:meta])* + $channel_variant:ty = $channel_id:expr,)+ + } ) => { - impl $crate::adc::AdcOps<$HAL> for $ADC { - type Channel = $Channel; - type Settings = $Settings; + $(#[$ref_voltage_attr])* + pub enum ReferenceVoltage { + $($(#[$ref_voltage_variant_attr])* $ref_voltage_variant),+ + } - #[inline] - fn raw_init(&mut self, settings: Self::Settings) { - let $settings_periph_var = self; - let $settings_var = settings; + /// Configuration for the ADC peripheral. + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] + pub struct AdcSettings { + pub clock_divider: $crate::adc::ClockDivider, + pub ref_voltage: ReferenceVoltage, + } - $apply_settings - } + impl $crate::adc::AdcOps<$hal> for $adc { + type Channel = $channel_type; + type Settings = AdcSettings; + + #[inline] + fn raw_init(&mut $rself, $rsettings: Self::Settings) $set_reference_body #[inline] fn raw_read_adc(&self) -> u16 { @@ -264,69 +359,195 @@ macro_rules! impl_adc { } #[inline] - fn raw_set_channel(&mut self, channel: Self::Channel) { - let $periph_var = self; - let $chan_var = channel; - - $set_channel - } + fn raw_set_channel(&mut $cself, $cchannel: Self::Channel) $set_channel_body #[inline] fn raw_enable_channel(&mut self, channel: Self::Channel) { - match channel { - $( - x if x == $pin_channel => { - $(self.$didr.modify(|_, w| w.$didr_method().set_bit());)? - } - )+ - _ => unreachable!(), + $crate::paste::paste! { + match channel { + $(x @ $pin_id => { $(self.[<$pin_reg:lower>].modify(|_, w| w.[<$pin_bit:lower>]().set_bit()))? }),+ + _ => unreachable!(), + } } } #[inline] fn raw_disable_channel(&mut self, channel: Self::Channel) { - match channel { - $( - x if x == $pin_channel => { - $(self.$didr.modify(|_, w| w.$didr_method().clear_bit());)? - } - )+ - _ => unreachable!(), + $crate::paste::paste! { + match channel { + $(x @ $pin_id => { $(self.[<$pin_reg:lower>].modify(|_, w| w.[<$pin_bit:lower>]().clear_bit()))? }),+ + _ => unreachable!(), + } } } } - $( - $(#[$pin_attr])* - impl $crate::adc::AdcChannel<$HAL, $ADC> for $crate::port::Pin<$crate::port::mode::Analog, $pin> { + $($(#[$pin_attr])* + impl $crate::adc::AdcChannel<$hal, $adc> for $crate::port::Pin<$crate::port::mode::Analog, $pin> { #[inline] - fn channel(&self) -> $Channel { - $pin_channel + fn channel(&self) -> $channel_type { + $pin_id + } + })+ + + $( + $(#[$channel_attr])* + impl $crate::adc::AdcChannel<$hal, $adc> for $channel_variant { + #[inline] + fn channel(&self) -> $channel_type { + $channel_id + } } - } )+ + $( + /// Convert this channel into a generic "[`Channel`][adc-channel]" type. + /// + /// The generic channel type can be used to store multiple channels in an array. + /// + /// [adc-channel]: crate::adc::Channel + $(#[$channel_attr])* + impl $channel_variant { + pub fn into_channel(self) -> $crate::adc::Channel<$hal, $adc> { + $crate::adc::Channel::new(self) + } + } + )* + }; - $($( - $(#[$channel_attr])* - impl $crate::adc::AdcChannel<$HAL, $ADC> for $channel_ty { - #[inline] - fn channel(&self) -> $Channel { - $channel + ( + impl AdcProvider for $adc:ty { + type Hal = $hal:ty; + + $($(#[$pin_attr:meta])* + const $pin:ty$(: $pin_reg:ident::$pin_bit:ident)? = $pin_id:expr;)+ + } + + type ChannelId = $channel_type:ty; + pub enum Channels { + $($(#[$channel_attr:meta])* + $channel_variant:ty = $channel_value:expr,)+ + } + ) => { + $crate::impl_adc! { + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + /// Voltage applied to AREF pin. + Aref, + /// System reference voltage, GND (default). + #[default] + AVcc, + /// Internal reference. + Internal, + } + + pub fn set_reference(self, settings: Self::Settings) { + self.adcsra.write(|w| { + w.aden().set_bit(); + match settings.clock_divider { + $crate::adc::ClockDivider::Factor2 => w.adps().prescaler_2(), + $crate::adc::ClockDivider::Factor4 => w.adps().prescaler_4(), + $crate::adc::ClockDivider::Factor8 => w.adps().prescaler_8(), + $crate::adc::ClockDivider::Factor16 => w.adps().prescaler_16(), + $crate::adc::ClockDivider::Factor32 => w.adps().prescaler_32(), + $crate::adc::ClockDivider::Factor64 => w.adps().prescaler_64(), + $crate::adc::ClockDivider::Factor128 => w.adps().prescaler_128(), + } + }); + self.admux.write(|w| match settings.ref_voltage { + ReferenceVoltage::Aref => w.refs().aref(), + ReferenceVoltage::AVcc => w.refs().avcc(), + ReferenceVoltage::Internal => w.refs().internal(), + }); + } + pub fn set_channel(self, channel: Self::Channel) { + self.admux.modify(|_, w| w.mux().variant(channel)); + } + + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + $($(#[$pin_attr])* + const $pin$(: $pin_reg::$pin_bit)? = $pin_id;)+ + } + + type ChannelId = $channel_type; + pub enum Channels { + $($(#[$channel_attr])* + $channel_variant = $channel_value,)+ } } + }; + ( + impl AdcProvider for $adc:ty { + type Hal = $hal:ty; - /// Convert this channel into a generic "[`Channel`][adc-channel]" type. - /// - /// The generic channel type can be used to store multiple channels in an array. - /// - /// [adc-channel]: crate::adc::Channel - $(#[$channel_attr])* - impl $channel_ty { - pub fn into_channel(self) -> $crate::adc::Channel<$HAL, $ADC> { - $crate::adc::Channel::new(self) + $($(#[$pin_attr:meta])* + const $pin:ty$(: $pin_reg:ident::$pin_bit:ident)? = $pin_id:expr;)+ + } + + pub enum Channels { + $($(#[$channel_attr:meta])* + $channel_variant:ty = $channel_value:expr,)+ + } + ) => { + $crate::impl_adc! { + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + /// Voltage applied to AREF pin. + Aref, + /// System reference voltage, GND (default). + #[default] + AVcc, + /// Internal reference. + Internal, + } + + pub fn set_reference(self, settings: Self::Settings) { + self.adcsra.write(|w| { + w.aden().set_bit(); + match settings.clock_divider { + $crate::adc::ClockDivider::Factor2 => w.adps().prescaler_2(), + $crate::adc::ClockDivider::Factor4 => w.adps().prescaler_4(), + $crate::adc::ClockDivider::Factor8 => w.adps().prescaler_8(), + $crate::adc::ClockDivider::Factor16 => w.adps().prescaler_16(), + $crate::adc::ClockDivider::Factor32 => w.adps().prescaler_32(), + $crate::adc::ClockDivider::Factor64 => w.adps().prescaler_64(), + $crate::adc::ClockDivider::Factor128 => w.adps().prescaler_128(), + } + }); + self.admux.write(|w| match settings.ref_voltage { + ReferenceVoltage::Aref => w.refs().aref(), + ReferenceVoltage::AVcc => w.refs().avcc(), + ReferenceVoltage::Internal => w.refs().internal(), + }); + } + pub fn set_channel(self, channel: Self::Channel) { + self.admux.modify(|_, w| w.mux().bits(channel & 0x1f)); + self.adcsrb.modify(|_, w| w.mux5().bit(channel & 0x20 != 0)); + } + + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + $($(#[$pin_attr])* + const $pin$(: $pin_reg::$pin_bit)? = $pin_id;)+ + } + + type ChannelId = u8; + pub enum Channels { + $($(#[$channel_attr])* + $channel_variant = $channel_value,)+ } } - )*)? }; } - diff --git a/avr-hal-generic/src/lib.rs b/avr-hal-generic/src/lib.rs index c9d5e3e66c..3b7cb0527e 100644 --- a/avr-hal-generic/src/lib.rs +++ b/avr-hal-generic/src/lib.rs @@ -1,6 +1,38 @@ #![no_std] #![cfg_attr(avr_hal_asm_macro, feature(asm_experimental_arch))] #![cfg_attr(not(avr_hal_asm_macro), feature(llvm_asm))] +//! Defines the internal API used to generate the per-device external API +//! (user-facing) in the HAL crates. +//! +//! # Macro Design (WIP) +//! +//! As part of an effort to make the macros here more maintainable and less +//! repetitive, they are being restructured module-by-module. Currently revised +//! modules are: +//! - [`adc`] +//! - [`port`] +//! +//! The general guiding principals are: +//! 1. What goes inside the macro invocation should look like regular code as +//! much as possible; +//! 2. Information related to groups of implementations of a feature should be +//! encoded as alternative matchers in the macro, rather than by introducing +//! many metavariables that each invocation will need to repeat; +//! As an example of such information, take the ADC's reference voltage. All +//! Atmega processors can be abstracted with the same definition of the +//! `ReferenceVoltage` type, but Attiny processors differ among themselves and +//! also from the Atmega implementation. Rather than leave that type up to the +//! invocation, write one fully general matcher and write smaller matchers that +//! expand to pre-filled versions of the former. The HAL crates then use these +//! as much as possible, falling back only when there is singular hardware +//! that would need its own matcher but would use it only once. +//! 3. Information unique to each implementation should be left to the +//! invocation, but make the macro smart enough to avoid repeating ourselves. +//! An example of this is the mapping between ADC channels and pins. The best +//! scenario here is a mapping like ` = `, maybe `: +//! = `, if there's more information needed to encode the mapping. +//! [`paste::paste`] can be used for gluing the information into adequate +//! identifiers. pub use embedded_hal_v0 as hal; diff --git a/mcu/atmega-hal/src/adc.rs b/mcu/atmega-hal/src/adc.rs index fde390b828..79421e0029 100644 --- a/mcu/atmega-hal/src/adc.rs +++ b/mcu/atmega-hal/src/adc.rs @@ -1,56 +1,8 @@ //! Analog-to-Digital Converter -use crate::port; +use crate::{pac, port::*}; pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider}; -/// Select the voltage reference for the ADC peripheral -/// -/// The internal voltage reference options may not be used if an external reference voltage is -/// being applied to the AREF pin. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum ReferenceVoltage { - /// Voltage applied to AREF pin. - Aref, - /// Default reference voltage (default). - AVcc, - /// Internal reference voltage. - Internal, -} - -impl Default for ReferenceVoltage { - fn default() -> Self { - Self::AVcc - } -} - -/// Configuration for the ADC peripheral. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -pub struct AdcSettings { - pub clock_divider: ClockDivider, - pub ref_voltage: ReferenceVoltage, -} - -fn apply_settings(peripheral: &crate::pac::ADC, settings: AdcSettings) { - peripheral.adcsra.write(|w| { - w.aden().set_bit(); - match settings.clock_divider { - ClockDivider::Factor2 => w.adps().prescaler_2(), - ClockDivider::Factor4 => w.adps().prescaler_4(), - ClockDivider::Factor8 => w.adps().prescaler_8(), - ClockDivider::Factor16 => w.adps().prescaler_16(), - ClockDivider::Factor32 => w.adps().prescaler_32(), - ClockDivider::Factor64 => w.adps().prescaler_64(), - ClockDivider::Factor128 => w.adps().prescaler_128(), - } - }); - peripheral.admux.write(|w| match settings.ref_voltage { - ReferenceVoltage::Aref => w.refs().aref(), - ReferenceVoltage::AVcc => w.refs().avcc(), - ReferenceVoltage::Internal => w.refs().internal(), - }); -} - /// Check the [`avr_hal_generic::adc::Adc`] documentation. pub type Adc = avr_hal_generic::adc::Adc; @@ -144,232 +96,195 @@ pub mod channel { feature = "atmega48p", ))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PC0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PC1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PC2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PC3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PC4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PC5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - }, - channels: { + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PC0: DIDR0::ADC0D = pac::adc::admux::MUX_A::ADC0; + const PC1: DIDR0::ADC1D = pac::adc::admux::MUX_A::ADC1; + const PC2: DIDR0::ADC2D = pac::adc::admux::MUX_A::ADC2; + const PC3: DIDR0::ADC3D = pac::adc::admux::MUX_A::ADC3; + const PC4: DIDR0::ADC4D = pac::adc::admux::MUX_A::ADC4; + const PC5: DIDR0::ADC5D = pac::adc::admux::MUX_A::ADC5; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { #[cfg(feature = "enable-extra-adc")] - channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6, + channel::ADC6 = pac::adc::admux::MUX_A::ADC6, #[cfg(feature = "enable-extra-adc")] - channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, + channel::ADC7 = pac::adc::admux::MUX_A::ADC7, + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, #[cfg(any(feature = "atmega328p", feature = "atmega328pb", feature = "atmega48p"))] - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, + channel::Temperature = pac::adc::admux::MUX_A::TEMPSENS, + } } #[cfg(any(feature = "atmega32a"))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5), - port::PA6: (crate::pac::adc::admux::MUX_A::ADC6), - port::PA7: (crate::pac::adc::admux::MUX_A::ADC7), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PA0 = pac::adc::admux::MUX_A::ADC0; + const PA1 = pac::adc::admux::MUX_A::ADC1; + const PA2 = pac::adc::admux::MUX_A::ADC2; + const PA3 = pac::adc::admux::MUX_A::ADC3; + const PA4 = pac::adc::admux::MUX_A::ADC4; + const PA5 = pac::adc::admux::MUX_A::ADC5; + const PA6 = pac::adc::admux::MUX_A::ADC6; + const PA7 = pac::adc::admux::MUX_A::ADC7; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + } } #[cfg(feature = "atmega32u4")] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: u8, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f)); - peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0)); - }, - pins: { - port::PF0: (0b000000, didr0::adc0d), - port::PF1: (0b000001, didr0::adc1d), - port::PF4: (0b000100, didr0::adc4d), - port::PF5: (0b000101, didr0::adc5d), - port::PF6: (0b000110, didr0::adc6d), - port::PF7: (0b000111, didr0::adc7d), - port::PD4: (0b100000, didr2::adc8d), - port::PD6: (0b100001, didr2::adc9d), - port::PD7: (0b100010, didr2::adc10d), - port::PB4: (0b100011, didr2::adc11d), - port::PB5: (0b100100, didr2::adc12d), - port::PB6: (0b100101, didr2::adc13d), - }, - channels: { - channel::Vbg: 0b011110, - channel::Gnd: 0b011111, - channel::Temperature: 0b100111, - }, + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PF0: DIDR0::ADC0D = 0b000000; + const PF1: DIDR0::ADC1D = 0b000001; + const PF4: DIDR0::ADC4D = 0b000100; + const PF5: DIDR0::ADC5D = 0b000101; + const PF6: DIDR0::ADC6D = 0b000110; + const PF7: DIDR0::ADC7D = 0b000111; + const PD4: DIDR2::ADC8D = 0b100000; + const PD6: DIDR2::ADC9D = 0b100001; + const PD7: DIDR2::ADC10D = 0b100010; + const PB4: DIDR2::ADC11D = 0b100011; + const PB5: DIDR2::ADC12D = 0b100100; + const PB6: DIDR2::ADC13D = 0b100101; + } + + pub enum Channels { + channel::Vbg = 0b011110, + channel::Gnd = 0b011111, + channel::Temperature = 0b100111, + } } -#[cfg(feature = "atmega128a")] +#[cfg(any(feature = "atmega128a"))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PF0: (crate::pac::adc::admux::MUX_A::ADC0), - port::PF1: (crate::pac::adc::admux::MUX_A::ADC1), - port::PF2: (crate::pac::adc::admux::MUX_A::ADC2), - port::PF3: (crate::pac::adc::admux::MUX_A::ADC3), - port::PF4: (crate::pac::adc::admux::MUX_A::ADC4), - port::PF5: (crate::pac::adc::admux::MUX_A::ADC5), - port::PF6: (crate::pac::adc::admux::MUX_A::ADC6), - port::PF7: (crate::pac::adc::admux::MUX_A::ADC7), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, -} + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PF0 = pac::adc::admux::MUX_A::ADC0; + const PF1 = pac::adc::admux::MUX_A::ADC1; + const PF2 = pac::adc::admux::MUX_A::ADC2; + const PF3 = pac::adc::admux::MUX_A::ADC3; + const PF4 = pac::adc::admux::MUX_A::ADC4; + const PF5 = pac::adc::admux::MUX_A::ADC5; + const PF6 = pac::adc::admux::MUX_A::ADC6; + const PF7 = pac::adc::admux::MUX_A::ADC7; + } + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + } +} #[cfg(any(feature = "atmega2560", feature = "atmega1280"))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: u8, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().bits(id & 0x1f)); - peripheral.adcsrb.modify(|_, w| w.mux5().bit(id & 0x20 != 0)); - }, - pins: { - port::PF0: (0b000000, didr0::adc0d), - port::PF1: (0b000001, didr0::adc1d), - port::PF2: (0b000010, didr0::adc2d), - port::PF3: (0b000011, didr0::adc3d), - port::PF4: (0b000100, didr0::adc4d), - port::PF5: (0b000101, didr0::adc5d), - port::PF6: (0b000110, didr0::adc6d), - port::PF7: (0b000111, didr0::adc7d), - port::PK0: (0b100000, didr2::adc8d), - port::PK1: (0b100001, didr2::adc9d), - port::PK2: (0b100010, didr2::adc10d), - port::PK3: (0b100011, didr2::adc11d), - port::PK4: (0b100100, didr2::adc12d), - port::PK5: (0b100101, didr2::adc13d), - port::PK6: (0b100110, didr2::adc14d), - port::PK7: (0b100111, didr2::adc15d), - }, - channels: { - channel::Vbg: 0b011110, - channel::Gnd: 0b011111, - }, + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PF0: DIDR0::ADC0D = 0b000000; + const PF1: DIDR0::ADC1D = 0b000001; + const PF2: DIDR0::ADC2D = 0b000010; + const PF3: DIDR0::ADC3D = 0b000011; + const PF4: DIDR0::ADC4D = 0b000100; + const PF5: DIDR0::ADC5D = 0b000101; + const PF6: DIDR0::ADC6D = 0b000110; + const PF7: DIDR0::ADC7D = 0b000111; + const PK0: DIDR2::ADC8D = 0b100000; + const PK1: DIDR2::ADC9D = 0b100001; + const PK2: DIDR2::ADC10D = 0b100010; + const PK3: DIDR2::ADC11D = 0b100011; + const PK4: DIDR2::ADC12D = 0b100100; + const PK5: DIDR2::ADC13D = 0b100101; + const PK6: DIDR2::ADC14D = 0b100110; + const PK7: DIDR2::ADC15D = 0b100111; + } + + pub enum Channels { + channel::Vbg = 0b011110, + channel::Gnd = 0b011111, + } } #[cfg(any(feature = "atmega1284p"))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - }, - channels: { + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PA0: DIDR0::ADC0D = pac::adc::admux::MUX_A::ADC0; + const PA1: DIDR0::ADC1D = pac::adc::admux::MUX_A::ADC1; + const PA2: DIDR0::ADC2D = pac::adc::admux::MUX_A::ADC2; + const PA3: DIDR0::ADC3D = pac::adc::admux::MUX_A::ADC3; + const PA4: DIDR0::ADC4D = pac::adc::admux::MUX_A::ADC4; + const PA5: DIDR0::ADC5D = pac::adc::admux::MUX_A::ADC5; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { #[cfg(feature = "enable-extra-adc")] - channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6, + channel::ADC6 = pac::adc::admux::MUX_A::ADC6, #[cfg(feature = "enable-extra-adc")] - channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, + channel::ADC7 = pac::adc::admux::MUX_A::ADC7, + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + } } #[cfg(any(feature = "atmega8"))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PC0: (crate::pac::adc::admux::MUX_A::ADC0), - port::PC1: (crate::pac::adc::admux::MUX_A::ADC1), - port::PC2: (crate::pac::adc::admux::MUX_A::ADC2), - port::PC3: (crate::pac::adc::admux::MUX_A::ADC3), - port::PC4: (crate::pac::adc::admux::MUX_A::ADC4), - port::PC5: (crate::pac::adc::admux::MUX_A::ADC5), - }, - channels: { + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PC0 = pac::adc::admux::MUX_A::ADC0; + const PC1 = pac::adc::admux::MUX_A::ADC1; + const PC2 = pac::adc::admux::MUX_A::ADC2; + const PC3 = pac::adc::admux::MUX_A::ADC3; + const PC4 = pac::adc::admux::MUX_A::ADC4; + const PC5 = pac::adc::admux::MUX_A::ADC5; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { #[cfg(feature = "enable-extra-adc")] - channel::ADC6: crate::pac::adc::admux::MUX_A::ADC6, + channel::ADC6 = pac::adc::admux::MUX_A::ADC6, #[cfg(feature = "enable-extra-adc")] - channel::ADC7: crate::pac::adc::admux::MUX_A::ADC7, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, + channel::ADC7 = pac::adc::admux::MUX_A::ADC7, + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + } } #[cfg(any(feature = "atmega164pa"))] avr_hal_generic::impl_adc! { - hal: crate::Atmega, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { apply_settings(peripheral, settings) }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - port::PA6: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), - port::PA7: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - }, + impl AdcProvider for pac::ADC { + type Hal = crate::Atmega; + + const PC0 = pac::adc::admux::MUX_A::ADC0; + const PC1 = pac::adc::admux::MUX_A::ADC1; + const PC2 = pac::adc::admux::MUX_A::ADC2; + const PC3 = pac::adc::admux::MUX_A::ADC3; + const PC4 = pac::adc::admux::MUX_A::ADC4; + const PC5 = pac::adc::admux::MUX_A::ADC5; + const PC6 = pac::adc::admux::MUX_A::ADC6; + const PC7 = pac::adc::admux::MUX_A::ADC7; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + } } diff --git a/mcu/attiny-hal/src/adc.rs b/mcu/attiny-hal/src/adc.rs index b877f4f8de..a12e3b6f7a 100644 --- a/mcu/attiny-hal/src/adc.rs +++ b/mcu/attiny-hal/src/adc.rs @@ -1,47 +1,9 @@ #![allow(non_camel_case_types)] //! Analog-to-Digital Converter -use crate::port; +use crate::{pac, port::*}; pub use avr_hal_generic::adc::{AdcChannel, AdcOps, ClockDivider}; -/// Select the voltage reference for the ADC peripheral -/// -/// The internal voltage reference options may not be used if an external reference voltage is -/// being applied to the AREF pin. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum ReferenceVoltage { - /// Voltage applied to AREF pin. - #[cfg(any( - feature = "attiny85", - feature = "attiny167", - ))] - Aref, - /// Default reference voltage (default). - AVcc, - /// Internal 1.1V reference. - Internal1_1, - /// Internal 2.56V reference. - #[cfg(any( - feature = "attiny85", - feature = "attiny167", - ))] - Internal2_56, -} - -impl Default for ReferenceVoltage { - fn default() -> Self { - Self::AVcc - } -} - -/// Configuration for the ADC peripheral. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -pub struct AdcSettings { - pub clock_divider: ClockDivider, - pub ref_voltage: ReferenceVoltage, -} - /// Check the [`avr_hal_generic::adc::Adc`] documentation. pub type Adc = avr_hal_generic::adc::Adc; @@ -68,127 +30,152 @@ pub mod channel { pub struct Temperature; } -fn apply_clock(peripheral: &crate::pac::ADC, settings: AdcSettings) { - peripheral.adcsra.write(|w| { - w.aden().set_bit(); - match settings.clock_divider { - ClockDivider::Factor2 => w.adps().prescaler_2(), - ClockDivider::Factor4 => w.adps().prescaler_4(), - ClockDivider::Factor8 => w.adps().prescaler_8(), - ClockDivider::Factor16 => w.adps().prescaler_16(), - ClockDivider::Factor32 => w.adps().prescaler_32(), - ClockDivider::Factor64 => w.adps().prescaler_64(), - ClockDivider::Factor128 => w.adps().prescaler_128(), - } - }); -} - - #[cfg(feature = "attiny85")] avr_hal_generic::impl_adc! { - hal: crate::Attiny, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { - apply_clock(peripheral, settings); - peripheral.admux.write(|w| match settings.ref_voltage { + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + /// Voltage applied to AREF pin. + Aref, + /// System reference voltage, GND (default). + #[default] + AVcc, + /// Internal 1.1V reference. + Internal1_1, + /// Internal 2.56V reference. + Internal2_56, + } + + pub fn set_reference(self, settings: Self::Settings) { + self.admux.write(|w| match settings.ref_voltage { ReferenceVoltage::Aref => w.refs().aref(), ReferenceVoltage::AVcc => w.refs().vcc(), ReferenceVoltage::Internal1_1 => w.refs().internal().refs2().clear_bit(), ReferenceVoltage::Internal2_56 => w.refs().internal().refs2().set_bit(), }); - }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PB5: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PB2: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PB4: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PB3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, -} + } + pub fn set_channel(self, channel: Self::Channel) { + self.admux.modify(|_, w| w.mux().variant(channel)); + } + + impl AdcProvider for pac::ADC { + type Hal = crate::Attiny; + const PB5: DIDR0::ADC0D = pac::adc::admux::MUX_A::ADC0; + const PB2: DIDR0::ADC1D = pac::adc::admux::MUX_A::ADC1; + const PB4: DIDR0::ADC2D = pac::adc::admux::MUX_A::ADC2; + const PB3: DIDR0::ADC3D = pac::adc::admux::MUX_A::ADC3; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + channel::Temperature = pac::adc::admux::MUX_A::TEMPSENS, + } +} #[cfg(feature = "attiny88")] avr_hal_generic::impl_adc! { - hal: crate::Attiny, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { - apply_clock(peripheral, settings); - peripheral.admux.write(|w| match settings.ref_voltage { + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + /// System reference voltage, GND (default). + #[default] + AVcc, + /// Internal 1.1V reference. + Internal1_1, + } + + pub fn set_reference(self, settings: Self::Settings) { + self.admux.write(|w| match settings.ref_voltage { ReferenceVoltage::AVcc => w.refs0().avcc(), ReferenceVoltage::Internal1_1 => w.refs0().internal(), }); - }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PC0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PC1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PC2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PC3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PC4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PC5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - port::PA0: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), - }, - channels: { - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, -} + } + pub fn set_channel(self, channel: Self::Channel) { + self.admux.modify(|_, w| w.mux().variant(channel)); + } + + impl AdcProvider for pac::ADC { + type Hal = crate::Attiny; + const PC0: DIDR0::ADC0D = pac::adc::admux::MUX_A::ADC0; + const PC1: DIDR0::ADC1D = pac::adc::admux::MUX_A::ADC1; + const PC2: DIDR0::ADC2D = pac::adc::admux::MUX_A::ADC2; + const PC3: DIDR0::ADC3D = pac::adc::admux::MUX_A::ADC3; + const PC4: DIDR0::ADC4D = pac::adc::admux::MUX_A::ADC4; + const PC5: DIDR0::ADC5D = pac::adc::admux::MUX_A::ADC5; + const PA0: DIDR0::ADC6D = pac::adc::admux::MUX_A::ADC6; + const PA1: DIDR0::ADC7D = pac::adc::admux::MUX_A::ADC7; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + channel::Temperature = pac::adc::admux::MUX_A::TEMPSENS, + } +} #[cfg(feature = "attiny167")] avr_hal_generic::impl_adc! { - hal: crate::Attiny, - peripheral: crate::pac::ADC, - settings: AdcSettings, - apply_settings: |peripheral, settings| { - apply_clock(peripheral, settings); - peripheral.amiscr.write(|w| match settings.ref_voltage { + /// Select the voltage reference for the ADC peripheral + /// + /// The internal voltage reference options may not be used if an external reference voltage is + /// being applied to the AREF pin. + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] + #[repr(u8)] + pub enum ReferenceVoltage { + /// Voltage applied to AREF pin. + Aref, + /// System reference voltage, GND (default). + #[default] + AVcc, + /// Internal 1.1V reference. + Internal1_1, + /// Internal 2.56V reference. + Internal2_56, + } + + pub fn set_reference(self, settings: Self::Settings) { + self.amiscr.write(|w| match settings.ref_voltage { ReferenceVoltage::Aref => w.arefen().set_bit(), _ => w.arefen().clear_bit(), }); - peripheral.admux.write(|w| match settings.ref_voltage { + self.admux.write(|w| match settings.ref_voltage { ReferenceVoltage::Aref => w.refs().avcc(), ReferenceVoltage::AVcc => w.refs().avcc(), ReferenceVoltage::Internal1_1 => w.refs().internal_11(), ReferenceVoltage::Internal2_56 => w.refs().internal_256(), }); - }, - channel_id: crate::pac::adc::admux::MUX_A, - set_channel: |peripheral, id| { - peripheral.admux.modify(|_, w| w.mux().variant(id)); - }, - pins: { - port::PA0: (crate::pac::adc::admux::MUX_A::ADC0, didr0::adc0d), - port::PA1: (crate::pac::adc::admux::MUX_A::ADC1, didr0::adc1d), - port::PA2: (crate::pac::adc::admux::MUX_A::ADC2, didr0::adc2d), - port::PA3: (crate::pac::adc::admux::MUX_A::ADC3, didr0::adc3d), - port::PA4: (crate::pac::adc::admux::MUX_A::ADC4, didr0::adc4d), - port::PA5: (crate::pac::adc::admux::MUX_A::ADC5, didr0::adc5d), - port::PA6: (crate::pac::adc::admux::MUX_A::ADC6, didr0::adc6d), - port::PA7: (crate::pac::adc::admux::MUX_A::ADC7, didr0::adc7d), - port::PB5: (crate::pac::adc::admux::MUX_A::ADC8, didr1::adc8d), - port::PB6: (crate::pac::adc::admux::MUX_A::ADC9, didr1::adc9d), - port::PB7: (crate::pac::adc::admux::MUX_A::ADC10, didr1::adc10d), - }, - channels: { - channel::AVcc_4: crate::pac::adc::admux::MUX_A::ADC_AVCC_4, - channel::Vbg: crate::pac::adc::admux::MUX_A::ADC_VBG, - channel::Gnd: crate::pac::adc::admux::MUX_A::ADC_GND, - channel::Temperature: crate::pac::adc::admux::MUX_A::TEMPSENS, - }, + } + pub fn set_channel(self, channel: Self::Channel) { + self.admux.modify(|_, w| w.mux().variant(channel)); + } + + impl AdcProvider for pac::ADC { + type Hal = crate::Attiny; + + const PB5: DIDR0::ADC0D = pac::adc::admux::MUX_A::ADC0; + const PB2: DIDR0::ADC1D = pac::adc::admux::MUX_A::ADC1; + const PB4: DIDR0::ADC2D = pac::adc::admux::MUX_A::ADC2; + const PB3: DIDR0::ADC3D = pac::adc::admux::MUX_A::ADC3; + } + + type ChannelId = pac::adc::admux::MUX_A; + pub enum Channels { + channel::AVcc_4 = pac::adc::admux::MUX_A::ADC_AVCC_4, + channel::Vbg = pac::adc::admux::MUX_A::ADC_VBG, + channel::Gnd = pac::adc::admux::MUX_A::ADC_GND, + channel::Temperature = pac::adc::admux::MUX_A::TEMPSENS, + } }