Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New ADC V2 with Async support #814

Open
wants to merge 78 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
e0db457
Allow delay to be constructed with source (Clock V2)
rnd-ash Dec 10, 2024
29168c7
Fix compile tests and restrict source to Gclk0
rnd-ash Dec 10, 2024
d8056c1
Fix compile for sam51
rnd-ash Jan 6, 2025
ca1e486
Cargo fmt
rnd-ash Jan 6, 2025
d7ce590
Merge branch 'atsamd-rs:master' into master
rnd-ash Jan 7, 2025
5dd776b
Add ADC sample settings
rnd-ash Jan 10, 2025
8edb4db
Merge branch 'atsamd-rs:master' into adc_v2
rnd-ash Jan 14, 2025
53818c7
Begin constructing an async ADC concept for D5X
rnd-ash Jan 15, 2025
7e06a82
Draft up new ADC API
rnd-ash Jan 20, 2025
f2b6cc8
Test implementation of async read for ADC
rnd-ash Jan 20, 2025
98261d7
Resolve rest of the adc read future
rnd-ash Jan 20, 2025
afc5430
Move to type based ADC implementation
rnd-ash Jan 21, 2025
7c76cb6
Broken read_blocking implementation
rnd-ash Jan 21, 2025
282c02e
Begin implementing async reading ADC
rnd-ash Jan 22, 2025
18cbbfe
Automatically convert pins to correct mode in with_pins
jbeaurivage Jan 21, 2025
ba755bc
Remove explicit reference to a chip in favor of PAC
jbeaurivage Jan 21, 2025
9a0219d
Split async and sync ADC into different implementations
rnd-ash Jan 22, 2025
f00feed
Merge pull request #2 from jbeaurivage/adc_v2-fixes
rnd-ash Jan 22, 2025
fa51270
Clean up ADC
rnd-ash Jan 22, 2025
ebeb28a
Add inlines everywhere
jbeaurivage Jan 22, 2025
f37b36f
Add wait_flags method and do some extra cleanup
jbeaurivage Jan 22, 2025
bf25449
Add blocking and async buffered read methods
jbeaurivage Jan 22, 2025
a9b46f0
Merge pull request #3 from jbeaurivage/adc_v2-fixes
rnd-ash Jan 22, 2025
6bbbfda
Derive debug for Adc Error
rnd-ash Jan 22, 2025
53aafe0
Fix ADC read_buffer not ever starting
rnd-ash Jan 22, 2025
88f74f5
Fix ADC reading blocking buffer always returning BufferOverrun
rnd-ash Jan 22, 2025
53955a6
Implement more ADCSettings
rnd-ash Jan 22, 2025
9262d33
Add in temperature calibration parameters to calibration
rnd-ash Jan 22, 2025
627d9a9
Add in CPU Temperature reading
rnd-ash Jan 23, 2025
d0e5602
Add CPU internal sensors reading, and setting VREF for adc
rnd-ash Jan 23, 2025
61e8fc6
Restrict internal CPU sensors to primary CPU ADC
rnd-ash Jan 23, 2025
6fa6e30
Remove breaking comments in Cargo.toml
rnd-ash Jan 23, 2025
4cf54ef
Allow blocking methods on async-enabled ADCs
jbeaurivage Jan 22, 2025
8914319
Derive defmt::Format for error type
jbeaurivage Jan 22, 2025
a25b15c
Remove duplicate methods
jbeaurivage Jan 23, 2025
eb8b043
Merge pull request #4 from jbeaurivage/adc_v2-fixes
rnd-ash Jan 23, 2025
6cbc27e
ADC: Add support for samd21 line
rnd-ash Jan 23, 2025
7f7002f
Remove curiosity nano reference
rnd-ash Jan 24, 2025
b236399
Make names more consistent with the rest of the crate
rnd-ash Jan 27, 2025
a1e8fb9
samd21 - Fix ADC results being multiplied by 2x
rnd-ash Jan 27, 2025
8e0bda2
Error if ADC is configured for summation/averaging but user has selec…
rnd-ash Jan 27, 2025
17b2aa6
Improve ADC comments
rnd-ash Jan 31, 2025
92fc81d
Resolve clippy warnings
rnd-ash Jan 31, 2025
183d873
Add ADC Pins for D11
rnd-ash Jan 31, 2025
582b554
Improve imports and hal_cfg usage for ADC
rnd-ash Jan 31, 2025
c01f9ed
Leave workspace Cargo.toml unchanged
jbeaurivage Feb 4, 2025
34db6e0
Make good use of the typelevel guarantees provided by clock::v2
jbeaurivage Feb 4, 2025
d7922c1
Remove the need for the Channel machinery
jbeaurivage Feb 4, 2025
5d5f486
Merge pull request #5 from jbeaurivage/adc_v2
rnd-ash Feb 4, 2025
d83129c
Merge branch 'master' into adc_v2
rnd-ash Feb 4, 2025
932b9f6
D5x - Document TH and TL parameters better
rnd-ash Feb 4, 2025
f6571bc
Improve D11/D21 ADC clocking
jbeaurivage Feb 5, 2025
a85b6af
Cleanup config type aliases
jbeaurivage Feb 5, 2025
d0384ab
Add doc comment for ADC::new (thumbv6)
jbeaurivage Feb 5, 2025
2e398ea
Simplify some snippets, add missing doc comment, and add missing sync…
jbeaurivage Feb 5, 2025
ddccfe0
Minimal working ADC example for feather_m0
jbeaurivage Feb 5, 2025
e45049f
Fix some bugs in conversion methods
jbeaurivage Feb 5, 2025
d28c3f0
Slightly improve docs
jbeaurivage Feb 5, 2025
1667fbf
Add D11 ADC calibration
rnd-ash Feb 10, 2025
4303f46
Revert workspace Cargo.toml
jbeaurivage Feb 10, 2025
284110c
Merge branch 'adc_v2' into adc_v2
rnd-ash Feb 11, 2025
f1c4808
Merge pull request #6 from jbeaurivage/adc_v2
rnd-ash Feb 11, 2025
9492091
Update T1 BSPs
jbeaurivage Feb 11, 2025
42d831d
Merge pull request #7 from jbeaurivage/adc_v2
rnd-ash Feb 11, 2025
e42ee42
Fix misaligned flash read
ianrrees Feb 16, 2025
39b984a
Make internal calibration API safer
ianrrees Feb 16, 2025
872e5bf
Fix math error in ADC bias calibration
ianrrees Feb 16, 2025
1adbef7
Merge pull request #8 from jbeaurivage/adc-testing
rnd-ash Feb 20, 2025
cfcedf1
Improve ADC reading results by powering down and up ADC
rnd-ash Mar 4, 2025
e87e875
Merge remote-tracking branch 'refs/remotes/origin/adc_v2' into adc_v2
rnd-ash Mar 4, 2025
5c5cfff
Fix fmt and clippy warns
jbeaurivage Feb 11, 2025
a6d87c6
Start fixing pygamer examples
jbeaurivage Feb 20, 2025
371d802
Fix overrun errors on thumbv6 targets
jbeaurivage Mar 4, 2025
6feda91
Fix dividers in examples
jbeaurivage Mar 4, 2025
9496416
Merge pull request #9 from jbeaurivage/adc_v2_fix_overrun
rnd-ash Mar 5, 2025
1ef46e0
Remove pygamer neopixel examples
rnd-ash Mar 15, 2025
d4117e7
Fix Samd21g build
rnd-ash Mar 15, 2025
cc03084
Merge branch 'master' into adc_v2
rnd-ash Mar 15, 2025
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
Prev Previous commit
Next Next commit
Split async and sync ADC into different implementations
rnd-ash committed Jan 22, 2025
commit 9a0219d97511a2a313e379e34dde604de3e5e150
194 changes: 194 additions & 0 deletions boards/same51_curiosity_nano/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#![no_std]
#![deny(missing_docs)]

//! Board support crate for Adafruit's Feather M4 Express,
//! an ATSAMD51-based board in Feather form factor.

#[cfg(feature = "rt")]
pub use cortex_m_rt::entry;

pub use atsamd_hal as hal;
pub use hal::ehal;
pub use hal::pac;

use hal::clock::GenericClockController;
use hal::sercom::{
i2c, spi,
uart::{self, BaudMode, Oversampling},
IoSet1, UndocIoSet1,
};
use hal::time::Hertz;

#[cfg(feature = "usb")]
use hal::usb::usb_device::bus::UsbBusAllocator;
#[cfg(feature = "usb")]
pub use hal::usb::UsbBus;

hal::bsp_peripherals!(
Sercom1 { SpiSercom }
Sercom2 { I2cSercom }
Sercom5 { UartSercom }
);

hal::bsp_pins!(
PA02 {
/// Analog pin 0. Can act as a true analog output
/// as it has a DAC (which is not currently supported
/// by this hal) as well as input.
name: a0,
}
PA05 {
/// Analog Pin 1
name: a1,
}
PB08 {
/// Analog Pin 2
name: a2,
}
PB09 {
/// Analog Pin 3
name: a3,
}
PA04 {
/// Analog Pin 4
name: a4,
}
PA06 {
/// Analog Pin 5
name: a5,
}
PB01 {
/// Analog Vdiv (1/2 resistor divider for monitoring the battery)
name: battery,
}

PB17 {
/// Pin 0, UART rx
name: d0,
aliases: {
AlternateC: UartRx
}
}
PB16 {
/// Pin 1, UART tx
name: d1,
aliases: {
AlternateC: UartTx
}
}
PA14 {
/// Pin 4, PWM capable
name: d4,
}
PA16 {
/// Pin 5, PWM capable
name: d5,
}
PA18 {
/// Pin 6, PWM capable
name: d6,
}
PB03 {
/// Neopixel Pin
name: neopixel,
}
PA19 {
/// Pin 9, PWM capable. Also analog input (A7)
name: d9,
}
PA20 {
/// Pin 10, PWM capable
name: d10,
}
PA21 {
/// Pin 11, PWM capable
name: d11,
}
PA22 {
/// Pin 12, PWM capable
name: d12,
}
PA23 {
/// Pin 13, which is also attached to the red LED. PWM capable.
name: d13,
aliases: {
PushPullOutput: RedLed,
AlternateE: RedLedPwm
}
}
PA12 {
/// The I2C data line
name: sda,
aliases: {
AlternateC: Sda
}
}
PA13 {
/// The I2C clock line
name: scl,
aliases: {
AlternateC: Scl
}
}
PA17 {
/// The SPI SCK
name: sck,
aliases: {
AlternateC: Sclk
}
}
PB23 {
/// The SPI MOSI
name: mosi,
aliases: {
AlternateC: Mosi
}
}
PB22 {
/// The SPI MISO
name: miso,
aliases: {
AlternateC: Miso
}
}
PA24 {
/// The USB D- pad
name: usb_dm,
aliases: {
AlternateH: UsbDm
}
}
PA25 {
/// The USB D+ pad
name: usb_dp,
aliases: {
AlternateH: UsbDp
}
}
);

/// UART pads for the labelled RX & TX pins
pub type UartPads = uart::Pads<UartSercom, IoSet1, UartRx, UartTx>;

/// UART device for the labelled RX & TX pins
pub type Uart = uart::Uart<uart::Config<UartPads>, uart::Duplex>;

/// Convenience for setting up the labelled RX, TX pins to
/// operate as a UART device running at the specified baud.
pub fn uart(
clocks: &mut GenericClockController,
baud: impl Into<Hertz>,
sercom: UartSercom,
mclk: &mut pac::Mclk,
rx: impl Into<UartRx>,
tx: impl Into<UartTx>,
) -> Uart {
let gclk0 = clocks.gclk0();

let clock = &clocks.sercom5_core(&gclk0).unwrap();
let baud = baud.into();
let pads = uart::Pads::default().rx(rx.into()).tx(tx.into());
uart::Config::new(mclk, sercom, pads, clock.freq())
.baud(baud, BaudMode::Fractional(Oversampling::Bits16))
.enable()
}
90 changes: 54 additions & 36 deletions hal/src/peripherals/adc/mod.rs
Original file line number Diff line number Diff line change
@@ -183,7 +183,7 @@ impl<I: AdcInstance, Id: ChId> Channel<I, Id, NoneT> {

// These methods are only implemented for a Channel that holds a configured pin
impl<I: AdcInstance, Id: ChId, P: AdcPin<I, Id>> Channel<I, Id, P> {
pub fn read_blocking(&self, adc: &mut Adc<I>) -> u16 {
pub fn read_blocking(&self, adc: &mut Adc<I, NoneT>) -> u16 {
//f(Id::ID as u16);
adc.read_blocking(Id::ID)
}
@@ -194,7 +194,10 @@ impl<I: AdcInstance, Id: ChId, P: AdcPin<I, Id>> Channel<I, Id, P> {
}

#[cfg(feature = "async")]
pub async fn read(&self, adc: &mut Adc<I>) -> u16 {
pub async fn read<F>(&self, adc: &mut Adc<I, F>) -> u16
where
F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
{
adc.read(Id::ID).await
}

@@ -205,14 +208,12 @@ impl<I: AdcInstance, Id: ChId, P: AdcPin<I, Id>> Channel<I, Id, P> {
}

/// ADC Instance
pub struct Adc<I: AdcInstance> {
pub struct Adc<I: AdcInstance, F = NoneT> {
adc: I::Instance,
_irqs: PhantomData<F>,
}

pub struct AsyncAdc<A: AdcInstance, I> {
inner: A,
_irqs: PhantomData<I>,
}
pub struct AdcFuture;

impl<I: AdcInstance> Adc<I> {
/// Construct a new ADC instance
@@ -241,7 +242,10 @@ impl<I: AdcInstance> Adc<I> {
adc.ctrla().modify(|_, w| w.swrst().set_bit());
while adc.syncbusy().read().swrst().bit_is_set() {}
// Calibrate and setup the Vref (This is done once)
let mut new_adc = Self { adc };
let mut new_adc = Self {
adc,
_irqs: PhantomData,
};

I::calibrate(&new_adc.adc);
new_adc.configure(settings);
@@ -289,6 +293,29 @@ impl<I: AdcInstance> Adc<I> {
while self.adc.syncbusy().read().refctrl().bit_is_set() {}
}

pub fn read_blocking(&mut self, ch: u8) -> u16 {
self.sync();
self.mux(ch);
self.sync();
self.adc.ctrla().modify(|_, w| w.enable().set_bit()); // Enable ADC
self.sync();
self.adc.swtrig().modify(|_, w| w.start().set_bit()); // Start sample
while self.adc.intflag().read().resrdy().bit_is_clear() {}
let res = self.adc.result().read().bits();
self.adc.ctrla().modify(|_, w| w.enable().clear_bit()); // Stop ADC (No sync required)
res
}

pub fn read_ptat_blocking(&mut self) -> u16 {
self.read_blocking(0x19)
}

pub fn read_ctat_blocking(&mut self) -> u16 {
self.read_blocking(0x1A)
}
}

impl<I: AdcInstance, T> Adc<I, T> {
#[inline(always)]
fn sync(&self) {
// Slightly more performant than checking the individual bits
@@ -372,28 +399,31 @@ impl<I: AdcInstance> Adc<I> {
while self.adc.syncbusy().read().inputctrl().bit_is_set() {}
}

pub fn read_blocking(&mut self, ch: u8) -> u16 {
self.sync();
self.mux(ch);
self.sync();
self.adc.ctrla().modify(|_, w| w.enable().set_bit()); // Enable ADC
self.sync();
self.adc.swtrig().modify(|_, w| w.start().set_bit()); // Start sample
while self.adc.intflag().read().resrdy().bit_is_clear() {}
let res = self.adc.result().read().bits();
self.adc.ctrla().modify(|_, w| w.enable().clear_bit()); // Stop ADC (No sync required)
res
}

#[cfg(feature = "async")]
pub async fn read(&mut self, ch: u8) -> u16 {
pub fn into_future<F>(self, _irqs: F) -> Adc<I, F>
where
F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
{
use crate::async_hal::interrupts::InterruptSource;
use core::{future::poll_fn, task::Poll};
self.disable_interrupts();
unsafe {
I::Interrupt::unpend();
I::Interrupt::enable();
}
Adc {
adc: self.adc,
_irqs: PhantomData,
}
}
}

#[cfg(feature = "async")]
impl<I: AdcInstance, F> Adc<I, F>
where
F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
{
pub async fn read(&mut self, ch: u8) -> u16 {
use core::{future::poll_fn, task::Poll};
self.disable_interrupts();
self.sync();
self.mux(ch);
self.sync();
@@ -406,7 +436,6 @@ impl<I: AdcInstance> Adc<I> {
self.disable_interrupts();
return Poll::Ready(self.result());
}

I::waker().register(cx.waker());
self.enable_interrupts();

@@ -419,19 +448,8 @@ impl<I: AdcInstance> Adc<I> {
})
.await;
self.adc.ctrla().modify(|_, w| w.enable().clear_bit()); // Stop ADC (No sync required)
unsafe {
I::Interrupt::disable();
}
result
}

pub fn read_ptat_blocking(&mut self) -> u16 {
self.read_blocking(0x19)
}

pub fn read_ctat_blocking(&mut self) -> u16 {
self.read_blocking(0x1A)
}
}

// Here I declare the number of channels for the SAME51 ADC