Skip to content
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
93cb1d5
added ability to trigger ADC flush, added call in Adc::read_channel()
NoahLutz Jan 14, 2026
9493627
initial implementation to support differential sampling
NoahLutz Jan 30, 2026
e6498b8
restored CPU voltage measurment
NoahLutz Feb 2, 2026
25be268
updated d11 implementation to support differential sampling
NoahLutz Feb 2, 2026
698c958
removed unused macro
NoahLutz Feb 2, 2026
a7eb6da
added missing DAC0 analog input channel for D5x family chips
NoahLutz Feb 2, 2026
9a4a58c
fixed typo in Muxposselect enum variant name
NoahLutz Feb 2, 2026
31901e2
added method to retrieve ADC sample resolution
NoahLutz Feb 3, 2026
ecb62f5
Merge branch 'adc-retrieve-resolution' into adc-differential-sampling
NoahLutz Feb 3, 2026
e45ba54
fixed enum variant match syntax
NoahLutz Feb 3, 2026
d005756
Merge branch 'adc-retrieve-resolution' into adc-differential-sampling
NoahLutz Feb 3, 2026
607694f
added associated type to AdcInput to handle signedness for ADC result…
NoahLutz Feb 5, 2026
4f5d207
set CTRLB.LEFTADJ when using differential sampling, added appropriate…
NoahLutz Feb 9, 2026
52eb5c1
added support for right-shifting 8-bit, 10-bit and 16-bit results whe…
NoahLutz Feb 10, 2026
a13b4a4
added support for offset and reference compensation
NoahLutz Feb 10, 2026
b55cf0b
added support for automatically handling left-adjusting and enabling …
NoahLutz Feb 11, 2026
5138ebe
added read of RESULT register in check_read_discard() to discard ADC …
NoahLutz Feb 11, 2026
f2e39ac
Merge branch 'adc-fix-read-discard' into adc-differential-sampling
NoahLutz Feb 11, 2026
9f019d3
added handling of enable/disable of offset compensation when auto rai…
NoahLutz Feb 12, 2026
1047ef0
fixed unintentional overwriting of various registers during operation
NoahLutz Feb 12, 2026
429d732
cleaned up the logic for handling left-shifted results
NoahLutz Feb 12, 2026
28d5cae
simplified get_resolution() and adjusted auto left-shit to only adjus…
NoahLutz Feb 13, 2026
72d6d2c
Merge branch 'master' into adc-differential-sampling
NoahLutz Feb 26, 2026
36fbece
removed now unecessary flush() after conversion
NoahLutz Feb 26, 2026
e61a562
added support for d11 implementation
NoahLutz Mar 3, 2026
6e3fdb0
refactored read* functions and elevated CpuSourceVoltage to type-leve…
NoahLutz Mar 5, 2026
a46c8ce
removed conditonally-compiled fields in AdcSettings
NoahLutz Mar 9, 2026
49efeb2
updated API to use pin parameters and inputs as mutable borrows and c…
NoahLutz Mar 10, 2026
c3d1d40
updated impacted board examples
NoahLutz Mar 10, 2026
89f06da
added back initialization of INPUTCTRL.GAIN for D11/D21 family chips
NoahLutz Mar 11, 2026
f58a86e
minor formatting changes
NoahLutz Mar 11, 2026
8da29df
updated doc example
NoahLutz Mar 11, 2026
d4a885b
Merge branch 'master' into adc-differential-sampling
NoahLutz Mar 12, 2026
5051226
rustfmt changes and additional documentation comments
NoahLutz Mar 12, 2026
2ba7322
fixed clippy errors
NoahLutz Mar 12, 2026
c60c17a
fixed same clippy error in d11 implementation
NoahLutz Mar 12, 2026
c0eeb9d
refactored to remove AdcInput wrapper type, separated functionality i…
NoahLutz Mar 16, 2026
3e1f35b
moved remaining traits to mod.rs, removed input.rs
NoahLutz Mar 16, 2026
feb6f77
Revert "updated impacted board examples"
NoahLutz Mar 16, 2026
1e014e7
fix d11 implementation
NoahLutz Mar 16, 2026
c81757f
fix feather_m0 ADC example
NoahLutz Mar 16, 2026
51d3b2f
added feature gates for enable_offset_compensation() and enable_auto_…
NoahLutz Mar 16, 2026
9d8b0c5
updated documentation comments
NoahLutz Mar 16, 2026
f8991fd
Merge branch 'atsamd-rs:master' into adc-differential-sampling
NoahLutz Mar 23, 2026
c4334d1
replaced cast_signed() with cast using as
NoahLutz Mar 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions boards/feather_m0/examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bsp::Pins;
use pac::{CorePeripherals, Peripherals};

use hal::{
adc::{Accumulation, Adc, Prescaler, Resolution},
adc::{Accumulation, Adc, Prescaler, Resolution, SingleEndedInput},
clock::GenericClockController,
};

Expand All @@ -44,10 +44,11 @@ fn main() -> ! {
.enable(peripherals.adc, &mut peripherals.pm, &adc_clock)
.unwrap();
let mut adc_pin = pins.a0.into_alternate();
let mut adc_input = SingleEndedInput::from_pin(&mut adc_pin);

loop {
let res = adc.read(&mut adc_pin);
let res = adc.read(&mut adc_input);
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC value: {}", read).unwrap();
cortex_m_semihosting::hprintln!("ADC value: {}", res).unwrap();
}
}
5 changes: 3 additions & 2 deletions boards/feather_m0/examples/async_adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use bsp::Pins;
use pac::{CorePeripherals, Peripherals};

use hal::{
adc::{Accumulation, Adc, Adc0, Prescaler, Resolution},
adc::{Accumulation, Adc, Adc0, Prescaler, Resolution, SingleEndedInput},
clock::GenericClockController,
};

Expand Down Expand Up @@ -49,9 +49,10 @@ async fn main(_s: embassy_executor::Spawner) -> ! {
.into_future(Irqs);

let mut adc_pin = pins.a0.into_alternate();
let mut adc_input = SingleEndedInput::from_pin(&mut adc_pin);

loop {
let res = adc.read(&mut adc_pin).await;
let res = adc.read(&mut adc_input).await;
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
}
Expand Down
5 changes: 3 additions & 2 deletions boards/feather_m4/examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bsp::Pins;
use pac::{CorePeripherals, Peripherals};

use hal::{
adc::{Accumulation, Adc, Prescaler, Resolution},
adc::{Accumulation, Adc, Prescaler, Resolution, SingleEndedInput},
clock::v2::{clock_system_at_reset, pclk::Pclk},
};

Expand Down Expand Up @@ -50,9 +50,10 @@ fn main() -> ! {
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
.unwrap();
let mut adc_pin = pins.a0.into_alternate();
let mut adc_input = SingleEndedInput::from_pin(&mut adc_pin);

loop {
let res = adc.read(&mut adc_pin);
let res = adc.read(&mut adc_input);
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC value: {}", res);
}
Expand Down
5 changes: 3 additions & 2 deletions boards/metro_m4/examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bsp::Pins;
use pac::{CorePeripherals, Peripherals};

use hal::{
adc::{Accumulation, Adc, Prescaler, Resolution},
adc::{Accumulation, Adc, Prescaler, Resolution, SingleEndedInput},
clock::v2::{clock_system_at_reset, pclk::Pclk},
};

Expand Down Expand Up @@ -49,9 +49,10 @@ fn main() -> ! {
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
.unwrap();
let mut adc_pin = pins.a0.into_alternate();
let mut adc_input = SingleEndedInput::from_pin(&mut adc_pin);

loop {
let res = adc.read(&mut adc_pin);
let res = adc.read(&mut adc_input);
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
}
Expand Down
5 changes: 3 additions & 2 deletions boards/metro_m4/examples/async_adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use bsp::Pins;
use pac::{CorePeripherals, Peripherals};

use hal::{
adc::{Accumulation, Adc, Adc0, Prescaler, Resolution},
adc::{Accumulation, Adc, Adc0, Prescaler, Resolution, SingleEndedInput},
clock::v2::{clock_system_at_reset, pclk::Pclk},
};

Expand Down Expand Up @@ -54,9 +54,10 @@ async fn main(_s: embassy_executor::Spawner) -> ! {
.into_future(Irqs);

let mut adc_pin = pins.a0.into_alternate();
let mut adc_input = SingleEndedInput::from_pin(&mut adc_pin);

loop {
let res = adc.read(&mut adc_pin).await;
let res = adc.read(&mut adc_input).await;
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
}
Expand Down
6 changes: 3 additions & 3 deletions boards/pygamer/src/pins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -934,8 +934,8 @@ impl JoystickReader {
// unnecessary? note adafruit recenters around zero.. Im not doing that
// either atm.

let y_data: u16 = adc.read(&mut self.joy_y);
let x_data: u16 = adc.read(&mut self.joy_x);
let y_data: u16 = adc.read(&mut hal::adc::SingleEndedInput::from_pin(&mut self.joy_y));
let x_data: u16 = adc.read(&mut hal::adc::SingleEndedInput::from_pin(&mut self.joy_x));

(x_data, y_data)
}
Expand Down Expand Up @@ -969,7 +969,7 @@ pub struct BatteryReader {
impl BatteryReader {
/// Returns a float for voltage of battery
pub fn read(&mut self, adc: &mut hal::adc::Adc<hal::adc::Adc0>) -> f32 {
let data: u16 = adc.read(&mut self.battery);
let data: u16 = adc.read(&mut hal::adc::SingleEndedInput::from_pin(&mut self.battery));
let result: f32 = (data as f32 / 4095.0) * 2.0 * 3.3;
result
}
Expand Down
5 changes: 3 additions & 2 deletions boards/samd11_bare/examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bsp::Pins;
use pac::{CorePeripherals, Peripherals};

use hal::{
adc::{Accumulation, Adc, Prescaler, Resolution},
adc::{Accumulation, Adc, Prescaler, Resolution, SingleEndedInput},
clock::GenericClockController,
};

Expand Down Expand Up @@ -45,9 +45,10 @@ fn main() -> ! {
.unwrap();

let mut adc_pin = pins.d1.into_alternate();
let mut adc_input = SingleEndedInput::from_pin(&mut adc_pin);

loop {
let res = adc.read(&mut adc_pin);
let res = adc.read(&mut adc_input);
#[cfg(feature = "use_semihosting")]
cortex_m_semihosting::hprintln!("ADC Result: {}", res);
}
Expand Down
57 changes: 57 additions & 0 deletions hal/src/peripherals/adc/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ pub struct AdcBuilder {
pub sample_clock_cycles: Option<u8>,
pub accumulation: Accumulation,
pub vref: Option<Reference>,
pub offset_compensation: Option<bool>,
pub reference_compensation: Option<bool>,
pub auto_left_adjust: Option<bool>,
pub auto_rail_to_rail: Option<bool>,
}

/// Version of [AdcBuilder] without any optional settings.
Expand All @@ -162,6 +166,10 @@ pub(crate) struct AdcSettings {
pub sample_clock_cycles: u8,
pub accumulation: Accumulation,
pub vref: Reference,
pub offset_compensation: bool,
pub reference_compensation: bool,
pub auto_left_adjust: bool,
pub auto_rail_to_rail: bool,
}

impl AdcBuilder {
Expand All @@ -172,6 +180,10 @@ impl AdcBuilder {
sample_clock_cycles: None,
accumulation: accumulation_method,
vref: None,
offset_compensation: None,
reference_compensation: None,
auto_left_adjust: None,
auto_rail_to_rail: None,
}
}

Expand All @@ -190,6 +202,10 @@ impl AdcBuilder {
sample_clock_cycles: self.sample_clock_cycles.unwrap(),
accumulation: self.accumulation,
vref: self.vref.unwrap(),
offset_compensation: self.offset_compensation.unwrap_or(false),
reference_compensation: self.reference_compensation.unwrap_or(false),
auto_left_adjust: self.auto_left_adjust.unwrap_or(false),
auto_rail_to_rail: self.auto_rail_to_rail.unwrap_or(false),
})
}

Expand Down Expand Up @@ -244,6 +260,47 @@ impl AdcBuilder {
Ok(adc_clk_freq / clocks_per_sample)
}

/// Configure the ADC offset compensation
///
/// ## Important
/// * (D5x) Enabling offset compesation forces the clock cycles per sample
/// to be 4 GCLK cycles, any change to the cycles per sample via
/// [`Self::with_clock_cycles_per_sample()`] will be ignored.
/// * (D11/D21) Not supported.
pub fn enable_offset_compensation(mut self, enable: bool) -> Self {
Comment thread
rnd-ash marked this conversation as resolved.
self.offset_compensation = Some(enable);
self
}

/// Configure the ADC reference compensation
pub fn enable_reference_compensation(mut self, enable: bool) -> Self {
self.reference_compensation = Some(enable);
self
}

/// Enables automatic left-adjustment when measuring differential inputs.
/// This allows use of the ADC summation or averaging hardware with
/// negative result values. Results are automatically right-shifted back
/// appropriately.
pub fn enable_auto_left_adjust(mut self, enable: bool) -> Self {
self.auto_left_adjust = Some(enable);
self
}

/// Automatically enables rail-to-rail operation when measuring a
/// differential input. This relaxes common-mode input requirements on
/// differential inputs and allows measurments closer to supply rails.
///
/// ## Important
/// * (D5x) Enabling auto rail-to-rail incurs a slight runtime performance
/// hit as the CTRLA.R2R bit is enable-protected, meaning the ADC must be
/// shut down and re-enabled to enable/disable rail-to-rail mode.
/// * (D11/D21) Not supported.
pub fn enable_auto_rail_to_rail(mut self, enable: bool) -> Self {
Comment thread
rnd-ash marked this conversation as resolved.
self.auto_rail_to_rail = Some(enable);
self
}

/// Turn the builder into an ADC
#[hal_cfg("adc-d5x")]
#[inline]
Expand Down
100 changes: 100 additions & 0 deletions hal/src/peripherals/adc/d11/channel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use core::marker::PhantomData;
use atsamd_hal_macros::hal_cfg;
use crate::{
adc::*,
pac::adc::inputctrl::{Muxposselect, Muxnegselect},
typelevel::Sealed,
};

macro_rules! channel {
(
$(
$CH:ident: ($($PMUX:path)?, $($NMUX:path)?) $(+ $MARKER:ident)*
),+
$(,)?
) => {
crate::paste::paste!{
$(
pub struct $CH<I: AdcInstance> {
adc: PhantomData<I>,
}

impl<I: AdcInstance> Sealed for $CH<I> {}

$(
impl<I: AdcInstance> PosChannel<I> for $CH<I> {
const MUXVAL: Muxposselect = $PMUX;
}
)?
$(
impl<I: AdcInstance> NegChannel<I> for $CH<I> {
const MUXVAL: Muxnegselect = $NMUX;
}
)?
$(
impl<I: AdcInstance> $MARKER<I> for $CH<I> {}
)*

impl<I: AdcInstance> $CH<I> {
pub fn get_channel() -> Self {
Self {
adc: PhantomData
}
}
}
)+
}
};
}

#[hal_cfg("adc-d21")]
channel! {
AIN0: (Muxposselect::Pin0, Muxnegselect::Pin0),
AIN1: (Muxposselect::Pin1, Muxnegselect::Pin1),
AIN2: (Muxposselect::Pin2, Muxnegselect::Pin2),
AIN3: (Muxposselect::Pin3, Muxnegselect::Pin3),
AIN4: (Muxposselect::Pin4, Muxnegselect::Pin4),
AIN5: (Muxposselect::Pin5, Muxnegselect::Pin5),
AIN6: (Muxposselect::Pin6, Muxnegselect::Pin6),
AIN7: (Muxposselect::Pin7, Muxnegselect::Pin7),
AIN8: (Muxposselect::Pin8, ),
AIN9: (Muxposselect::Pin9, ),
AIN10: (Muxposselect::Pin10, ),
AIN11: (Muxposselect::Pin11, ),
AIN12: (Muxposselect::Pin12, ),
AIN13: (Muxposselect::Pin13, ),
AIN14: (Muxposselect::Pin14, ),
AIN15: (Muxposselect::Pin15, ),
AIN16: (Muxposselect::Pin15, ),
AIN17: (Muxposselect::Pin15, ),
AIN18: (Muxposselect::Pin15, ),
AIN19: (Muxposselect::Pin15, ),
TEMP: (Muxposselect::Temp, ),
SCALEDCOREVCC: (Muxposselect::Scaledcorevcc, ) + CpuVoltageSource,
SCALEDIOVCC: (Muxposselect::Scalediovcc, ) + CpuVoltageSource,
BANDGAP: (Muxposselect::Bandgap, ) + CpuVoltageSource,
DAC: (Muxposselect::Dac, ),
GND: (, Muxnegselect::Gnd),
IOGND: (, Muxnegselect::Iognd),
}

#[hal_cfg("adc-d11")]
channel! {
AIN0: (Muxposselect::Pin0, Muxnegselect::Pin0),
AIN1: (Muxposselect::Pin1, Muxnegselect::Pin1),
AIN2: (Muxposselect::Pin2, Muxnegselect::Pin2),
AIN3: (Muxposselect::Pin3, Muxnegselect::Pin3),
AIN4: (Muxposselect::Pin4, Muxnegselect::Pin4),
AIN5: (Muxposselect::Pin5, Muxnegselect::Pin5),
AIN6: (Muxposselect::Pin6, Muxnegselect::Pin6),
AIN7: (Muxposselect::Pin7, Muxnegselect::Pin7),
AIN8: (Muxposselect::Pin8, ),
AIN9: (Muxposselect::Pin9, ),
TEMP: (Muxposselect::Temp, ),
SCALEDCOREVCC: (Muxposselect::Scaledcorevcc, ) + CpuVoltageSource,
SCALEDIOVCC: (Muxposselect::Scalediovcc, ) + CpuVoltageSource,
BANDGAP: (Muxposselect::Bandgap, ) + CpuVoltageSource,
DAC: (Muxposselect::Dac, ),
GND: (, Muxnegselect::Gnd),
IOGND: (, Muxnegselect::Iognd),
}
Loading