Skip to content

Commit

Permalink
Adds delays for start up times
Browse files Browse the repository at this point in the history
  • Loading branch information
thalesfragoso committed Jun 13, 2019
1 parent 75bee83 commit 18e8b1c
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 15 deletions.
2 changes: 1 addition & 1 deletion examples/adc-dma-circ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn main() -> ! {
let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;

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

// Setup GPIOA
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
Expand Down
8 changes: 7 additions & 1 deletion examples/adc-dma-rx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn main() -> ! {
let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;

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

// Setup GPIOA
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
Expand All @@ -42,9 +42,15 @@ fn main() -> ! {
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();

Expand Down
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
50 changes: 40 additions & 10 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use embedded_hal::adc::{Channel, OneShot};

use crate::gpio::Analog;
use crate::gpio::{gpioa, gpiob, gpioc};
use crate::rcc::APB2;
use crate::time::Hertz;
use crate::rcc::{APB2, Clocks};
use crate::dma::{Receive, TransferPayload, dma1::C1, CircBuffer, Transfer, W, RxDma};
use core::sync::atomic::{self, Ordering};
use cortex_m::asm::delay;

use crate::stm32::ADC1;
#[cfg(any(
Expand All @@ -20,7 +20,7 @@ pub struct Adc<ADC> {
rb: ADC,
sample_time: AdcSampleTime,
align: AdcAlign,
clk: Hertz
clocks: Clocks
}

#[derive(Clone, Copy, Debug, PartialEq)]
Expand Down Expand Up @@ -175,18 +175,29 @@ macro_rules! adc_hal {
///
/// Sets all configurable parameters to one-shot defaults,
/// performs a boot-time calibration.
pub fn $init(adc: $ADC, apb2: &mut APB2, clk: Hertz) -> Self {
pub fn $init(adc: $ADC, apb2: &mut APB2, clocks: Clocks) -> Self {
let mut s = Self {
rb: adc,
sample_time: AdcSampleTime::default(),
align: AdcAlign::default(),
clk: clk,
clocks,
};
s.enable_clock(apb2);
s.power_down();
s.reset(apb2);
s.setup_oneshot();
s.power_up();

// The manual states that we need to wait two ADC clocks cycles after power-up
// before starting calibration, we already delayed in the power-up process, but
// if the adc clock is too low that was not enough.
if s.clocks.adcclk().0 < 2_500_000 {
let two_adc_cycles = s.clocks.sysclk().0 / s.clocks.adcclk().0 *2;
let already_delayed = s.clocks.sysclk().0 / 800_000;
if two_adc_cycles > already_delayed {
delay(two_adc_cycles - already_delayed);
}
}
s.calibrate();
s
}
Expand Down Expand Up @@ -234,6 +245,12 @@ macro_rules! adc_hal {

fn power_up(&mut self) {
self.rb.cr2.modify(|_, w| w.adon().set_bit());

// The reference manual says that a stabilization time is needed after power_up,
// this time can be found in the datasheets.
// Here we are delaying for approximately 1us, considering 1.25 instructions per
// cycle. Do we support a chip which needs more than 1us ?
delay(self.clocks.sysclk().0 / 800_000);
}

fn power_down(&mut self) {
Expand All @@ -249,6 +266,10 @@ macro_rules! adc_hal {
apb2.enr().modify(|_, w| w.$adcxen().set_bit());
}

fn disable_clock(&mut self, apb2: &mut APB2) {
apb2.enr().modify(|_, w| w.$adcxen().clear_bit());
}

fn calibrate(&mut self) {
/* reset calibration */
self.rb.cr2.modify(|_, w| w.rstcal().set_bit());
Expand Down Expand Up @@ -365,6 +386,13 @@ macro_rules! adc_hal {
let res = self.rb.dr.read().data().bits();
res
}

/// Powers down the ADC, disables the ADC clock and releases the ADC Peripheral
pub fn release(mut self, apb2: &mut APB2) -> $ADC {
self.power_down();
self.disable_clock(apb2);
self.rb
}
}

impl<WORD, PIN> OneShot<$ADC, WORD, PIN> for Adc<$ADC>
Expand All @@ -375,9 +403,7 @@ macro_rules! adc_hal {
type Error = ();

fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
self.power_up();
let res = self.convert(PIN::channel());
self.power_down();
Ok(res.into())
}
}
Expand All @@ -390,14 +416,18 @@ impl Adc<ADC1> {
fn read_aux(&mut self, chan: u8) -> u16 {
let tsv_off = if self.rb.cr2.read().tsvrefe().bit_is_clear() {
self.rb.cr2.modify(|_, w| w.tsvrefe().set_bit());

// The reference manual says that a stabilization time is needed after the powering the
// sensor, this time can be found in the datasheets.
// Here we are delaying for approximately 10us, considering 1.25 instructions per
// cycle. Do we support a chip which needs more than 10us ?
delay(self.clocks.sysclk().0 / 80_000);
true
} else {
false
};

self.power_up();
let val = self.convert(chan);
self.power_down();

if tsv_off {
self.rb.cr2.modify(|_, w| w.tsvrefe().clear_bit());
Expand Down Expand Up @@ -431,7 +461,7 @@ impl Adc<ADC1> {
// recommended ADC sampling for temperature sensor is 17.1 usec,
// so use the following approximate settings
// to support all ADC frequencies
let sample_time = match self.clk.0 {
let sample_time = match self.clocks.adcclk().0 {
0 ... 1_200_000 => AdcSampleTime::T_1,
1_200_001 ... 1_500_000 => AdcSampleTime::T_7,
1_500_001 ... 2_400_000 => AdcSampleTime::T_13,
Expand Down

0 comments on commit 18e8b1c

Please sign in to comment.