Skip to content

Commit 651bc67

Browse files
author
Cor Peters
committed
Added dma support +dma-adc examples
1 parent b1905bc commit 651bc67

File tree

11 files changed

+1898
-8
lines changed

11 files changed

+1898
-8
lines changed

Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,19 @@ version = "0.2.5"
2323

2424
[dependencies.embedded-hal]
2525
features = ["unproven"]
26-
version = "0.2.3"
26+
version = "0.2.4"
27+
28+
[dependencies.embedded-dma]
29+
version = "0.1.2"
2730

2831
[dependencies.void]
2932
default-features = false
3033
version = "1.0.2"
3134

35+
[dependencies.stable_deref_trait]
36+
default-features = false
37+
version = "1.1"
38+
3239
[dev-dependencies]
3340
cortex-m-rt = "0.6.10"
3441
cortex-m-rtfm = "0.5.1"

examples/adc-continious-dma.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use cortex_m_rt::entry;
5+
6+
use crate::hal::{
7+
adc::{
8+
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
9+
AdcClaim, ClockSource, Temperature, Vref,
10+
},
11+
dma::{config::DmaConfig, stream::DMAExt, TransferExt},
12+
gpio::GpioExt,
13+
rcc::{Config, RccExt},
14+
stm32::Peripherals,
15+
};
16+
use stm32g4xx_hal as hal;
17+
18+
use log::info;
19+
20+
#[macro_use]
21+
mod utils;
22+
23+
#[entry]
24+
fn main() -> ! {
25+
utils::logger::init();
26+
27+
info!("start");
28+
29+
let dp = Peripherals::take().unwrap();
30+
let mut cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");
31+
32+
info!("rcc");
33+
let rcc = dp.RCC.constrain();
34+
let mut rcc = rcc.freeze(Config::hsi());
35+
36+
let streams = dp.DMA1.split(&rcc);
37+
let config = DmaConfig::default()
38+
.transfer_complete_interrupt(false)
39+
.circular_buffer(true)
40+
.memory_increment(true);
41+
42+
info!("Setup Gpio");
43+
let gpioa = dp.GPIOA.split(&mut rcc);
44+
let pa0 = gpioa.pa0.into_analog();
45+
46+
info!("Setup Adc1");
47+
let (mut adc, syst) = dp.ADC1.claim(ClockSource::SystemClock, &rcc, cp.SYST);
48+
cp.SYST = syst;
49+
50+
adc.enable_temperature(&dp.ADC12_COMMON);
51+
adc.set_continuous(Continuous::Continuous);
52+
adc.reset_sequence();
53+
adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_640_5);
54+
adc.configure_channel(&Temperature, Sequence::Two, SampleTime::Cycles_640_5);
55+
56+
info!("Setup DMA");
57+
let first_buffer = cortex_m::singleton!(: [u16; 10] = [0; 10]).unwrap();
58+
let mut transfer = streams.0.into_circ_peripheral_to_memory_transfer(
59+
adc.enable_dma(AdcDma::Continuous),
60+
&mut first_buffer[..],
61+
config,
62+
);
63+
64+
transfer.start(|adc| adc.start_conversion());
65+
66+
loop {
67+
let mut b = [0_u16; 4];
68+
let r = transfer.read_exact(&mut b);
69+
70+
info!("read: {}", r);
71+
assert!(r == b.len());
72+
73+
let millivolts = Vref::sample_to_millivolts((b[0] + b[2]) / 2);
74+
info!("pa3: {}mV", millivolts);
75+
let temp = Temperature::temperature_to_degrees_centigrade((b[1] + b[3]) / 2);
76+
info!("temp: {}℃C", temp); // Note: Temperature seems quite low...
77+
}
78+
}

examples/adc-one-shot-dma.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use cortex_m_rt::entry;
5+
6+
use crate::hal::{
7+
adc::{
8+
config::{Continuous, Dma as AdcDma, SampleTime, Sequence},
9+
AdcClaim, ClockSource, Temperature,
10+
},
11+
dma::{config::DmaConfig, stream::DMAExt, TransferExt},
12+
gpio::GpioExt,
13+
rcc::{Config, RccExt},
14+
stm32::Peripherals,
15+
};
16+
use stm32g4xx_hal as hal;
17+
18+
use log::info;
19+
20+
#[macro_use]
21+
mod utils;
22+
23+
#[entry]
24+
fn main() -> ! {
25+
utils::logger::init();
26+
27+
info!("start");
28+
29+
let dp = Peripherals::take().unwrap();
30+
let mut cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");
31+
32+
info!("rcc");
33+
34+
let rcc = dp.RCC.constrain();
35+
let mut rcc = rcc.freeze(Config::hsi());
36+
37+
let mut streams = dp.DMA1.split(&rcc);
38+
let config = DmaConfig::default()
39+
.transfer_complete_interrupt(false)
40+
.circular_buffer(false)
41+
.memory_increment(true);
42+
43+
info!("Setup Gpio");
44+
let gpioa = dp.GPIOA.split(&mut rcc);
45+
let pa0 = gpioa.pa0.into_analog();
46+
47+
info!("Setup Adc1");
48+
let (mut adc, syst) = dp.ADC1.claim(ClockSource::SystemClock, &rcc, cp.SYST);
49+
cp.SYST = syst;
50+
51+
adc.enable_temperature(&dp.ADC12_COMMON);
52+
adc.set_continuous(Continuous::Single);
53+
adc.reset_sequence();
54+
adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_640_5);
55+
adc.configure_channel(&Temperature, Sequence::Two, SampleTime::Cycles_640_5);
56+
57+
info!("Setup DMA");
58+
let first_buffer = cortex_m::singleton!(: [u16; 2] = [0; 2]).unwrap();
59+
let mut transfer = streams.0.into_peripheral_to_memory_transfer(
60+
adc.enable_dma(AdcDma::Single),
61+
&mut first_buffer[..],
62+
config,
63+
);
64+
65+
transfer.start(|adc| adc.start_conversion());
66+
67+
info!("Wait for Conversion");
68+
while !transfer.get_transfer_complete_flag() {}
69+
info!("Conversion Done");
70+
71+
transfer.pause(|adc| adc.cancel_conversion());
72+
let (s0, adc, first_buffer) = transfer.free();
73+
let adc = adc.disable();
74+
75+
streams.0 = s0;
76+
77+
let millivolts = adc.sample_to_millivolts(first_buffer[0]);
78+
info!("pa3: {}mV", millivolts);
79+
let millivolts = Temperature::temperature_to_degrees_centigrade(first_buffer[1]);
80+
info!("temp: {}℃C", millivolts); // Note: Temperature seems quite low...
81+
82+
#[allow(clippy::empty_loop)]
83+
loop {}
84+
}

src/adc.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
pub use crate::time::U32Ext as _;
1313
use crate::{
1414
delay::*,
15+
dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory},
1516
gpio::*,
1617
rcc::Rcc,
1718
signature::{VtempCal110, VtempCal30, VDDA_CALIB},
@@ -1191,7 +1192,7 @@ macro_rules! adc {
11911192
(additionals: $adc_type:ident => ($common_type:ident)) => {
11921193
};
11931194

1194-
($($adc_type:ident => ($enable_peripheral_fn_name:ident, $configure_clocks_fn_name:ident, ($common_type:ident) )),+ $(,)*) => {
1195+
($($adc_type:ident => ($enable_peripheral_fn_name:ident, $configure_clocks_fn_name:ident, $mux:expr, ($common_type:ident) )),+ $(,)*) => {
11951196
$(
11961197
impl AdcConfig for stm32::$adc_type {
11971198
#[inline(always)]
@@ -2139,6 +2140,17 @@ macro_rules! adc {
21392140
}
21402141
}
21412142

2143+
unsafe impl TargetAddress<PeripheralToMemory> for Adc<stm32::$adc_type, DMA> {
2144+
#[inline(always)]
2145+
fn address(&self) -> u32 {
2146+
self.adc.data_register_address()
2147+
}
2148+
2149+
type MemSize = u16;
2150+
2151+
const REQUEST_LINE: Option<u8> = Some($mux as u8);
2152+
}
2153+
21422154
impl<PIN> OneShot<stm32::$adc_type, u16, PIN> for Adc<stm32::$adc_type, Disabled>
21432155
where
21442156
PIN: Channel<stm32::$adc_type, ID=u8>,
@@ -2164,7 +2176,7 @@ macro_rules! adc {
21642176
feature = "stm32g491",
21652177
feature = "stm32g4a1",
21662178
))]
2167-
adc!(ADC1 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
2179+
adc!(ADC1 => (enable_pheripheral12, configure_clock_source12, DmaMuxResources::ADC1, (ADC12_COMMON) ));
21682180

21692181
#[cfg(any(
21702182
feature = "stm32g431",
@@ -2177,7 +2189,7 @@ adc!(ADC1 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
21772189
feature = "stm32g491",
21782190
feature = "stm32g4a1",
21792191
))]
2180-
adc!(ADC2 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
2192+
adc!(ADC2 => (enable_pheripheral12, configure_clock_source12, DmaMuxResources::ADC2, (ADC12_COMMON) ));
21812193

21822194
#[cfg(any(
21832195
feature = "stm32g471",
@@ -2188,23 +2200,23 @@ adc!(ADC2 => (enable_pheripheral12, configure_clock_source12, (ADC12_COMMON) ));
21882200
feature = "stm32g491",
21892201
feature = "stm32g4a1",
21902202
))]
2191-
adc!(ADC3 => (enable_pheripheral345, configure_clock_source345, (ADC345_COMMON) ));
2203+
adc!(ADC3 => (enable_pheripheral345, configure_clock_source345, DmaMuxResources::ADC3, (ADC345_COMMON) ));
21922204

21932205
#[cfg(any(
21942206
feature = "stm32g473",
21952207
feature = "stm32g474",
21962208
feature = "stm32g483",
21972209
feature = "stm32g484",
21982210
))]
2199-
adc!(ADC4 => (enable_pheripheral345, configure_clock_source345, (ADC345_COMMON) ));
2211+
adc!(ADC4 => (enable_pheripheral345, configure_clock_source345, DmaMuxResources::ADC4, (ADC345_COMMON) ));
22002212

22012213
#[cfg(any(
22022214
feature = "stm32g473",
22032215
feature = "stm32g474",
22042216
feature = "stm32g483",
22052217
feature = "stm32g484",
22062218
))]
2207-
adc!(ADC5 => (enable_pheripheral345, configure_clock_source345, (ADC345_COMMON) ));
2219+
adc!(ADC5 => (enable_pheripheral345, configure_clock_source345, DmaMuxResources::ADC5, (ADC345_COMMON) ));
22082220

22092221
#[cfg(any(feature = "stm32g431", feature = "stm32g441", feature = "stm32g471",))]
22102222
adc_pins!(

src/dma.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//! Direct Memory Access.
2+
//!
3+
//! [Transfer::init](struct.Transfer.html#method.init) is only implemented for
4+
//! valid combinations of peripheral-stream-channel-direction, providing compile
5+
//! time checking.
6+
//!
7+
//! This module implements Memory To Memory, Peripheral To Memory and Memory to
8+
//! Peripheral transfers.
9+
//!
10+
//! Given that the Cortex-M7 core is capable of reordering accesses between
11+
//! normal and device memory, we insert DMB instructions to ensure correct
12+
//! operation. See ARM DAI 0321A, Section 3.2 which discusses the use of DMB
13+
//! instructions in DMA controller configuration.
14+
//!
15+
//! Adapted from
16+
//! https://github.com/stm32-rs/stm32h7xx-hal/blob/master/src/dma/mod.rs
17+
18+
use core::fmt::Debug;
19+
20+
pub mod config;
21+
pub(crate) mod mux;
22+
pub mod stream; // DMA MUX // DMA1 and DMA2
23+
pub mod traits;
24+
pub mod transfer;
25+
26+
use traits::{sealed::Bits, Direction, Stream, TargetAddress};
27+
pub use transfer::{Transfer, TransferExt};
28+
29+
/// Errors.
30+
#[derive(PartialEq, Debug, Copy, Clone)]
31+
pub enum DMAError {
32+
/// DMA not ready to change buffers.
33+
NotReady,
34+
/// The user provided a buffer that is not big enough while double buffering.
35+
SmallBuffer,
36+
/// DMA started transfer on the inactive buffer while the user was processing it.
37+
Overflow,
38+
}
39+
40+
/// Possible DMA's directions.
41+
#[derive(Debug, Clone, Copy, PartialEq)]
42+
pub enum DmaDirection {
43+
/// Memory to Memory transfer.
44+
MemoryToMemory,
45+
/// Peripheral to Memory transfer.
46+
PeripheralToMemory,
47+
/// Memory to Peripheral transfer.
48+
MemoryToPeripheral,
49+
}
50+
51+
/// DMA from a peripheral to a memory location.
52+
#[derive(Debug, Clone, Copy)]
53+
pub struct PeripheralToMemory;
54+
55+
impl PeripheralToMemory {
56+
pub fn new() -> Self {
57+
PeripheralToMemory
58+
}
59+
}
60+
61+
impl Direction for PeripheralToMemory {
62+
#[inline(always)]
63+
fn direction() -> DmaDirection {
64+
DmaDirection::PeripheralToMemory
65+
}
66+
}
67+
68+
/// DMA from one memory location to another memory location.
69+
#[derive(Debug, Clone, Copy)]
70+
pub struct MemoryToMemory<T>
71+
where
72+
T: Into<u32>,
73+
{
74+
data: T,
75+
}
76+
77+
impl<T> MemoryToMemory<T>
78+
where
79+
T: Into<u32>,
80+
{
81+
pub fn new(t: T) -> Self {
82+
Self { data: t }
83+
}
84+
}
85+
86+
impl<T> Direction for MemoryToMemory<T>
87+
where
88+
T: Into<u32>,
89+
{
90+
#[inline(always)]
91+
fn direction() -> DmaDirection {
92+
DmaDirection::MemoryToMemory
93+
}
94+
}
95+
96+
/// DMA from a memory location to a peripheral.
97+
#[derive(Debug, Clone, Copy)]
98+
pub struct MemoryToPeripheral;
99+
100+
impl MemoryToPeripheral {
101+
pub fn new() -> Self {
102+
MemoryToPeripheral
103+
}
104+
}
105+
106+
impl Direction for MemoryToPeripheral {
107+
fn direction() -> DmaDirection {
108+
DmaDirection::MemoryToPeripheral
109+
}
110+
}
111+
112+
unsafe impl TargetAddress<Self> for MemoryToMemory<u8> {
113+
fn address(&self) -> u32 {
114+
self.data.into()
115+
}
116+
type MemSize = u8;
117+
}
118+
119+
unsafe impl TargetAddress<Self> for MemoryToMemory<u16> {
120+
fn address(&self) -> u32 {
121+
self.data.into()
122+
}
123+
type MemSize = u16;
124+
}
125+
126+
unsafe impl TargetAddress<Self> for MemoryToMemory<u32> {
127+
fn address(&self) -> u32 {
128+
self.data.into()
129+
}
130+
type MemSize = u32;
131+
}

0 commit comments

Comments
 (0)