Skip to content

Commit 9cba0fb

Browse files
ADC Interrupt and DMA support (#226)
* DMA stuff * Multichannel reading * Add DMA modes and sequences * Check addis before trying to enable Use replace_bits premade function Make this more equivalent to the oneshot implementation * Use new functions for OneShot implementation Write != modify... * Amount of transfers, not bytes * Use Transfer interface for ADC DMA transfers * Clarify comment * Improve UX for DMA interrupt event * Feature gate `L` register * Updates after rebasing * Use new DMA API * Add usage example * Remove circular DMA for now * Move DMA implementation to adc.rs
1 parent 3e81cfa commit 9cba0fb

File tree

4 files changed

+480
-51
lines changed

4 files changed

+480
-51
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,7 @@ required-features = ["stm32l4x1"]
152152
[[example]]
153153
name = "lptim_rtic"
154154
required-features = ["rt", "stm32l4x2"]
155+
156+
[[example]]
157+
name = "adc_dma"
158+
required-features = ["rt", "stm32l4x1"]

examples/adc_dma.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use panic_rtt_target as _;
5+
use rtt_target::{rprintln, rtt_init_print};
6+
use stm32l4xx_hal::{
7+
adc::{DmaMode, SampleTime, Sequence, ADC},
8+
delay::DelayCM,
9+
dma::{dma1, RxDma, Transfer, W},
10+
prelude::*,
11+
time::Hertz,
12+
};
13+
14+
use rtic::app;
15+
16+
const SEQUENCE_LEN: usize = 3;
17+
18+
#[app(device = stm32l4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
19+
const APP: () = {
20+
// RTIC app is written in here!
21+
22+
struct Resources {
23+
transfer: Option<Transfer<W, &'static mut [u16; SEQUENCE_LEN], RxDma<ADC, dma1::C1>>>,
24+
}
25+
26+
#[init]
27+
fn init(cx: init::Context) -> init::LateResources {
28+
let MEMORY = {
29+
static mut MEMORY: [u16; SEQUENCE_LEN] = [0u16; SEQUENCE_LEN];
30+
unsafe { &mut MEMORY }
31+
};
32+
33+
rtt_init_print!();
34+
35+
rprintln!("Hello from init!");
36+
37+
let cp = cx.core;
38+
let mut dcb = cp.DCB;
39+
let mut dwt = cp.DWT;
40+
41+
dcb.enable_trace();
42+
dwt.enable_cycle_counter();
43+
44+
let pac = cx.device;
45+
46+
let mut rcc = pac.RCC.constrain();
47+
let mut flash = pac.FLASH.constrain();
48+
let mut pwr = pac.PWR.constrain(&mut rcc.apb1r1);
49+
let dma_channels = pac.DMA1.split(&mut rcc.ahb1);
50+
51+
//
52+
// Initialize the clocks
53+
//
54+
let clocks = rcc
55+
.cfgr
56+
.sysclk(Hertz(80_000_000))
57+
.freeze(&mut flash.acr, &mut pwr);
58+
59+
let mut delay = DelayCM::new(clocks);
60+
61+
let mut adc = ADC::new(
62+
pac.ADC1,
63+
pac.ADC_COMMON,
64+
&mut rcc.ahb2,
65+
&mut rcc.ccipr,
66+
&mut delay,
67+
);
68+
69+
let mut temp_pin = adc.enable_temperature();
70+
71+
let dma1_channel = dma_channels.1;
72+
73+
adc.configure_sequence(&mut temp_pin, Sequence::One, SampleTime::Cycles12_5);
74+
adc.configure_sequence(&mut temp_pin, Sequence::Two, SampleTime::Cycles247_5);
75+
adc.configure_sequence(&mut temp_pin, Sequence::Three, SampleTime::Cycles640_5);
76+
77+
// Heapless boxes also work very well as buffers for DMA transfers
78+
let transfer = Transfer::from_adc(adc, dma1_channel, MEMORY, DmaMode::Oneshot, true);
79+
80+
init::LateResources {
81+
transfer: Some(transfer),
82+
}
83+
}
84+
85+
#[idle]
86+
fn idle(_cx: idle::Context) -> ! {
87+
loop {
88+
cortex_m::asm::nop();
89+
}
90+
}
91+
92+
#[task(binds = DMA1_CH1, resources = [transfer])]
93+
fn dma1_interrupt(cx: dma1_interrupt::Context) {
94+
let transfer = cx.resources.transfer;
95+
if let Some(transfer_val) = transfer.take() {
96+
let (buffer, rx_dma) = transfer_val.wait();
97+
rprintln!("DMA measurements: {:?}", buffer);
98+
*transfer = Some(Transfer::from_adc_dma(
99+
rx_dma,
100+
buffer,
101+
DmaMode::Oneshot,
102+
true,
103+
));
104+
}
105+
}
106+
};

0 commit comments

Comments
 (0)