Skip to content
Merged
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
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ version = "0.2.5"

[dependencies.embedded-hal]
features = ["unproven"]
version = "0.2.3"
version = "0.2.4"

[dependencies.embedded-dma]
version = "0.1.2"

[dependencies.void]
default-features = false
version = "1.0.2"

[dependencies.stable_deref_trait]
default-features = false
version = "1.1"

[dev-dependencies]
cortex-m-rt = "0.6.10"
cortex-m-rtfm = "0.5.1"
Expand Down
78 changes: 78 additions & 0 deletions examples/adc-continious-dma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#![no_std]
#![no_main]

use cortex_m_rt::entry;

use crate::hal::{
adc::{
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
AdcClaim, ClockSource, Temperature, Vref,
},
dma::{config::DmaConfig, stream::DMAExt, TransferExt},
gpio::GpioExt,
rcc::{Config, RccExt},
stm32::Peripherals,
};
use stm32g4xx_hal as hal;

use log::info;

#[macro_use]
mod utils;

#[entry]
fn main() -> ! {
utils::logger::init();

info!("start");

let dp = Peripherals::take().unwrap();
let mut cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");

info!("rcc");
let rcc = dp.RCC.constrain();
let mut rcc = rcc.freeze(Config::hsi());

let streams = dp.DMA1.split(&rcc);
let config = DmaConfig::default()
.transfer_complete_interrupt(false)
.circular_buffer(true)
.memory_increment(true);

info!("Setup Gpio");
let gpioa = dp.GPIOA.split(&mut rcc);
let pa0 = gpioa.pa0.into_analog();

info!("Setup Adc1");
let (mut adc, syst) = dp.ADC1.claim(ClockSource::SystemClock, &rcc, cp.SYST);
cp.SYST = syst;

adc.enable_temperature(&dp.ADC12_COMMON);
adc.set_continuous(Continuous::Continuous);
adc.reset_sequence();
adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_640_5);
adc.configure_channel(&Temperature, Sequence::Two, SampleTime::Cycles_640_5);

info!("Setup DMA");
let first_buffer = cortex_m::singleton!(: [u16; 10] = [0; 10]).unwrap();
let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer(
adc.enable_dma(AdcDma::Continuous),
&mut first_buffer[..],
config,
);

transfer.start(|adc| adc.start_conversion());

loop {
let mut b = [0_u16; 4];
let r = transfer.read_exact(&mut b);

info!("read: {}", r);
assert!(r == b.len());

let millivolts = Vref::sample_to_millivolts((b[0] + b[2]) / 2);
info!("pa3: {}mV", millivolts);
let temp = Temperature::temperature_to_degrees_centigrade((b[1] + b[3]) / 2);
info!("temp: {}℃C", temp); // Note: Temperature seems quite low...
}
}
84 changes: 84 additions & 0 deletions examples/adc-one-shot-dma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#![no_std]
#![no_main]

use cortex_m_rt::entry;

use crate::hal::{
adc::{
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
AdcClaim, ClockSource, Temperature,
},
dma::{config::DmaConfig, stream::DMAExt, TransferExt},
gpio::GpioExt,
rcc::{Config, RccExt},
stm32::Peripherals,
};
use stm32g4xx_hal as hal;

use log::info;

#[macro_use]
mod utils;

#[entry]
fn main() -> ! {
utils::logger::init();

info!("start");

let dp = Peripherals::take().unwrap();
let mut cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");

info!("rcc");

let rcc = dp.RCC.constrain();
let mut rcc = rcc.freeze(Config::hsi());

let mut streams = dp.DMA1.split(&rcc);
let config = DmaConfig::default()
.transfer_complete_interrupt(false)
.circular_buffer(false)
.memory_increment(true);

info!("Setup Gpio");
let gpioa = dp.GPIOA.split(&mut rcc);
let pa0 = gpioa.pa0.into_analog();

info!("Setup Adc1");
let (mut adc, syst) = dp.ADC1.claim(ClockSource::SystemClock, &rcc, cp.SYST);
cp.SYST = syst;

adc.enable_temperature(&dp.ADC12_COMMON);
adc.set_continuous(Continuous::Single);
adc.reset_sequence();
adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_640_5);
adc.configure_channel(&Temperature, Sequence::Two, SampleTime::Cycles_640_5);

info!("Setup DMA");
let first_buffer = cortex_m::singleton!(: [u16; 2] = [0; 2]).unwrap();
let mut transfer = streams.0.into_peripheral_to_memory_transfer(
adc.enable_dma(AdcDma::Single),
&mut first_buffer[..],
config,
);

transfer.start(|adc| adc.start_conversion());

info!("Wait for Conversion");
while !transfer.get_transfer_complete_flag() {}
info!("Conversion Done");

transfer.pause(|adc| adc.cancel_conversion());
let (s0, adc, first_buffer) = transfer.free();
let adc = adc.disable();

streams.0 = s0;

let millivolts = adc.sample_to_millivolts(first_buffer[0]);
info!("pa3: {}mV", millivolts);
let millivolts = Temperature::temperature_to_degrees_centigrade(first_buffer[1]);
info!("temp: {}℃C", millivolts); // Note: Temperature seems quite low...

#[allow(clippy::empty_loop)]
loop {}
}
24 changes: 18 additions & 6 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
pub use crate::time::U32Ext as _;
use crate::{
delay::*,
dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory},
gpio::*,
rcc::Rcc,
signature::{VtempCal110, VtempCal30, VDDA_CALIB},
Expand Down Expand Up @@ -1191,7 +1192,7 @@ macro_rules! adc {
(additionals: $adc_type:ident => ($common_type:ident)) => {
};

($($adc_type:ident => ($enable_peripheral_fn_name:ident, $configure_clocks_fn_name:ident, ($common_type:ident) )),+ $(,)*) => {
($($adc_type:ident => ($enable_peripheral_fn_name:ident, $configure_clocks_fn_name:ident, $mux:expr, ($common_type:ident) )),+ $(,)*) => {
$(
impl AdcConfig for stm32::$adc_type {
#[inline(always)]
Expand Down Expand Up @@ -2139,6 +2140,17 @@ macro_rules! adc {
}
}

unsafe impl TargetAddress<PeripheralToMemory> for Adc<stm32::$adc_type, DMA> {
#[inline(always)]
fn address(&self) -> u32 {
self.adc.data_register_address()
}

type MemSize = u16;

const REQUEST_LINE: Option<u8> = Some($mux as u8);
}

impl<PIN> OneShot<stm32::$adc_type, u16, PIN> for Adc<stm32::$adc_type, Disabled>
where
PIN: Channel<stm32::$adc_type, ID=u8>,
Expand All @@ -2164,7 +2176,7 @@ macro_rules! adc {
feature = "stm32g491",
feature = "stm32g4a1",
))]
adc!(ADC1 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
adc!(ADC1 => (enable_pheripheral12, configure_clock_source12, DmaMuxResources::ADC1, (ADC12_COMMON) ));

#[cfg(any(
feature = "stm32g431",
Expand All @@ -2177,7 +2189,7 @@ adc!(ADC1 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
feature = "stm32g491",
feature = "stm32g4a1",
))]
adc!(ADC2 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
adc!(ADC2 => (enable_pheripheral12, configure_clock_source12, DmaMuxResources::ADC2, (ADC12_COMMON) ));

#[cfg(any(
feature = "stm32g471",
Expand All @@ -2188,23 +2200,23 @@ adc!(ADC2 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
feature = "stm32g491",
feature = "stm32g4a1",
))]
adc!(ADC3 => (enable_pheripheral345, configure_clock_source345, (ADC345_COMMON) ));
adc!(ADC3 => (enable_pheripheral345, configure_clock_source345, DmaMuxResources::ADC3, (ADC345_COMMON) ));

#[cfg(any(
feature = "stm32g473",
feature = "stm32g474",
feature = "stm32g483",
feature = "stm32g484",
))]
adc!(ADC4 => (enable_pheripheral345, configure_clock_source345, (ADC345_COMMON) ));
adc!(ADC4 => (enable_pheripheral345, configure_clock_source345, DmaMuxResources::ADC4, (ADC345_COMMON) ));

#[cfg(any(
feature = "stm32g473",
feature = "stm32g474",
feature = "stm32g483",
feature = "stm32g484",
))]
adc!(ADC5 => (enable_pheripheral345, configure_clock_source345, (ADC345_COMMON) ));
adc!(ADC5 => (enable_pheripheral345, configure_clock_source345, DmaMuxResources::ADC5, (ADC345_COMMON) ));

#[cfg(any(feature = "stm32g431", feature = "stm32g441", feature = "stm32g471",))]
adc_pins!(
Expand Down
131 changes: 131 additions & 0 deletions src/dma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//! Direct Memory Access.
//!
//! [Transfer::init](struct.Transfer.html#method.init) is only implemented for
//! valid combinations of peripheral-stream-channel-direction, providing compile
//! time checking.
//!
//! This module implements Memory To Memory, Peripheral To Memory and Memory to
//! Peripheral transfers.
//!
//! Given that the Cortex-M7 core is capable of reordering accesses between
//! normal and device memory, we insert DMB instructions to ensure correct
//! operation. See ARM DAI 0321A, Section 3.2 which discusses the use of DMB
//! instructions in DMA controller configuration.
//!
//! Adapted from
//! https://github.com/stm32-rs/stm32h7xx-hal/blob/master/src/dma/mod.rs
use core::fmt::Debug;

pub mod config;
pub(crate) mod mux;
pub mod stream; // DMA MUX // DMA1 and DMA2
pub mod traits;
pub mod transfer;

use traits::{sealed::Bits, Direction, Stream, TargetAddress};
pub use transfer::{Transfer, TransferExt};

/// Errors.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum DMAError {
/// DMA not ready to change buffers.
NotReady,
/// The user provided a buffer that is not big enough while double buffering.
SmallBuffer,
/// DMA started transfer on the inactive buffer while the user was processing it.
Overflow,
}

/// Possible DMA's directions.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DmaDirection {
/// Memory to Memory transfer.
MemoryToMemory,
/// Peripheral to Memory transfer.
PeripheralToMemory,
/// Memory to Peripheral transfer.
MemoryToPeripheral,
}

/// DMA from a peripheral to a memory location.
#[derive(Debug, Clone, Copy)]
pub struct PeripheralToMemory;

impl PeripheralToMemory {
pub fn new() -> Self {
PeripheralToMemory
}
}

impl Direction for PeripheralToMemory {
#[inline(always)]
fn direction() -> DmaDirection {
DmaDirection::PeripheralToMemory
}
}

/// DMA from one memory location to another memory location.
#[derive(Debug, Clone, Copy)]
pub struct MemoryToMemory<T>
where
T: Into<u32>,
{
data: T,
}

impl<T> MemoryToMemory<T>
where
T: Into<u32>,
{
pub fn new(t: T) -> Self {
Self { data: t }
}
}

impl<T> Direction for MemoryToMemory<T>
where
T: Into<u32>,
{
#[inline(always)]
fn direction() -> DmaDirection {
DmaDirection::MemoryToMemory
}
}

/// DMA from a memory location to a peripheral.
#[derive(Debug, Clone, Copy)]
pub struct MemoryToPeripheral;

impl MemoryToPeripheral {
pub fn new() -> Self {
MemoryToPeripheral
}
}

impl Direction for MemoryToPeripheral {
fn direction() -> DmaDirection {
DmaDirection::MemoryToPeripheral
}
}

unsafe impl TargetAddress<Self> for MemoryToMemory<u8> {
fn address(&self) -> u32 {
self.data.into()
}
type MemSize = u8;
}

unsafe impl TargetAddress<Self> for MemoryToMemory<u16> {
fn address(&self) -> u32 {
self.data.into()
}
type MemSize = u16;
}

unsafe impl TargetAddress<Self> for MemoryToMemory<u32> {
fn address(&self) -> u32 {
self.data.into()
}
type MemSize = u32;
}
Loading