Struct stm32f4xx_hal::adc::Adc [−][src]
pub struct Adc<ADC> { /* fields omitted */ }
Expand description
Analog to Digital Converter
Status
Most options relating to regular conversions are implemented. One-shot and sequences of conversions have been tested and work as expected.
GPIO to channel mapping should be correct for all supported F4 devices. The mappings were taken from CubeMX. The mappings are feature gated per 4xx device but there are actually sub variants for some devices and some pins may be missing on some variants. The implementation has been split up and commented to show which pins are available on certain device variants but currently the library doesn’t enforce this. To fully support the right pins would require 10+ more features for the various variants.
Todo
- Injected conversions
- Analog watchdog config
- Discontinuous mode
Examples
One-shot conversion
use stm32f4xx_hal::{
gpio::gpioa,
adc::{
Adc,
config::AdcConfig,
config::SampleTime,
},
};
let mut adc = Adc::adc1(device.ADC1, true, AdcConfig::default());
let pa3 = gpioa.pa3.into_analog();
let sample = adc.convert(&pa3, SampleTime::Cycles_480);
let millivolts = adc.sample_to_millivolts(sample);
info!("pa3: {}mV", millivolts);
Sequence conversion
use stm32f4xx_hal::{
gpio::gpioa,
adc::{
Adc,
config::AdcConfig,
config::SampleTime,
config::Sequence,
config::Eoc,
config::Scan,
config::Clock,
},
};
let config = AdcConfig::default()
//We'll either need DMA or an interrupt per conversion to convert
//multiple values in a sequence
.end_of_conversion_interrupt(Eoc::Conversion)
//Scan mode is also required to convert a sequence
.scan(Scan::Enabled)
//And since we're looking for one interrupt per conversion the
//clock will need to be fairly slow to avoid overruns breaking
//the sequence. If you are running in debug mode and logging in
//the interrupt, good luck... try setting pclk2 really low.
//(Better yet use DMA)
.clock(Clock::Pclk2_div_8);
let mut adc = Adc::adc1(device.ADC1, true, config);
let pa0 = gpioa.pa0.into_analog();
let pa3 = gpioa.pa3.into_analog();
adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_112);
adc.configure_channel(&pa3, Sequence::Two, SampleTime::Cycles_480);
adc.configure_channel(&pa0, Sequence::Three, SampleTime::Cycles_112);
adc.start_conversion();
External trigger
A common mistake on STM forums is enabling continuous mode but that causes it to start capturing on the first trigger and capture as fast as possible forever, regardless of future triggers. Continuous mode is disabled by default but I thought it was worth highlighting.
Getting the timer config right to make sure it’s sending the event the ADC is listening to can be a bit of a pain but the key fields are highlighted below. Try hooking a timer channel up to an external pin with an LED or oscilloscope attached to check it’s really generating pulses if the ADC doesn’t seem to be triggering.
use stm32f4xx_hal::{
gpio::gpioa,
adc::{
Adc,
config::AdcConfig,
config::SampleTime,
config::Sequence,
config::Eoc,
config::Scan,
config::Clock,
},
};
let config = AdcConfig::default()
//Set the trigger you want
.external_trigger(TriggerMode::RisingEdge, ExternalTrigger::Tim_1_cc_1);
let mut adc = Adc::adc1(device.ADC1, true, config);
let pa0 = gpioa.pa0.into_analog();
adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_112);
//Make sure it's enabled but don't start the conversion
adc.enable();
//Configure the timer
let mut tim = Timer::tim1(device.TIM1, 1.hz(), clocks);
unsafe {
let tim = &(*TIM1::ptr());
//Channel 1
//Disable the channel before configuring it
tim.ccer.modify(|_, w| w.cc1e().clear_bit());
tim.ccmr1_output().modify(|_, w| w
//Preload enable for channel
.oc1pe().set_bit()
//Set mode for channel, the default mode is "frozen" which won't work
.oc1m().pwm_mode1()
);
//Set the duty cycle, 0 won't work in pwm mode but might be ok in
//toggle mode or match mode
let max_duty = tim.arr.read().arr().bits() as u16;
tim.ccr1.modify(|_, w| w.ccr().bits(max_duty / 2));
//Enable the channel
tim.ccer.modify(|_, w| w.cc1e().set_bit());
//Enable the TIM main Output
tim.bdtr.modify(|_, w| w.moe().set_bit());
}
Implementations
Calculates the system VDDA by sampling the internal VREF channel and comparing the result with the value stored at the factory.
Enables the vbat internal channel
Enables the vbat internal channel
Enables the temp and vref internal channels. They can’t work while vbat is also enabled so this method also disables vbat.
Disables the temp and vref internal channels
Returns if the temp and vref internal channels are enabled
Enables the ADC clock, resets the peripheral (optionally), runs calibration and applies the supplied config
Arguments
reset
- should a reset be performed. This is provided because on some devices multiple ADCs share the same common reset
Applies all fields in AdcConfig
Returns if the adc is enabled
Disables the adc
Note
The ADC in the f4 has few restrictions on what can be configured while the ADC is enabled. If any bugs are found where some settings aren’t “sticking” try disabling the ADC before changing them. The reference manual for the chip I’m using only states that the sequence registers are locked when they are being converted.
Starts conversion sequence. Waits for the hardware to indicate it’s actually started.
Sets the sampling resolution
Sets which external trigger to use and if it is disabled, rising, falling or both
Enables and disables continuous mode
Sets if the end-of-conversion behaviour. The end-of-conversion interrupt occur either per conversion or for the whole sequence.
Resets the end-of-conversion flag
Sets the default sample time that is used for one-shot conversions.
configure_channel and start_conversion can be
used for configurations where different sampling times are required per channel.
Returns the current sequence length. Primarily useful for configuring DMA.
Reset the sequence
Returns the address of the ADC data register. Primarily useful for configuring DMA.
pub fn configure_channel<CHANNEL>(
&mut self,
_channel: &CHANNEL,
sequence: Sequence,
sample_time: SampleTime
) where
CHANNEL: Channel<ADC1, ID = u8>,
pub fn configure_channel<CHANNEL>(
&mut self,
_channel: &CHANNEL,
sequence: Sequence,
sample_time: SampleTime
) where
CHANNEL: Channel<ADC1, ID = u8>,
Configure a channel for sampling.
It will make sure the sequence is at least as long as the sequence
provided.
Arguments
channel
- channel to configuresequence
- where in the sequence to sample the channel. Also called rank in some STM docs/codesample_time
- how long to sample for. See datasheet and ref manual to work out how long you need
to sample for at a given ADC clock frequency
Returns the current sample stored in the ADC data register
Converts a sample value to millivolts using calibrated VDDA and configured resolution
Block until the conversion is completed
Panics
Will panic if there is no conversion started and the end-of-conversion bit is not set
Enables the ADC clock, resets the peripheral (optionally), runs calibration and applies the supplied config
Arguments
reset
- should a reset be performed. This is provided because on some devices multiple ADCs share the same common reset
Applies all fields in AdcConfig
Returns if the adc is enabled
Disables the adc
Note
The ADC in the f4 has few restrictions on what can be configured while the ADC is enabled. If any bugs are found where some settings aren’t “sticking” try disabling the ADC before changing them. The reference manual for the chip I’m using only states that the sequence registers are locked when they are being converted.
Starts conversion sequence. Waits for the hardware to indicate it’s actually started.
Sets the sampling resolution
Sets which external trigger to use and if it is disabled, rising, falling or both
Enables and disables continuous mode
Sets if the end-of-conversion behaviour. The end-of-conversion interrupt occur either per conversion or for the whole sequence.
Resets the end-of-conversion flag
Sets the default sample time that is used for one-shot conversions.
configure_channel and start_conversion can be
used for configurations where different sampling times are required per channel.
Returns the current sequence length. Primarily useful for configuring DMA.
Reset the sequence
Returns the address of the ADC data register. Primarily useful for configuring DMA.
pub fn configure_channel<CHANNEL>(
&mut self,
_channel: &CHANNEL,
sequence: Sequence,
sample_time: SampleTime
) where
CHANNEL: Channel<ADC2, ID = u8>,
pub fn configure_channel<CHANNEL>(
&mut self,
_channel: &CHANNEL,
sequence: Sequence,
sample_time: SampleTime
) where
CHANNEL: Channel<ADC2, ID = u8>,
Configure a channel for sampling.
It will make sure the sequence is at least as long as the sequence
provided.
Arguments
channel
- channel to configuresequence
- where in the sequence to sample the channel. Also called rank in some STM docs/codesample_time
- how long to sample for. See datasheet and ref manual to work out how long you need
to sample for at a given ADC clock frequency
Returns the current sample stored in the ADC data register
Converts a sample value to millivolts using calibrated VDDA and configured resolution
Block until the conversion is completed
Panics
Will panic if there is no conversion started and the end-of-conversion bit is not set
Enables the ADC clock, resets the peripheral (optionally), runs calibration and applies the supplied config
Arguments
reset
- should a reset be performed. This is provided because on some devices multiple ADCs share the same common reset
Applies all fields in AdcConfig
Returns if the adc is enabled
Disables the adc
Note
The ADC in the f4 has few restrictions on what can be configured while the ADC is enabled. If any bugs are found where some settings aren’t “sticking” try disabling the ADC before changing them. The reference manual for the chip I’m using only states that the sequence registers are locked when they are being converted.
Starts conversion sequence. Waits for the hardware to indicate it’s actually started.
Sets the sampling resolution
Sets which external trigger to use and if it is disabled, rising, falling or both
Enables and disables continuous mode
Sets if the end-of-conversion behaviour. The end-of-conversion interrupt occur either per conversion or for the whole sequence.
Resets the end-of-conversion flag
Sets the default sample time that is used for one-shot conversions.
configure_channel and start_conversion can be
used for configurations where different sampling times are required per channel.
Returns the current sequence length. Primarily useful for configuring DMA.
Reset the sequence
Returns the address of the ADC data register. Primarily useful for configuring DMA.
pub fn configure_channel<CHANNEL>(
&mut self,
_channel: &CHANNEL,
sequence: Sequence,
sample_time: SampleTime
) where
CHANNEL: Channel<ADC3, ID = u8>,
pub fn configure_channel<CHANNEL>(
&mut self,
_channel: &CHANNEL,
sequence: Sequence,
sample_time: SampleTime
) where
CHANNEL: Channel<ADC3, ID = u8>,
Configure a channel for sampling.
It will make sure the sequence is at least as long as the sequence
provided.
Arguments
channel
- channel to configuresequence
- where in the sequence to sample the channel. Also called rank in some STM docs/codesample_time
- how long to sample for. See datasheet and ref manual to work out how long you need
to sample for at a given ADC clock frequency
Returns the current sample stored in the ADC data register
Converts a sample value to millivolts using calibrated VDDA and configured resolution
Block until the conversion is completed
Panics
Will panic if there is no conversion started and the end-of-conversion bit is not set