Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions hal/src/peripherals/adc/d11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use super::{
#[cfg(feature = "async")]
use super::{FutureAdc, async_api};

#[cfg(feature = "dma")]
use pac::dmac::chctrlb::Trigsrcselect as TriggerSelect;

use crate::{calibration, pac};
use pac::Peripherals;
use pac::Sysctrl;
Expand All @@ -22,6 +25,8 @@ impl PrimaryAdc for Adc0 {}
impl AdcInstance for Adc0 {
type Instance = pac::Adc;

const DMA_TRIGGER: TriggerSelect = TriggerSelect::AdcResrdy;

#[cfg(feature = "async")]
type Interrupt = crate::async_hal::interrupts::ADC;

Expand Down
17 changes: 13 additions & 4 deletions hal/src/peripherals/adc/d5x/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ pub mod pin;
use pac::Supc;

#[cfg(feature = "async")]
use super::{FutureAdc, async_api};
use super::{async_api, FutureAdc};

#[cfg(feature = "dma")]
use pac::dmac::channel::chctrla::Trigsrcselect as TriggerSelect;

use super::{
ADC_SETTINGS_INTERNAL_READ, Accumulation, Adc, AdcInstance, AdcSettings, CpuVoltageSource,
Error, Flags, PrimaryAdc, SampleCount,
Accumulation, Adc, AdcInstance, AdcSettings, CpuVoltageSource, Error, Flags, PrimaryAdc,
SampleCount, ADC_SETTINGS_INTERNAL_READ,
};
use crate::{calibration, pac};

Expand All @@ -21,6 +24,9 @@ impl PrimaryAdc for Adc0 {}
impl AdcInstance for Adc0 {
type Instance = pac::Adc0;

#[cfg(feature = "dma")]
const DMA_TRIGGER: TriggerSelect = TriggerSelect::Adc0Resrdy;

type ClockId = crate::clock::v2::pclk::ids::Adc0;

#[cfg(feature = "async")]
Expand Down Expand Up @@ -72,6 +78,9 @@ impl AdcInstance for Adc1 {

type ClockId = crate::clock::v2::pclk::ids::Adc1;

#[cfg(feature = "dma")]
const DMA_TRIGGER: TriggerSelect = TriggerSelect::Adc1Resrdy;

#[cfg(feature = "async")]
type Interrupt = crate::async_hal::interrupts::ADC1;

Expand Down Expand Up @@ -235,7 +244,7 @@ impl<I: AdcInstance> Adc<I> {
Flags::from_bits_truncate(bits)
}

#[cfg(feature="async")]
#[cfg(feature = "async")]
/// Clear the specified interrupt flags
#[inline]
pub(super) fn clear_flags(&mut self, flags: &Flags) {
Expand Down
255 changes: 170 additions & 85 deletions hal/src/peripherals/adc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
//! adc.read_buffer(&mut adc_pin, &mut _buffer).unwrap();
//! ```

use core::ops::Deref;

use crate::{gpio::AnyPin, pac, typelevel::Sealed};
use atsamd_hal_macros::{hal_cfg, hal_module};
use core::ops::Deref;
use pac::Peripherals;

use crate::{gpio::AnyPin, pac, typelevel::Sealed};
#[cfg(feature = "dma")]
use pac::dmac;

#[hal_module(
any("adc-d11", "adc-d21") => "d11/mod.rs",
Expand All @@ -50,6 +51,14 @@ use crate::pac::adc as adc0;
#[hal_cfg("adc-d5x")]
use crate::pac::adc0;

#[cfg(feature = "dma")]
#[hal_cfg("adc-d5x")]
use dmac::channel::chctrla::Trigsrcselect as TriggerSelect;

#[cfg(feature = "dma")]
#[hal_cfg(any("adc-d11", "adc-d21"))]
use dmac::chctrlb::Trigsrcselect as TriggerSelect;

pub use adc0::refctrl::Refselselect as Reference;

/// ADC Settings when reading Internal sensors (Like VREF and Temperatures)
Expand Down Expand Up @@ -88,6 +97,16 @@ pub enum Error {
ClockTooFast,
/// Buffer overflowed
BufferOverrun,
/// DMA Error
#[cfg(feature = "dma")]
DmaError(crate::dmac::Error),
}

#[cfg(feature = "dma")]
impl From<crate::dmac::Error> for Error {
fn from(value: crate::dmac::Error) -> Self {
Self::DmaError(value)
}
}

/// Voltage source to use when using the ADC to measure the CPU voltage
Expand Down Expand Up @@ -140,6 +159,9 @@ pub trait AdcInstance {
// The Adc0 and Adc1 PAC types implement Deref
type Instance: Deref<Target = adc0::RegisterBlock>;

#[cfg(feature = "dma")]
const DMA_TRIGGER: TriggerSelect;

#[hal_cfg("adc-d5x")]
type ClockId: crate::clock::v2::apb::ApbId + crate::clock::v2::pclk::PclkId;

Expand Down Expand Up @@ -362,56 +384,6 @@ impl<I: AdcInstance> Adc<I> {
}
}

/// Read into a buffer from the provided ADC pin, in a blocking fashion
#[inline]
pub fn read_buffer<P: AdcPin<I>>(
&mut self,
_pin: &mut P,
dst: &mut [u16],
) -> Result<(), Error> {
self.read_buffer_channel(P::CHANNEL, dst)
}

/// Read into a buffer from the provided channel, in a blocking fashion
#[inline]
fn read_buffer_channel(&mut self, ch: u8, dst: &mut [u16]) -> Result<(), Error> {
// Clear overrun errors that might've occured before we try to read anything
self.clear_all_flags();
self.disable_interrupts(Flags::all());
self.mux(ch);
self.enable_freerunning();
self.start_conversion();
if self.discard {
// Discard first result
while !self.read_flags().contains(Flags::RESRDY) {
core::hint::spin_loop();
}
self.clear_all_flags();
self.discard = false;
}

for result in dst.iter_mut() {
while !self.read_flags().contains(Flags::RESRDY) {
core::hint::spin_loop();
}

let flags = self.read_flags();
self.clear_all_flags();
if let Err(e) = self.check_overrun(&flags) {
//self.power_down();
self.disable_freerunning();

return Err(e);
}

*result = self.conversion_result();
}
//self.power_down();
self.disable_freerunning();

Ok(())
}

/// Return the underlying ADC PAC object.
#[hal_cfg(any("adc-d11", "adc-d21"))]
#[inline]
Expand Down Expand Up @@ -479,47 +451,160 @@ where
self.inner.sync();
res
}
}

/// Read into a buffer from the provided ADC pin
#[inline]
pub async fn read_buffer<P: AdcPin<I>>(
&mut self,
_pin: &mut P,
dst: &mut [u16],
) -> Result<(), Error> {
self.read_buffer_channel(P::CHANNEL, dst).await
}
#[cfg(feature = "dma")]
mod dma {
use super::*;
#[cfg(feature = "async")]
use crate::dmac::ReadyFuture;
use crate::dmac::{AnyChannel, Buffer, Ready};

/// Read into a buffer from the provided channel ID
#[inline]
async fn read_buffer_channel(&mut self, ch: u8, dst: &mut [u16]) -> Result<(), Error> {
// Clear overrun errors that might've occured before we try to read anything
self.inner.clear_all_flags();
self.inner.mux(ch);
self.inner.enable_freerunning();
use atsamd_hal_macros::hal_macro_helper;
#[hal_cfg("adc-d5x")]
use pac::dmac::channel::chctrla::Trigactselect as TriggerAction;

if self.inner.discard {
// Discard first result
let _ = self.wait_flags(Flags::RESRDY).await;
let _ = self.inner.conversion_result();
self.inner.discard = false;
self.inner.clear_all_flags();
#[hal_cfg(any("adc-d11", "adc-d21"))]
use pac::dmac::chctrlb::Trigactselect as TriggerAction;

pub struct AdcDmaPtr(pub *mut u16);

unsafe impl Buffer for AdcDmaPtr {
type Beat = u16;

fn dma_ptr(&mut self) -> *mut Self::Beat {
self.0
}

fn incrementing(&self) -> bool {
false
}

fn buffer_len(&self) -> usize {
1
}
}

// Don't re-trigger start conversion now, its already enabled in free running
for result in dst.iter_mut() {
if let Err(e) = self.wait_flags(Flags::RESRDY).await {
//self.inner.power_down();
self.inner.disable_freerunning();
impl<I: AdcInstance> Adc<I> {
/// Read into a buffer from the provided ADC pin using DMA
/// in a blocking fashion
#[inline]
pub fn read_buffer<CH, P: AdcPin<I>>(
&mut self,
_pin: &mut P,
dst: &mut [u16],
channel: &mut CH,
) -> Result<(), Error>
where
CH: AnyChannel<Status = Ready>,
{
self.read_buffer_channel(P::CHANNEL, dst, channel)
}

return Err(e);
/// Read into a buffer from the provided channel, in a blocking fashion
#[inline]
#[hal_macro_helper]
fn read_buffer_channel<CH>(
&mut self,
ch: u8,
mut dst: &mut [u16],
channel: &mut CH,
) -> Result<(), Error>
where
CH: AnyChannel<Status = Ready>,
{
// Clear overrun errors that might've occured before we try to read anything
self.clear_all_flags();
self.disable_interrupts(Flags::all());
self.mux(ch);
self.enable_freerunning();
self.start_conversion();
if self.discard {
// Discard first result
while !self.read_flags().contains(Flags::RESRDY) {
core::hint::spin_loop();
}
self.clear_all_flags();
self.discard = false;
}
// Now read via DMA
let mut src = AdcDmaPtr(self.adc.result().as_ptr());

#[hal_cfg(any("adc-d5x"))]
let action = TriggerAction::Burst;
#[hal_cfg(any("adc-d11", "adc-d21"))]
let action = TriggerAction::Beat;
// SAFETY: We must make sure that any DMA transfer is complete or stopped before
// returning.
unsafe {
channel
.as_mut()
.transfer(&mut src, &mut dst, I::DMA_TRIGGER, action, None)?;
}
*result = self.inner.conversion_result();
while !channel.as_mut().xfer_complete() {
core::hint::spin_loop();
}
channel.as_mut().stop();
channel.as_mut().xfer_success()?;
self.disable_freerunning();
Ok(())
}
}

//self.inner.power_down();
self.inner.disable_freerunning();
#[cfg(feature = "async")]
impl<I: AdcInstance, F> FutureAdc<I, F>
where
F: crate::async_hal::interrupts::Binding<I::Interrupt, async_api::InterruptHandler<I>>,
{
/// Read into a buffer from the provided ADC pin using DMA
#[inline]
pub async fn read_buffer<CH, P: AdcPin<I>>(
&mut self,
_pin: &mut P,
dst: &mut [u16],
channel: &mut CH,
) -> Result<(), Error>
where
CH: AnyChannel<Status = ReadyFuture>,
{
self.read_buffer_channel(P::CHANNEL, dst, channel).await
}

Ok(())
#[inline]
#[hal_macro_helper]
async fn read_buffer_channel<CH>(
&mut self,
ch: u8,
dst: &mut [u16],
channel: &mut CH,
) -> Result<(), Error>
where
CH: AnyChannel<Status = ReadyFuture>,
{
// Clear overrun errors that might've occured before we try to read anything
self.inner.clear_all_flags();
self.inner.mux(ch);
self.inner.enable_freerunning();

if self.inner.discard {
// Discard first result
let _ = self.wait_flags(Flags::RESRDY).await;
let _ = self.inner.conversion_result();
self.inner.discard = false;
self.inner.clear_all_flags();
}
let src = AdcDmaPtr(self.inner.adc.result().as_ptr());
#[hal_cfg(any("adc-d5x"))]
let action = TriggerAction::Burst;
#[hal_cfg(any("adc-d11", "adc-d21"))]
let action = TriggerAction::Beat;
channel
.as_mut()
.transfer_future(src, dst, I::DMA_TRIGGER, action)
.await?;

self.inner.disable_freerunning();
Ok(())
}
}
}
Loading