Skip to content

Commit d3473a4

Browse files
rnd-ashjbeaurivage
authored andcommitted
feat: ADCv2
#814 This work was done over about 6 months by: Ashcon Mohseninia <[email protected]> and Justin Beaurivage <[email protected]> with input from the atsamd-rs community. Begin constructing an async ADC concept for D5X Draft up new ADC API Test implementation of async read for ADC Resolve rest of the adc read future Move to type based ADC implementation Broken read_blocking implementation Begin implementing async reading ADC Automatically convert pins to correct mode in with_pins Remove explicit reference to a chip in favor of PAC Split async and sync ADC into different implementations Clean up ADC Add inlines everywhere Add wait_flags method and do some extra cleanup Add blocking and async buffered read methods Derive debug for Adc Error Fix ADC read_buffer not ever starting Fix ADC reading blocking buffer always returning BufferOverrun Implement more ADCSettings Add in temperature calibration parameters to calibration Add in CPU Temperature reading Add CPU internal sensors reading, and setting VREF for adc Restrict internal CPU sensors to primary CPU ADC Remove breaking comments in Cargo.toml Allow blocking methods on async-enabled ADCs Derive defmt::Format for error type Remove duplicate methods ADC: Add support for samd21 line Remove curiosity nano reference Make names more consistent with the rest of the crate samd21 - Fix ADC results being multiplied by 2x Error if ADC is configured for summation/averaging but user has selected an incorrect bit width Improve ADC comments Resolve clippy warnings Add ADC Pins for D11 Improve imports and hal_cfg usage for ADC Leave workspace Cargo.toml unchanged Make good use of the typelevel guarantees provided by clock::v2 Remove the need for the Channel machinery D5x - Document TH and TL parameters better Improve D11/D21 ADC clocking Cleanup config type aliases Add doc comment for ADC::new (thumbv6) Simplify some snippets, add missing doc comment, and add missing sync calls Minimal working ADC example for feather_m0 Fix some bugs in conversion methods Slightly improve docs Revert workspace Cargo.toml Add D11 ADC calibration Update T1 BSPs Fix misaligned flash read Make internal calibration API safer Fix math error in ADC bias calibration Improve ADC reading results by powering down and up ADC Fix fmt and clippy warns Start fixing pygamer examples Fix overrun errors on thumbv6 targets Fix dividers in examples Fix Samd21g build First round of ADC Doc fixes Construct ADC from ADC Builder D5x - Correct all calibration values D11 - Correct all calibrations and add temp cals Cleanup and finalize ADC Refactor the check_and_clear_flags method Improve, standardize examples and make them more robust Mention that async ADC is supported in repo README Doc and formatting fixes Fix warning when building without async feature Supply vref in SAMD11 adc example Fix Calibration parts_to_f32 Stabilize ADC reading after a setting change Document TSEN enable correct calibration floating point values rework calibration decimal numbers Document tsen enabling procedure for d11 too ADC docs Remove disused parts_to_f32() Update docstrings for d5x temperature methods SAMD21 - Expose bandgap voltage and rename vbat to IO D2x - Optimize ADC temp cals D21 - Remove raw field on read_cpu_temperature Make ADC examples use single reads rather than buffer reads Fix output averages being wrong Calibration bug fixes Fine tune sensor reading settings Remove useless read from ADC when discarding value D21 - Document how to NOT nuke the VREF register when enabling TSEN Make reading CPU temperature infaillible Make cpu sensor/temp reading actually async for the async implementation Tidy comments in examples clippy lints, formatting
1 parent b6f1100 commit d3473a4

File tree

27 files changed

+2158
-705
lines changed

27 files changed

+2158
-705
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ use the async APIs.
109109
* DMAC
110110
* EIC (GPIO interrupts)
111111
* Timers
112+
* ADC
112113

113114
### Examples
114115

boards/feather_m0/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ required-features = ["adalogger", "usb", "sdmmc"]
8787
[[example]]
8888
name = "adc"
8989

90+
[[example]]
91+
name = "async_adc"
92+
required-features = ["async"]
93+
9094
[[example]]
9195
name = "async_dmac"
9296
required-features = ["dma", "async"]

boards/feather_m0/examples/adc.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,53 @@
11
#![no_std]
22
#![no_main]
33

4+
use atsamd_hal::adc::AdcBuilder;
5+
use feather_m0 as bsp;
6+
7+
use bsp::hal;
8+
use bsp::pac;
9+
410
#[cfg(not(feature = "use_semihosting"))]
511
use panic_halt as _;
612
#[cfg(feature = "use_semihosting")]
713
use panic_semihosting as _;
814

9-
use cortex_m_semihosting::hprintln;
10-
11-
use bsp::hal;
12-
use bsp::pac;
13-
use feather_m0 as bsp;
14-
1515
use bsp::entry;
16-
use hal::adc::Adc;
17-
use hal::clock::GenericClockController;
18-
use hal::prelude::*;
16+
use bsp::Pins;
1917
use pac::{CorePeripherals, Peripherals};
2018

19+
use hal::{
20+
adc::{Accumulation, Adc, Prescaler, Resolution},
21+
clock::GenericClockController,
22+
};
23+
2124
#[entry]
2225
fn main() -> ! {
2326
let mut peripherals = Peripherals::take().unwrap();
24-
let core = CorePeripherals::take().unwrap();
27+
let _core = CorePeripherals::take().unwrap();
28+
29+
let pins = Pins::new(peripherals.port);
30+
2531
let mut clocks = GenericClockController::with_external_32kosc(
2632
peripherals.gclk,
2733
&mut peripherals.pm,
2834
&mut peripherals.sysctrl,
2935
&mut peripherals.nvmctrl,
3036
);
31-
let pins = bsp::Pins::new(peripherals.port);
32-
let mut delay = hal::delay::Delay::new(core.SYST, &mut clocks);
33-
let mut adc = Adc::adc(peripherals.adc, &mut peripherals.pm, &mut clocks);
34-
let mut a0: bsp::A0 = pins.a0.into();
37+
let gclk0 = clocks.gclk0();
38+
let adc_clock = clocks.adc(&gclk0).unwrap();
39+
40+
let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
41+
.with_clock_cycles_per_sample(5)
42+
.with_clock_divider(Prescaler::Div128)
43+
.with_vref(atsamd_hal::adc::Reference::Intvcc0)
44+
.enable(peripherals.adc, &mut peripherals.pm, &adc_clock)
45+
.unwrap();
46+
let mut adc_pin = pins.a0.into_alternate();
3547

3648
loop {
37-
let data: u16 = adc.read(&mut a0).unwrap();
38-
hprintln!("{}", data).ok();
39-
delay.delay_ms(1000u16);
49+
let res = adc.read(&mut adc_pin);
50+
#[cfg(feature = "use_semihosting")]
51+
cortex_m_semihosting::hprintln!("ADC value: {}", read).unwrap();
4052
}
4153
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use atsamd_hal::adc::AdcBuilder;
5+
use feather_m0 as bsp;
6+
7+
use bsp::hal;
8+
use bsp::pac;
9+
10+
#[cfg(not(feature = "use_semihosting"))]
11+
use panic_halt as _;
12+
#[cfg(feature = "use_semihosting")]
13+
use panic_semihosting as _;
14+
15+
use bsp::Pins;
16+
use pac::{CorePeripherals, Peripherals};
17+
18+
use hal::{
19+
adc::{Accumulation, Adc, Adc0, Prescaler, Resolution},
20+
clock::GenericClockController,
21+
};
22+
23+
atsamd_hal::bind_interrupts!(struct Irqs {
24+
ADC => atsamd_hal::adc::InterruptHandler<Adc0>;
25+
});
26+
27+
#[embassy_executor::main]
28+
async fn main(_s: embassy_executor::Spawner) -> ! {
29+
let mut peripherals = Peripherals::take().unwrap();
30+
let _core = CorePeripherals::take().unwrap();
31+
32+
let pins = Pins::new(peripherals.port);
33+
34+
let mut clocks = GenericClockController::with_external_32kosc(
35+
peripherals.gclk,
36+
&mut peripherals.pm,
37+
&mut peripherals.sysctrl,
38+
&mut peripherals.nvmctrl,
39+
);
40+
let gclk0 = clocks.gclk0();
41+
let adc_clock = clocks.adc(&gclk0).unwrap();
42+
43+
let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
44+
.with_clock_cycles_per_sample(5)
45+
.with_clock_divider(Prescaler::Div128)
46+
.with_vref(atsamd_hal::adc::Reference::Arefa)
47+
.enable(peripherals.adc, &mut peripherals.pm, &adc_clock)
48+
.unwrap()
49+
.into_future(Irqs);
50+
51+
let mut adc_pin = pins.a0.into_alternate();
52+
53+
loop {
54+
let res = adc.read(&mut adc_pin).await;
55+
#[cfg(feature = "use_semihosting")]
56+
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
57+
}
58+
}

boards/feather_m4/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ version = "0.3.1"
3535
[dev-dependencies]
3636
heapless = "0.7"
3737
panic-halt = "0.2"
38+
cortex-m-semihosting = "0.5.0"
3839
panic-semihosting = "0.5"
3940
rtic = {version = "2.1.1", features = ["thumbv7-backend"]}
4041
smart-leds = "0.3"
@@ -53,6 +54,9 @@ usb = ["atsamd-hal/usb", "usb-device"]
5354
async = ["atsamd-hal/async"]
5455
use_semihosting = []
5556

57+
[[example]]
58+
name = "adc"
59+
5660
[[example]]
5761
name = "blinky_basic"
5862

boards/feather_m4/examples/adc.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use atsamd_hal::adc::AdcBuilder;
5+
use feather_m4 as bsp;
6+
7+
use bsp::hal;
8+
use bsp::pac;
9+
10+
#[cfg(not(feature = "use_semihosting"))]
11+
use panic_halt as _;
12+
#[cfg(feature = "use_semihosting")]
13+
use panic_semihosting as _;
14+
15+
use bsp::entry;
16+
use bsp::Pins;
17+
use pac::{CorePeripherals, Peripherals};
18+
19+
use hal::{
20+
adc::{Accumulation, Adc, Prescaler, Resolution},
21+
clock::v2::{clock_system_at_reset, pclk::Pclk},
22+
};
23+
24+
#[entry]
25+
fn main() -> ! {
26+
let mut peripherals = Peripherals::take().unwrap();
27+
let _core = CorePeripherals::take().unwrap();
28+
29+
let pins = Pins::new(peripherals.port);
30+
31+
let (mut buses, clocks, tokens) = clock_system_at_reset(
32+
peripherals.oscctrl,
33+
peripherals.osc32kctrl,
34+
peripherals.gclk,
35+
peripherals.mclk,
36+
&mut peripherals.nvmctrl,
37+
);
38+
39+
// Enable the ADC0 ABP clock...
40+
let apb_adc0 = buses.apb.enable(tokens.apbs.adc0);
41+
// ...and enable the ADC0 PCLK. Both of these are required for the
42+
// ADC to run.
43+
let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0);
44+
45+
let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
46+
.with_clock_cycles_per_sample(5)
47+
// Overruns if clock divider < 32 in debug mode
48+
.with_clock_divider(Prescaler::Div32)
49+
.with_vref(atsamd_hal::adc::Reference::Arefa)
50+
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
51+
.unwrap();
52+
let mut adc_pin = pins.a0.into_alternate();
53+
54+
loop {
55+
let res = adc.read(&mut adc_pin);
56+
#[cfg(feature = "use_semihosting")]
57+
cortex_m_semihosting::hprintln!("ADC value: {}", res);
58+
}
59+
}

boards/metro_m4/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ use_semihosting = []
6767
[[example]]
6868
name = "adc"
6969

70+
[[example]]
71+
name = "async_adc"
72+
required-features = ["async"]
73+
7074
[[example]]
7175
name = "async_dmac"
7276
required-features = ["dma", "async"]

boards/metro_m4/examples/adc.rs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![no_std]
22
#![no_main]
33

4+
use atsamd_hal::adc::AdcBuilder;
45
use metro_m4 as bsp;
56

67
use bsp::hal;
@@ -11,35 +12,47 @@ use panic_halt as _;
1112
#[cfg(feature = "use_semihosting")]
1213
use panic_semihosting as _;
1314

14-
use cortex_m_semihosting::hprintln;
15-
1615
use bsp::entry;
17-
use hal::adc::Adc;
18-
use hal::clock::GenericClockController;
19-
use hal::gpio::B;
20-
use hal::prelude::*;
21-
use pac::gclk::pchctrl::Genselect::Gclk11;
16+
use bsp::Pins;
2217
use pac::{CorePeripherals, Peripherals};
2318

19+
use hal::{
20+
adc::{Accumulation, Adc, Prescaler, Resolution},
21+
clock::v2::{clock_system_at_reset, pclk::Pclk},
22+
};
23+
2424
#[entry]
2525
fn main() -> ! {
2626
let mut peripherals = Peripherals::take().unwrap();
27-
let core = CorePeripherals::take().unwrap();
28-
let mut clocks = GenericClockController::with_external_32kosc(
27+
let _core = CorePeripherals::take().unwrap();
28+
29+
let pins = Pins::new(peripherals.port);
30+
31+
let (mut buses, clocks, tokens) = clock_system_at_reset(
32+
peripherals.oscctrl,
33+
peripherals.osc32kctrl,
2934
peripherals.gclk,
30-
&mut peripherals.mclk,
31-
&mut peripherals.osc32kctrl,
32-
&mut peripherals.oscctrl,
35+
peripherals.mclk,
3336
&mut peripherals.nvmctrl,
3437
);
35-
let pins = bsp::Pins::new(peripherals.port);
36-
let mut delay = hal::delay::Delay::new(core.SYST, &mut clocks);
37-
let mut adc0 = Adc::adc0(peripherals.adc0, &mut peripherals.mclk, &mut clocks, Gclk11);
38-
let mut a0 = pins.a0.into_alternate::<B>();
38+
39+
// Enable the ADC0 ABP clock...
40+
let apb_adc0 = buses.apb.enable(tokens.apbs.adc0);
41+
// ...and enable the ADC0 PCLK. Both of these are required for the
42+
// ADC to run.
43+
let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0);
44+
45+
let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
46+
.with_clock_cycles_per_sample(5)
47+
.with_clock_divider(Prescaler::Div32)
48+
.with_vref(atsamd_hal::adc::Reference::Arefa)
49+
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
50+
.unwrap();
51+
let mut adc_pin = pins.a0.into_alternate();
3952

4053
loop {
41-
let data: u16 = adc0.read(&mut a0).unwrap();
42-
hprintln!("{}", data).ok();
43-
delay.delay_ms(1000u16);
54+
let res = adc.read(&mut adc_pin);
55+
#[cfg(feature = "use_semihosting")]
56+
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
4457
}
4558
}

boards/metro_m4/examples/async_adc.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use atsamd_hal::adc::AdcBuilder;
5+
use metro_m4 as bsp;
6+
7+
use bsp::hal;
8+
use bsp::pac;
9+
10+
#[cfg(not(feature = "use_semihosting"))]
11+
use panic_halt as _;
12+
#[cfg(feature = "use_semihosting")]
13+
use panic_semihosting as _;
14+
15+
use bsp::Pins;
16+
use pac::{CorePeripherals, Peripherals};
17+
18+
use hal::{
19+
adc::{Accumulation, Adc, Adc0, Prescaler, Resolution},
20+
clock::v2::{clock_system_at_reset, pclk::Pclk},
21+
};
22+
23+
atsamd_hal::bind_multiple_interrupts!(struct Irqs {
24+
ADC0: [ADC0_RESRDY, ADC0_OTHER] => atsamd_hal::adc::InterruptHandler<Adc0>;
25+
});
26+
27+
#[embassy_executor::main]
28+
async fn main(_s: embassy_executor::Spawner) -> ! {
29+
let mut peripherals = Peripherals::take().unwrap();
30+
let _core = CorePeripherals::take().unwrap();
31+
32+
let pins = Pins::new(peripherals.port);
33+
34+
let (mut buses, clocks, tokens) = clock_system_at_reset(
35+
peripherals.oscctrl,
36+
peripherals.osc32kctrl,
37+
peripherals.gclk,
38+
peripherals.mclk,
39+
&mut peripherals.nvmctrl,
40+
);
41+
42+
// Enable the ADC0 ABP clock...
43+
let apb_adc0 = buses.apb.enable(tokens.apbs.adc0);
44+
// ...and enable the ADC0 PCLK. Both of these are required for the
45+
// ADC to run.
46+
let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0);
47+
48+
let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12))
49+
.with_clock_cycles_per_sample(5)
50+
.with_clock_divider(Prescaler::Div32)
51+
.with_vref(atsamd_hal::adc::Reference::Arefa)
52+
.enable(peripherals.adc0, apb_adc0, &pclk_adc0)
53+
.unwrap()
54+
.into_future(Irqs);
55+
56+
let mut adc_pin = pins.a0.into_alternate();
57+
58+
loop {
59+
let res = adc.read(&mut adc_pin).await;
60+
#[cfg(feature = "use_semihosting")]
61+
cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap();
62+
}
63+
}

0 commit comments

Comments
 (0)