Struct stm32wlxx_hal::adc::Adc
source · pub struct Adc { /* private fields */ }
stm32wl5x_cm0p
only.Expand description
Analog to digital converter driver.
Implementations§
source§impl Adc
impl Adc
sourcepub fn new(adc: ADC, clk: Clk, rcc: &mut RCC) -> Self
pub fn new(adc: ADC, clk: Clk, rcc: &mut RCC) -> Self
Create a new ADC driver from a ADC peripheral.
This will enable the ADC clock and reset the ADC peripheral.
Note: This will select the clock source, but you are responsible for enabling that clock source.
Example
Initialize the ADC with HSI16.
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
Initialize the ADC with PCLK/4.
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
sourcepub const unsafe fn new_no_init(adc: ADC) -> Self
pub const unsafe fn new_no_init(adc: ADC) -> Self
Create a new ADC driver from an ADC peripheral without initialization.
This is a slightly safer version of steal
.
Safety
- Reset the ADC peripheral if determinism is required.
- Enable the ADC peripheral clock before using the ADC.
- Select the clock source if a non-default clock is required.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
// safety: nothing is using the peripheral
unsafe { Adc::pulse_reset(&mut dp.RCC) };
Adc::enable_clock(&mut dp.RCC);
// safety: ADC peripheral has been reset and clocks are enabled
let mut adc: Adc = unsafe { Adc::new_no_init(dp.ADC) };
// select the ADC clock, optional
adc.set_clock_source(adc::Clk::PClkDiv4, &mut dp.RCC);
sourcepub fn free(self) -> ADC
pub fn free(self) -> ADC
Free the ADC peripheral from the driver.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
// ... use ADC
let adc: pac::ADC = adc.free();
sourcepub unsafe fn steal() -> Adc
pub unsafe fn steal() -> Adc
Steal the ADC peripheral from whatever is currently using it.
This will not initialize the ADC (unlike new
).
Safety
- Ensure that the code stealing the ADC has exclusive access to the peripheral. Singleton checks are bypassed with this method.
- Reset the ADC peripheral if determinism is required.
- Enable the ADC peripheral clock before using the ADC.
- Select the clock source if a non-default clock is required.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let _: pac::ADC = dp.ADC;
unsafe { Adc::pulse_reset(&mut dp.RCC) };
Adc::enable_clock(&mut dp.RCC);
let mut adc: Adc = unsafe { Adc::steal() };
// select the ADC clock, optional
adc.set_clock_source(adc::Clk::PClkDiv4, &mut dp.RCC);
sourcepub fn set_clock_source(&mut self, clk: Clk, rcc: &mut RCC)
pub fn set_clock_source(&mut self, clk: Clk, rcc: &mut RCC)
Set the ADC clock source.
Panics
- (debug) ADC is enabled
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc: Adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
// change the clock source
adc.disable();
adc.set_clock_source(adc::Clk::PClkDiv4, &mut dp.RCC);
sourcepub fn clock_source(&self, rcc: &RCC) -> Option<Clk>
pub fn clock_source(&self, rcc: &RCC) -> Option<Clk>
Get the ADC clock source.
Returns None
if the ADC is configured for an asynchronous clock,
but no asynchronous clock is selected.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc: Adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
assert_eq!(adc.clock_source(&dp.RCC), Some(adc::Clk::PClkDiv4));
sourcepub unsafe fn disable_clock(rcc: &mut RCC)
pub unsafe fn disable_clock(rcc: &mut RCC)
Disable the ADC clock.
Safety
- Ensure nothing is using the ADC before disabling the clock.
- You are responsible for re-enabling the clock before using the ADC.
sourcepub fn enable_clock(rcc: &mut RCC)
pub fn enable_clock(rcc: &mut RCC)
Enable the ADC clock.
new
will enable clocks for you.
sourcepub unsafe fn pulse_reset(rcc: &mut RCC)
pub unsafe fn pulse_reset(rcc: &mut RCC)
sourcepub fn clock_hz(&self, rcc: &RCC) -> u32
pub fn clock_hz(&self, rcc: &RCC) -> u32
Calculate the ADC clock frequency in hertz.
Note: If the ADC prescaler register erroneously returns a reserved value the code will default to an ADC prescaler of 1.
Fractional frequencies will be rounded towards zero.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let adc: Adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
assert_eq!(adc.clock_hz(&dp.RCC), 16_000_000);
sourcepub unsafe fn unmask_irq()
Available on crate feature rt
only.
pub unsafe fn unmask_irq()
rt
only.sourcepub fn set_sample_times(&mut self, mask: u32, sel0: Ts, sel1: Ts)
pub fn set_sample_times(&mut self, mask: u32, sel0: Ts, sel1: Ts)
Set sample times for all channels.
For each bit in the mask:
0
: Sample time is set by thesel0
argument.1
: Sample time is set by thesel1
argument.
Panics
- (debug) An ADC conversion is in-progress
Example
Set ADC channels In0
and In1
(pins B13
and B14
respectively) and the internal VBAT to a sample time of
39.5 ADC clock cycles, and set all other channels to a sample time of
160.5 clock cycles.
use stm32wlxx_hal::{
self as hal,
adc::{self, Adc, Ts},
gpio::pins::{B13, B14},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.set_sample_times(
B14::ADC_CH.mask() | B13::ADC_CH.mask() | adc::Ch::Vbat.mask(),
Ts::Cyc160,
Ts::Cyc39,
);
sourcepub fn set_max_sample_time(&mut self)
pub fn set_max_sample_time(&mut self)
Sets all channels to the maximum sample time.
This is a helper for testing and rapid prototyping purpose because
set_sample_times
is verbose.
This method is equivalent to this:
use stm32wlxx_hal::adc::Ts;
adc.set_sample_times(0, Ts::Cyc160, Ts::Cyc160);
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.set_max_sample_time();
sourcepub fn set_isr(&mut self, isr: u32)
pub fn set_isr(&mut self, isr: u32)
Clear interrupts.
Example
Clear all interrupts.
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.set_isr(adc::irq::ALL);
sourcepub fn isr() -> R
pub fn isr() -> R
Read the interrupt status.
Example
Check if the ADC is ready.
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
// this will be false because the ADC is not enabled
let ready: bool = Adc::isr().adrdy().is_ready();
sourcepub fn set_ier(&mut self, ier: u32)
pub fn set_ier(&mut self, ier: u32)
Enable and disable interrupts.
Example
Enable all IRQs
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.set_ier(adc::irq::ALL);
sourcepub fn start_chsel(&mut self, ch: u32)
pub fn start_chsel(&mut self, ch: u32)
Configure the channel sequencer.
This is advanced ADC usage, most of the time you will want to use a one of the available sample methods that will configure this.
This will not poll for completion, when this method returns the channel configuration may not be ready.
Panics
- (debug) ADC conversion is in-progress.
Example
Select the ADC VBAT channel.
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.start_chsel(adc::Ch::Vbat.mask());
while Adc::isr().ccrdy().is_not_complete() {}
sourcepub fn start_conversion(&mut self)
pub fn start_conversion(&mut self)
Start an ADC conversion.
This is advanced ADC usage, most of the time you will want to use a one of the available sample methods that will configure this.
This will not poll for completion, when this method returns the AD conversion may not be complete.
Panics
- (debug) ADC is not enabled
- (debug) ADC has a pending disable request
Example
See data
.
sourcepub fn stop_conversion(&mut self)
pub fn stop_conversion(&mut self)
Stop an ADC conversion if there is one in-progress.
sourcepub fn data(&self) -> u16
pub fn data(&self) -> u16
Read the ADC conversion data.
This is advanced ADC usage, most of the time you will want to use a one of the available sample methods.
Example
Read the ADC VBAT channel.
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
// calibrate the ADC before it is enabled
adc.calibrate(&mut delay);
// enable the ADC
adc.enable();
// set the sample times to the maximum (160.5 ADC cycles)
adc.set_max_sample_time();
// select the Vbat channel and poll for completion
adc.start_chsel(adc::Ch::Vbat.mask());
while Adc::isr().ccrdy().is_not_complete() {}
// start the conversion and poll for completion
adc.start_conversion();
while Adc::isr().eoc().is_not_complete() {}
// read the ADC data
let vbat: u16 = adc.data();
sourcepub fn enable_tsen(&mut self)
pub fn enable_tsen(&mut self)
Enable the temperature sensor.
You MUST wait for the temperature sensor to start up
(TS_START_TYP
or TS_START_MAX
)
before the samples will be accurate.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.enable_tsen();
// wait for the temperature sensor to startup
delay.delay_us(adc::TS_START_MAX.as_micros() as u32);
sourcepub fn disable_tsen(&mut self)
pub fn disable_tsen(&mut self)
Disable the temperature sensor.
sourcepub fn is_tsen_enabled(&mut self) -> bool
pub fn is_tsen_enabled(&mut self) -> bool
Returns true
if the temperature sensor is enabled.
sourcepub fn temperature(&mut self) -> Ratio<i16>
pub fn temperature(&mut self) -> Ratio<i16>
Get the junction temperature.
Panics
- (debug) ADC is not enabled
- (debug) ADC has a pending disable request
- (debug) Temperature sensor is not enabled
Sample Time
You must set a sampling time with
set_sample_times
greater than or equal to
TS_MIN_SAMPLE
before calling this method.
When in doubt use the maximum sampling time, Ts::Cyc160
.
Calibration
The temperature calibration provided on-chip appears to be for an uncalibrated ADC, though I can find no mention of this in the datasheet.
If the ADC has been calibrated with calibrate
the calibration offset
will be removed from the sample.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.enable();
adc.enable_tsen();
delay.delay_us(adc::TS_START_MAX.as_micros() as u32);
adc.set_max_sample_time();
let tj: i16 = adc.temperature().to_integer();
sourcepub fn enable_vref(&mut self)
pub fn enable_vref(&mut self)
Enable the internal voltage reference.
sourcepub fn disable_vref(&mut self)
pub fn disable_vref(&mut self)
Disable the internal voltage reference.
sourcepub fn is_vref_enabled(&mut self) -> bool
pub fn is_vref_enabled(&mut self) -> bool
Returns true
if the internal voltage reference is enabled.
sourcepub fn enable_oversampling(
&mut self,
ratio: OversampleRatio,
shift: OversampleShift
)
pub fn enable_oversampling( &mut self, ratio: OversampleRatio, shift: OversampleShift )
sourcepub fn disable_oversampling(&mut self)
pub fn disable_oversampling(&mut self)
sourcepub fn is_oversampling_enabled(&mut self) -> bool
pub fn is_oversampling_enabled(&mut self) -> bool
Returns true
if oversampling is enabled.
sourcepub fn vref(&mut self) -> u16
pub fn vref(&mut self) -> u16
Read the internal voltage reference.
Panics
- (debug) ADC is not enabled
- (debug) ADC has a pending disable request
- (debug) Voltage reference is not enabled
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.calibrate(&mut delay);
adc.set_max_sample_time();
adc.enable();
adc.enable_vref();
let vref: u16 = adc.vref();
let vref_cal: u16 = adc::vref_cal();
let error: i16 = ((vref as i16) - (vref_cal as i16)).abs();
assert!(error < 10);
sourcepub fn dac(&mut self) -> u16
pub fn dac(&mut self) -> u16
Sample the DAC output.
The DAC must be configured to output to chip peripherals for this to work as expected.
Panics
- (debug) ADC is not enabled
- (debug) ADC has a pending disable request
Example
use stm32wlxx_hal::{
adc::{self, Adc},
dac::{Dac, ModeChip},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.calibrate(&mut delay);
adc.set_max_sample_time();
let mut dac: Dac = Dac::new(dp.DAC, &mut dp.RCC);
dac.set_mode_chip(ModeChip::Norm);
dac.setup_soft_trigger();
dac.soft_trigger(1234);
// should be in the same ballpark as the DAC output
let sample: u16 = adc.dac();
sourcepub fn pin<P: AdcCh>(&mut self, pin: &Analog<P>) -> u16
pub fn pin<P: AdcCh>(&mut self, pin: &Analog<P>) -> u16
Sample a GPIO pin.
Panics
- (debug) ADC is not enabled
- (debug) ADC has a pending disable request
Example
use stm32wlxx_hal::{
adc::{self, Adc},
gpio::{pins::B4, Analog, PortB},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.calibrate(&mut delay);
adc.set_max_sample_time();
adc.enable();
let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
let b4: Analog<B4> = cortex_m::interrupt::free(|cs| Analog::new(gpiob.b4, cs));
let sample: u16 = adc.pin(&b4);
sourcepub fn enable_vbat(&mut self)
pub fn enable_vbat(&mut self)
Enable VBAT.
To prevent any unwanted consumption on the battery, it is recommended to enable the bridge divider only when needed for ADC conversion.
sourcepub fn disable_vbat(&mut self)
pub fn disable_vbat(&mut self)
Disable VBAT.
sourcepub fn is_vbat_enabled(&self) -> bool
pub fn is_vbat_enabled(&self) -> bool
Returns true
if VBAT is enabled.
sourcepub fn vbat(&mut self) -> u16
pub fn vbat(&mut self) -> u16
Sample the VBAT pin.
This is internally connected to a bridge divider, the converted digital value is a third the VBAT voltage.
Panics
- (debug) ADC is not enabled
- (debug) ADC has a pending disable request
- (debug) VBAT is not enabled
Example
use stm32wlxx_hal::{
self as hal,
adc::{self, Adc},
dac::{Dac, ModeChip},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.calibrate(&mut delay);
adc.enable();
adc.enable_vbat();
adc.set_max_sample_time();
let sample: u16 = adc.vbat();
source§impl Adc
impl Adc
sourcepub fn is_enabled(&self) -> bool
pub fn is_enabled(&self) -> bool
Returns true
if the ADC is enabled.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
assert_eq!(adc.is_enabled(), false);
sourcepub fn disable_in_progress(&self) -> bool
pub fn disable_in_progress(&self) -> bool
Returns true
if an ADC disable command is in-progress.
sourcepub fn is_disabled(&self) -> bool
pub fn is_disabled(&self) -> bool
Returns true
if the ADC is disabled, and there is no disable command
in-progress.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
assert_eq!(adc.is_disabled(), true);
sourcepub fn start_enable(&mut self) -> bool
pub fn start_enable(&mut self) -> bool
Start the ADC enable procedure.
This is advanced ADC usage, most of the time you will want to use
enable
.
This will not poll for completion, when this method returns the ADC may not be enabled.
The method returns true
if the caller function should poll for
completion (the ADC was not already enabled),
if the ADC was already enabled and the ADRDY interrupt was cleared then
the ADRDY bit will not be set again after calling this method
which can lead to polling loops that will never terminate.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
if adc.start_enable() {
while Adc::isr().adrdy().is_not_ready() {}
}
sourcepub fn enable(&mut self)
pub fn enable(&mut self)
Enable the ADC and poll for completion.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.enable();
sourcepub fn start_disable(&mut self)
pub fn start_disable(&mut self)
Start the ADC disable procedure.
This is advanced ADC usage, most of the time you will want to use
disable
.
This will not poll for completion, when this function returns the ADC may not be disabled.
This will stop any conversions in-progress.
The ADC takes about 20 CPU cycles to disable with a 48MHz sysclk and the ADC on the 16MHz HSI clock.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.enable();
// ... use ADC
adc.start_disable();
while !adc.is_disabled() {}
sourcepub fn disable(&mut self)
pub fn disable(&mut self)
Disable the ADC and poll for completion.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let mut adc = Adc::new(dp.ADC, adc::Clk::PClkDiv4, &mut dp.RCC);
adc.enable();
// ... use ADC
adc.disable();
source§impl Adc
impl Adc
sourcepub fn calibrate<D: DelayUs<u8>>(&mut self, delay: &mut D)
pub fn calibrate<D: DelayUs<u8>>(&mut self, delay: &mut D)
Calibrate the ADC for additional accuracy.
Calibration should be performed before starting A/D conversion. It removes the offset error which may vary from chip to chip due to process variation.
The calibration factor is lost in the following cases:
- The power supply is removed from the ADC (for example when entering STANDBY or VBAT mode)
- The ADC peripheral is reset.
This will disable the ADC if it is not already disabled.
This function is the simple way to calibrate the ADC, you can use these methods to achieve the same results if you desire finer controls:
enable_vreg
- A delay function
start_calibrate
set_ier
(optional)Adc::isr
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.calibrate(&mut delay);
sourcepub fn enable_vreg(&mut self)
pub fn enable_vreg(&mut self)
Enable the ADC voltage regulator for calibration.
This is advanced ADC usage, most of the time you will want to use
calibrate
.
This will disable the ADC and DMA request generation if not already disabled.
You MUST wait T_ADCVREG_SETUP
before the voltage regulator
output is available. This delay is not performed for you.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.enable_vreg();
delay.delay_us(u32::from(adc::T_ADCVREG_SETUP_MICROS));
sourcepub fn disable_vreg(&mut self)
pub fn disable_vreg(&mut self)
sourcepub fn start_calibrate(&mut self)
pub fn start_calibrate(&mut self)
Start the ADC calibration.
This is advanced ADC usage, most of the time you will want to use
calibrate
.
When this function returns the ADC calibration has started, but
may not have finished.
Check if the ADC calibration has finished with Adc::isr
.
Panics
- (debug) ADC is enabled.
- (debug) ADC voltage regulator is not enabled.
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.enable_vreg();
delay.delay_us(u32::from(adc::T_ADCVREG_SETUP_MICROS));
adc.start_calibrate();
// datasheet says this takes 82 ADC clock cycles
// my measurements are closer to 120 ADC clock cycles
while Adc::isr().eocal().is_not_complete() {}
sourcepub fn force_cal(&mut self, calfact: u8)
pub fn force_cal(&mut self, calfact: u8)
Force the ADC calibration.
The calibration factor is lost each time power is removed from the ADC (for example when entering standby or VBAT mode) It is possible to save and restore the calibration factor with firmware to save time when re-starting the ADC (as long as temperature and voltage are stable during the ADC power-down).
Panics
- (debug) ADC is not enabled
- (debug) ADC conversion is in-progress
Example
use stm32wlxx_hal::{
adc::{self, Adc},
pac, rcc,
util::new_delay,
};
let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
let cp: pac::CorePeripherals = pac::CorePeripherals::take().unwrap();
// enable the HSI16 source clock
dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
while dp.RCC.cr.read().hsirdy().is_not_ready() {}
let mut delay = new_delay(cp.SYST, &dp.RCC);
let mut adc = Adc::new(dp.ADC, adc::Clk::RccHsi, &mut dp.RCC);
adc.calibrate(&mut delay);
// save the calibration factor
let calfact: u8 = adc.calfact();
// restore the calibration
adc.enable(); // ADC must be enabled to restore the calibration
adc.force_cal(calfact);