Skip to content

Commit

Permalink
Adds DMA support for ADC1 (#73)
Browse files Browse the repository at this point in the history
* Adds DMA support for ADC
  • Loading branch information
thalesfragoso authored and therealprof committed Jun 20, 2019
1 parent 42bb6ec commit 4fdc432
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Added DMA support for ADC1.
- Added type aliases `Tx1` for `Tx<USART1>`, `RxDma1` for `RxDma<USART1, dma1::C5>`, etc.
- Add ADC1 reading functions for channels 16 (temperature) and 17 (internal reference voltage)
- Update existing ADC example according to ADC API changes
Expand Down
61 changes: 61 additions & 0 deletions examples/adc-dma-circ.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! ADC interface circular DMA RX transfer test
#![no_main]
#![no_std]

use panic_halt as _;

use cortex_m::{asm, singleton};

use stm32f1xx_hal::{
prelude::*,
pac,
adc,
dma::Half,
};
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
// Aquire peripherals
let p = pac::Peripherals::take().unwrap();
let mut flash = p.FLASH.constrain();
let mut rcc = p.RCC.constrain();

// Configure ADC clocks
// Default value is the slowest possible ADC clock: PCLK2 / 8. Meanwhile ADC
// clock is configurable. So its frequency may be tweaked to meet certain
// practical needs. User specified value is be approximated using supported
// prescaler values 2/4/6/8.
let clocks = rcc.cfgr.adcclk(2.mhz()).freeze(&mut flash.acr);

let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;

// Setup ADC
let adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);

// Setup GPIOA
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);

// Configure pa0 as an analog input
let adc_ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);

let adc_dma = adc1.with_dma(adc_ch0, dma_ch1);
let buf = singleton!(: [[u16; 8]; 2] = [[0; 8]; 2]).unwrap();

let mut circ_buffer = adc_dma.circ_read(buf);

while circ_buffer.readable_half().unwrap() != Half::First {}

let _first_half = circ_buffer.peek(|half, _| *half).unwrap();

while circ_buffer.readable_half().unwrap() != Half::Second {}

let _second_half = circ_buffer.peek(|half, _| *half).unwrap();

let (_buf, adc_dma) = circ_buffer.stop();
let (_adc1, _adc_ch0, _dma_ch1) = adc_dma.split();
asm::bkpt();

loop {}
}
58 changes: 58 additions & 0 deletions examples/adc-dma-rx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//! ADC interface DMA RX transfer test
#![no_main]
#![no_std]

use panic_halt as _;

use cortex_m::{asm, singleton};

use stm32f1xx_hal::{
prelude::*,
pac,
adc,
};
use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
// Aquire peripherals
let p = pac::Peripherals::take().unwrap();
let mut flash = p.FLASH.constrain();
let mut rcc = p.RCC.constrain();

// Configure ADC clocks
// Default value is the slowest possible ADC clock: PCLK2 / 8. Meanwhile ADC
// clock is configurable. So its frequency may be tweaked to meet certain
// practical needs. User specified value is be approximated using supported
// prescaler values 2/4/6/8.
let clocks = rcc.cfgr.adcclk(2.mhz()).freeze(&mut flash.acr);

let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;

// Setup ADC
let adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);

// Setup GPIOA
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);

// Configure pa0 as an analog input
let adc_ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);

let adc_dma = adc1.with_dma(adc_ch0, dma_ch1);
let buf = singleton!(: [u16; 8] = [0; 8]).unwrap();

// The read method consumes the buf and self, starts the adc and dma transfer and returns a
// RxDma struct. The wait method consumes the RxDma struct, waits for the whole transfer to be
// completed and then returns the updated buf and underlying adc_dma struct. For non blocking,
// one can call the is_done method of RxDma and only call wait after that method returns true.
let (_buf, adc_dma) = adc_dma.read(buf).wait();
asm::bkpt();

// Consumes the AdcDma struct, restores adc configuration to previous state and returns the
// Adc struct in normal mode.
let (_adc1, _adc_ch0, _dma_ch1) = adc_dma.split();
asm::bkpt();

loop {}
}
4 changes: 2 additions & 2 deletions examples/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ fn main() -> ! {
hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();

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

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

// Setup GPIOB
let mut gpiob = p.GPIOB.split(&mut rcc.apb2);
Expand Down
2 changes: 1 addition & 1 deletion examples/adc_temperature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn main() -> ! {
hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();

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

// Read temperature sensor
loop {
Expand Down
Loading

0 comments on commit 4fdc432

Please sign in to comment.