Skip to content

Commit 4fdc432

Browse files
thalesfragosotherealprof
authored andcommitted
Adds DMA support for ADC1 (#73)
* Adds DMA support for ADC
1 parent 42bb6ec commit 4fdc432

File tree

9 files changed

+355
-67
lines changed

9 files changed

+355
-67
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Added DMA support for ADC1.
1213
- Added type aliases `Tx1` for `Tx<USART1>`, `RxDma1` for `RxDma<USART1, dma1::C5>`, etc.
1314
- Add ADC1 reading functions for channels 16 (temperature) and 17 (internal reference voltage)
1415
- Update existing ADC example according to ADC API changes

examples/adc-dma-circ.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! ADC interface circular DMA RX transfer test
2+
3+
#![no_main]
4+
#![no_std]
5+
6+
use panic_halt as _;
7+
8+
use cortex_m::{asm, singleton};
9+
10+
use stm32f1xx_hal::{
11+
prelude::*,
12+
pac,
13+
adc,
14+
dma::Half,
15+
};
16+
use cortex_m_rt::entry;
17+
18+
#[entry]
19+
fn main() -> ! {
20+
// Aquire peripherals
21+
let p = pac::Peripherals::take().unwrap();
22+
let mut flash = p.FLASH.constrain();
23+
let mut rcc = p.RCC.constrain();
24+
25+
// Configure ADC clocks
26+
// Default value is the slowest possible ADC clock: PCLK2 / 8. Meanwhile ADC
27+
// clock is configurable. So its frequency may be tweaked to meet certain
28+
// practical needs. User specified value is be approximated using supported
29+
// prescaler values 2/4/6/8.
30+
let clocks = rcc.cfgr.adcclk(2.mhz()).freeze(&mut flash.acr);
31+
32+
let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;
33+
34+
// Setup ADC
35+
let adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
36+
37+
// Setup GPIOA
38+
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
39+
40+
// Configure pa0 as an analog input
41+
let adc_ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);
42+
43+
let adc_dma = adc1.with_dma(adc_ch0, dma_ch1);
44+
let buf = singleton!(: [[u16; 8]; 2] = [[0; 8]; 2]).unwrap();
45+
46+
let mut circ_buffer = adc_dma.circ_read(buf);
47+
48+
while circ_buffer.readable_half().unwrap() != Half::First {}
49+
50+
let _first_half = circ_buffer.peek(|half, _| *half).unwrap();
51+
52+
while circ_buffer.readable_half().unwrap() != Half::Second {}
53+
54+
let _second_half = circ_buffer.peek(|half, _| *half).unwrap();
55+
56+
let (_buf, adc_dma) = circ_buffer.stop();
57+
let (_adc1, _adc_ch0, _dma_ch1) = adc_dma.split();
58+
asm::bkpt();
59+
60+
loop {}
61+
}

examples/adc-dma-rx.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//! ADC interface DMA RX transfer test
2+
3+
#![no_main]
4+
#![no_std]
5+
6+
use panic_halt as _;
7+
8+
use cortex_m::{asm, singleton};
9+
10+
use stm32f1xx_hal::{
11+
prelude::*,
12+
pac,
13+
adc,
14+
};
15+
use cortex_m_rt::entry;
16+
17+
#[entry]
18+
fn main() -> ! {
19+
// Aquire peripherals
20+
let p = pac::Peripherals::take().unwrap();
21+
let mut flash = p.FLASH.constrain();
22+
let mut rcc = p.RCC.constrain();
23+
24+
// Configure ADC clocks
25+
// Default value is the slowest possible ADC clock: PCLK2 / 8. Meanwhile ADC
26+
// clock is configurable. So its frequency may be tweaked to meet certain
27+
// practical needs. User specified value is be approximated using supported
28+
// prescaler values 2/4/6/8.
29+
let clocks = rcc.cfgr.adcclk(2.mhz()).freeze(&mut flash.acr);
30+
31+
let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;
32+
33+
// Setup ADC
34+
let adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
35+
36+
// Setup GPIOA
37+
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
38+
39+
// Configure pa0 as an analog input
40+
let adc_ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);
41+
42+
let adc_dma = adc1.with_dma(adc_ch0, dma_ch1);
43+
let buf = singleton!(: [u16; 8] = [0; 8]).unwrap();
44+
45+
// The read method consumes the buf and self, starts the adc and dma transfer and returns a
46+
// RxDma struct. The wait method consumes the RxDma struct, waits for the whole transfer to be
47+
// completed and then returns the updated buf and underlying adc_dma struct. For non blocking,
48+
// one can call the is_done method of RxDma and only call wait after that method returns true.
49+
let (_buf, adc_dma) = adc_dma.read(buf).wait();
50+
asm::bkpt();
51+
52+
// Consumes the AdcDma struct, restores adc configuration to previous state and returns the
53+
// Adc struct in normal mode.
54+
let (_adc1, _adc_ch0, _dma_ch1) = adc_dma.split();
55+
asm::bkpt();
56+
57+
loop {}
58+
}

examples/adc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ fn main() -> ! {
2929
hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();
3030

3131
// Setup ADC
32-
let mut adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks.adcclk());
32+
let mut adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
3333

3434
#[cfg(feature = "stm32f103")]
35-
let mut adc2 = adc::Adc::adc2(p.ADC2, &mut rcc.apb2, clocks.adcclk());
35+
let mut adc2 = adc::Adc::adc2(p.ADC2, &mut rcc.apb2, clocks);
3636

3737
// Setup GPIOB
3838
let mut gpiob = p.GPIOB.split(&mut rcc.apb2);

examples/adc_temperature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn main() -> ! {
2525
hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();
2626

2727
// Setup ADC
28-
let mut adc = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks.adcclk());
28+
let mut adc = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
2929

3030
// Read temperature sensor
3131
loop {

0 commit comments

Comments
 (0)