Struct Adc

Source
pub struct Adc<ADC> { /* private fields */ }
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 stm32f7x7_hal::{
  gpio::gpioa,
  adc::{
    Adc,
    config::AdcConfig,
    config::SampleTime,
  },
};

fn main() {
    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 stm32f7x7_hal::{
  gpio::gpioa,
  adc::{
    Adc,
    config::AdcConfig,
    config::SampleTime,
    config::Sequence,
    config::Eoc,
    config::Scan,
    config::Clock,
  },
};

fn main() {
    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 stm32f7x7_hal::{
  gpio::gpioa,
  adc::{
    Adc,
    config::AdcConfig,
    config::SampleTime,
    config::Sequence,
    config::Eoc,
    config::Scan,
    config::Clock,
  },
};

fn main() {
    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());

       //This is pwm mode 1, the default mode is "frozen" which won't work
       let mode = 0b0110;

       //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
         .oc1m().bits(mode)
       );

       //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.ccr1().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§

Source§

impl Adc<ADC1>

Source

pub fn adc1(adc: ADC1, reset: bool, config: AdcConfig) -> Adc<ADC1>

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
Source

pub fn apply_config(&mut self, config: AdcConfig)

Applies all fields in AdcConfig

Source

pub fn calibrate(&mut self)

Calculates the system VDDA by sampling the internal VREF channel and comparing the result with the value stored at the factory.

Source

pub fn enable_vbat(&self)

Enables the vbat internal channel

Source

pub fn disable_vbat(&self)

Enables the vbat internal channel

Source

pub fn enable_temperature_and_vref(&mut self)

Enables the temp and vref internal channels. They can’t work while vbat is also enabled so this method also disables vbat.

Source

pub fn disable_temperature_and_vref(&mut self)

Disables the temp and vref internal channels

Source

pub fn temperature_and_vref_enabled(&mut self) -> bool

Returns if the temp and vref internal channels are enabled

Source

pub fn is_enabled(&self) -> bool

Returns if the adc is enabled

Source

pub fn enable(&mut self)

Enables the adc

Source

pub fn disable(&mut self)

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.

Source

pub fn start_conversion(&mut self)

Starts conversion sequence. Waits for the hardware to indicate it’s actually started.

Source

pub fn set_clock(&mut self, clock: Clock)

Sets the clock for the adc

Source

pub fn set_resolution(&mut self, resolution: Resolution)

Sets the sampling resolution

Source

pub fn set_align(&mut self, align: Align)

Sets the DR register alignment to left or right

Source

pub fn set_scan(&mut self, scan: Scan)

Enables and disables scan mode

Source

pub fn set_external_trigger( &mut self, (edge, extsel): (TriggerMode, ExternalTrigger), )

Sets which external trigger to use and if it is disabled, rising, falling or both

Source

pub fn set_continuous(&mut self, continuous: Continuous)

Enables and disables continuous mode

Source

pub fn set_dma(&mut self, dma: Dma)

Sets DMA to disabled, single or continuous

Source

pub fn set_end_of_conversion_interrupt(&mut self, eoc: Eoc)

Sets if the end-of-conversion behaviour. The end-of-conversion interrupt occur either per conversion or for the whole sequence.

Source

pub fn clear_end_of_conversion_flag(&mut self)

Resets the end-of-conversion flag

Source

pub fn set_default_sample_time(&mut self, sample_time: SampleTime)

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.

Source

pub fn sequence_length(&mut self) -> u8

Returns the current sequence length. Primarily useful for configuring DMA.

Source

pub fn reset_sequence(&mut self)

Reset the sequence

Source

pub fn data_register_address(&mut self) -> u32

Returns the address of the ADC data register. Primarily useful for configuring DMA.

Source

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 configure
  • sequence - where in the sequence to sample the channel. Also called rank in some STM docs/code
  • sample_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
Source

pub fn current_sample(&self) -> u16

Returns the current sample stored in the ADC data register

Source

pub fn sample_to_millivolts(&self, sample: u16) -> u16

Converts a sample value to millivolts using calibrated VDDA and configured resolution

Source

pub fn wait_for_conversion_sequence(&self)

Block until the conversion is completed

§Panics

Will panic if there is no conversion started and the end-of-conversion bit is not set

Source

pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: SampleTime) -> u16
where PIN: Channel<ADC1, ID = u8>,

Synchronously convert a single sample Note that it reconfigures the adc sequence and doesn’t restore it

Source§

impl Adc<ADC2>

Source

pub fn adc2(adc: ADC2, reset: bool, config: AdcConfig) -> Adc<ADC2>

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
Source

pub fn apply_config(&mut self, config: AdcConfig)

Applies all fields in AdcConfig

Source

pub fn calibrate(&mut self)

Calculates the system VDDA by sampling the internal VREF channel and comparing the result with the value stored at the factory.

Source

pub fn enable_vbat(&self)

Enables the vbat internal channel

Source

pub fn disable_vbat(&self)

Enables the vbat internal channel

Source

pub fn enable_temperature_and_vref(&mut self)

Enables the temp and vref internal channels. They can’t work while vbat is also enabled so this method also disables vbat.

Source

pub fn disable_temperature_and_vref(&mut self)

Disables the temp and vref internal channels

Source

pub fn temperature_and_vref_enabled(&mut self) -> bool

Returns if the temp and vref internal channels are enabled

Source

pub fn is_enabled(&self) -> bool

Returns if the adc is enabled

Source

pub fn enable(&mut self)

Enables the adc

Source

pub fn disable(&mut self)

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.

Source

pub fn start_conversion(&mut self)

Starts conversion sequence. Waits for the hardware to indicate it’s actually started.

Source

pub fn set_clock(&mut self, clock: Clock)

Sets the clock for the adc

Source

pub fn set_resolution(&mut self, resolution: Resolution)

Sets the sampling resolution

Source

pub fn set_align(&mut self, align: Align)

Sets the DR register alignment to left or right

Source

pub fn set_scan(&mut self, scan: Scan)

Enables and disables scan mode

Source

pub fn set_external_trigger( &mut self, (edge, extsel): (TriggerMode, ExternalTrigger), )

Sets which external trigger to use and if it is disabled, rising, falling or both

Source

pub fn set_continuous(&mut self, continuous: Continuous)

Enables and disables continuous mode

Source

pub fn set_dma(&mut self, dma: Dma)

Sets DMA to disabled, single or continuous

Source

pub fn set_end_of_conversion_interrupt(&mut self, eoc: Eoc)

Sets if the end-of-conversion behaviour. The end-of-conversion interrupt occur either per conversion or for the whole sequence.

Source

pub fn clear_end_of_conversion_flag(&mut self)

Resets the end-of-conversion flag

Source

pub fn set_default_sample_time(&mut self, sample_time: SampleTime)

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.

Source

pub fn sequence_length(&mut self) -> u8

Returns the current sequence length. Primarily useful for configuring DMA.

Source

pub fn reset_sequence(&mut self)

Reset the sequence

Source

pub fn data_register_address(&mut self) -> u32

Returns the address of the ADC data register. Primarily useful for configuring DMA.

Source

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 configure
  • sequence - where in the sequence to sample the channel. Also called rank in some STM docs/code
  • sample_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
Source

pub fn current_sample(&self) -> u16

Returns the current sample stored in the ADC data register

Source

pub fn sample_to_millivolts(&self, sample: u16) -> u16

Converts a sample value to millivolts using calibrated VDDA and configured resolution

Source

pub fn wait_for_conversion_sequence(&self)

Block until the conversion is completed

§Panics

Will panic if there is no conversion started and the end-of-conversion bit is not set

Source

pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: SampleTime) -> u16
where PIN: Channel<ADC2, ID = u8>,

Synchronously convert a single sample Note that it reconfigures the adc sequence and doesn’t restore it

Source§

impl Adc<ADC3>

Source

pub fn adc3(adc: ADC3, reset: bool, config: AdcConfig) -> Adc<ADC3>

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
Source

pub fn apply_config(&mut self, config: AdcConfig)

Applies all fields in AdcConfig

Source

pub fn calibrate(&mut self)

Calculates the system VDDA by sampling the internal VREF channel and comparing the result with the value stored at the factory.

Source

pub fn enable_vbat(&self)

Enables the vbat internal channel

Source

pub fn disable_vbat(&self)

Enables the vbat internal channel

Source

pub fn enable_temperature_and_vref(&mut self)

Enables the temp and vref internal channels. They can’t work while vbat is also enabled so this method also disables vbat.

Source

pub fn disable_temperature_and_vref(&mut self)

Disables the temp and vref internal channels

Source

pub fn temperature_and_vref_enabled(&mut self) -> bool

Returns if the temp and vref internal channels are enabled

Source

pub fn is_enabled(&self) -> bool

Returns if the adc is enabled

Source

pub fn enable(&mut self)

Enables the adc

Source

pub fn disable(&mut self)

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.

Source

pub fn start_conversion(&mut self)

Starts conversion sequence. Waits for the hardware to indicate it’s actually started.

Source

pub fn set_clock(&mut self, clock: Clock)

Sets the clock for the adc

Source

pub fn set_resolution(&mut self, resolution: Resolution)

Sets the sampling resolution

Source

pub fn set_align(&mut self, align: Align)

Sets the DR register alignment to left or right

Source

pub fn set_scan(&mut self, scan: Scan)

Enables and disables scan mode

Source

pub fn set_external_trigger( &mut self, (edge, extsel): (TriggerMode, ExternalTrigger), )

Sets which external trigger to use and if it is disabled, rising, falling or both

Source

pub fn set_continuous(&mut self, continuous: Continuous)

Enables and disables continuous mode

Source

pub fn set_dma(&mut self, dma: Dma)

Sets DMA to disabled, single or continuous

Source

pub fn set_end_of_conversion_interrupt(&mut self, eoc: Eoc)

Sets if the end-of-conversion behaviour. The end-of-conversion interrupt occur either per conversion or for the whole sequence.

Source

pub fn clear_end_of_conversion_flag(&mut self)

Resets the end-of-conversion flag

Source

pub fn set_default_sample_time(&mut self, sample_time: SampleTime)

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.

Source

pub fn sequence_length(&mut self) -> u8

Returns the current sequence length. Primarily useful for configuring DMA.

Source

pub fn reset_sequence(&mut self)

Reset the sequence

Source

pub fn data_register_address(&mut self) -> u32

Returns the address of the ADC data register. Primarily useful for configuring DMA.

Source

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 configure
  • sequence - where in the sequence to sample the channel. Also called rank in some STM docs/code
  • sample_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
Source

pub fn current_sample(&self) -> u16

Returns the current sample stored in the ADC data register

Source

pub fn sample_to_millivolts(&self, sample: u16) -> u16

Converts a sample value to millivolts using calibrated VDDA and configured resolution

Source

pub fn wait_for_conversion_sequence(&self)

Block until the conversion is completed

§Panics

Will panic if there is no conversion started and the end-of-conversion bit is not set

Source

pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: SampleTime) -> u16
where PIN: Channel<ADC3, ID = u8>,

Synchronously convert a single sample Note that it reconfigures the adc sequence and doesn’t restore it

Trait Implementations§

Source§

impl<ADC: Clone> Clone for Adc<ADC>

Source§

fn clone(&self) -> Adc<ADC>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<ADC> Debug for Adc<ADC>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<PIN> OneShot<ADC1, u16, PIN> for Adc<ADC1>
where PIN: Channel<ADC1, ID = u8>,

Source§

type Error = ()

Error type returned by ADC methods
Source§

fn read(&mut self, pin: &mut PIN) -> Result<u16, Self::Error>

Request that the ADC begin a conversion on the specified pin Read more
Source§

impl<PIN> OneShot<ADC2, u16, PIN> for Adc<ADC2>
where PIN: Channel<ADC2, ID = u8>,

Source§

type Error = ()

Error type returned by ADC methods
Source§

fn read(&mut self, pin: &mut PIN) -> Result<u16, Self::Error>

Request that the ADC begin a conversion on the specified pin Read more
Source§

impl<PIN> OneShot<ADC3, u16, PIN> for Adc<ADC3>
where PIN: Channel<ADC3, ID = u8>,

Source§

type Error = ()

Error type returned by ADC methods
Source§

fn read(&mut self, pin: &mut PIN) -> Result<u16, Self::Error>

Request that the ADC begin a conversion on the specified pin Read more
Source§

impl<ADC: Copy> Copy for Adc<ADC>

Auto Trait Implementations§

§

impl<ADC> Freeze for Adc<ADC>
where ADC: Freeze,

§

impl<ADC> RefUnwindSafe for Adc<ADC>
where ADC: RefUnwindSafe,

§

impl<ADC> Send for Adc<ADC>
where ADC: Send,

§

impl<ADC> Sync for Adc<ADC>
where ADC: Sync,

§

impl<ADC> Unpin for Adc<ADC>
where ADC: Unpin,

§

impl<ADC> UnwindSafe for Adc<ADC>
where ADC: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.