stm32f7x7_hal/adc.rs
1//! Analog to digital converter configuration.
2//! According to CubeMx, all STM32F4 chips use the same ADC IP so this should be correct for all variants.
3
4#![deny(missing_docs)]
5
6/*
7 Currently unused but this is the formula for using temperature calibration:
8 Temperature in °C = (110-30)/(VtempCal110::get().read()-VtempCal30::get().read()) * (adc_sample - VtempCal30::get().read()) + 30
9*/
10
11use crate::{gpio::*, signature::VrefCal, signature::VDDA_CALIB, stm32};
12use core::fmt;
13use embedded_hal::adc::{Channel, OneShot};
14
15/// Vref internal signal, used for calibration
16pub struct Vref;
17
18/// Vbat internal signal, used for monitoring the battery (if used)
19pub struct Vbat;
20
21/// Core temperature internal signal
22pub struct Temperature;
23
24macro_rules! adc_pins {
25 ($($pin:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
26 $(
27 impl Channel<stm32::$adc> for $pin {
28 type ID = u8;
29 fn channel() -> u8 { $chan }
30 }
31 )+
32 };
33}
34
35/// Contains types related to ADC configuration
36pub mod config {
37 /// The place in the sequence a given channel should be captured
38 #[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
39 pub enum Sequence {
40 /// 1
41 One,
42 /// 2
43 Two,
44 /// 3
45 Three,
46 /// 4
47 Four,
48 /// 5
49 Five,
50 /// 6
51 Six,
52 /// 7
53 Seven,
54 /// 8
55 Eight,
56 /// 9
57 Nine,
58 /// 10
59 Ten,
60 /// 11
61 Eleven,
62 /// 12
63 Twelve,
64 /// 13
65 Thirteen,
66 /// 14
67 Fourteen,
68 /// 15
69 Fifteen,
70 /// 16
71 Sixteen,
72 }
73
74 impl From<Sequence> for u8 {
75 fn from(s: Sequence) -> u8 {
76 match s {
77 Sequence::One => 0,
78 Sequence::Two => 1,
79 Sequence::Three => 2,
80 Sequence::Four => 3,
81 Sequence::Five => 4,
82 Sequence::Six => 5,
83 Sequence::Seven => 6,
84 Sequence::Eight => 7,
85 Sequence::Nine => 8,
86 Sequence::Ten => 9,
87 Sequence::Eleven => 10,
88 Sequence::Twelve => 11,
89 Sequence::Thirteen => 12,
90 Sequence::Fourteen => 13,
91 Sequence::Fifteen => 14,
92 Sequence::Sixteen => 15,
93 }
94 }
95 }
96
97 impl From<u8> for Sequence {
98 fn from(bits: u8) -> Self {
99 match bits {
100 0 => Sequence::One,
101 1 => Sequence::Two,
102 2 => Sequence::Three,
103 3 => Sequence::Four,
104 4 => Sequence::Five,
105 5 => Sequence::Six,
106 6 => Sequence::Seven,
107 7 => Sequence::Eight,
108 8 => Sequence::Nine,
109 9 => Sequence::Ten,
110 10 => Sequence::Eleven,
111 11 => Sequence::Twelve,
112 12 => Sequence::Thirteen,
113 13 => Sequence::Fourteen,
114 14 => Sequence::Fifteen,
115 15 => Sequence::Sixteen,
116 _ => unimplemented!(),
117 }
118 }
119 }
120
121 /// The number of cycles to sample a given channel for
122 #[derive(Debug, PartialEq, Copy, Clone)]
123 pub enum SampleTime {
124 /// 3 cycles
125 Cycles_3,
126 /// 15 cycles
127 Cycles_15,
128 /// 28 cycles
129 Cycles_28,
130 /// 56 cycles
131 Cycles_56,
132 /// 84 cycles
133 Cycles_84,
134 /// 112 cycles
135 Cycles_112,
136 /// 144 cycles
137 Cycles_144,
138 /// 480 cycles
139 Cycles_480,
140 }
141
142 impl From<u8> for SampleTime {
143 fn from(f: u8) -> SampleTime {
144 match f {
145 0 => SampleTime::Cycles_3,
146 1 => SampleTime::Cycles_15,
147 2 => SampleTime::Cycles_28,
148 3 => SampleTime::Cycles_56,
149 4 => SampleTime::Cycles_84,
150 5 => SampleTime::Cycles_112,
151 6 => SampleTime::Cycles_144,
152 7 => SampleTime::Cycles_480,
153 _ => unimplemented!(),
154 }
155 }
156 }
157
158 impl From<SampleTime> for u8 {
159 fn from(l: SampleTime) -> u8 {
160 match l {
161 SampleTime::Cycles_3 => 0,
162 SampleTime::Cycles_15 => 1,
163 SampleTime::Cycles_28 => 2,
164 SampleTime::Cycles_56 => 3,
165 SampleTime::Cycles_84 => 4,
166 SampleTime::Cycles_112 => 5,
167 SampleTime::Cycles_144 => 6,
168 SampleTime::Cycles_480 => 7,
169 }
170 }
171 }
172
173 /// Clock config for the ADC
174 /// Check the datasheet for the maximum speed the ADC supports
175 #[derive(Debug, Clone, Copy)]
176 pub enum Clock {
177 /// PCLK2 (APB2) divided by 2
178 Pclk2_div_2,
179 /// PCLK2 (APB2) divided by 4
180 Pclk2_div_4,
181 /// PCLK2 (APB2) divided by 6
182 Pclk2_div_6,
183 /// PCLK2 (APB2) divided by 8
184 Pclk2_div_8,
185 }
186
187 impl From<Clock> for u8 {
188 fn from(c: Clock) -> u8 {
189 match c {
190 Clock::Pclk2_div_2 => 0,
191 Clock::Pclk2_div_4 => 1,
192 Clock::Pclk2_div_6 => 2,
193 Clock::Pclk2_div_8 => 3,
194 }
195 }
196 }
197
198 /// Resolution to sample at
199 #[derive(Debug, Clone, Copy)]
200 pub enum Resolution {
201 /// 12-bit
202 Twelve,
203 /// 10-bit
204 Ten,
205 /// 8-bit
206 Eight,
207 /// 6-bit
208 Six,
209 }
210 impl From<Resolution> for u8 {
211 fn from(r: Resolution) -> u8 {
212 match r {
213 Resolution::Twelve => 0,
214 Resolution::Ten => 1,
215 Resolution::Eight => 2,
216 Resolution::Six => 3,
217 }
218 }
219 }
220
221 /// Possible external triggers the ADC can listen to
222 #[derive(Debug, Clone, Copy)]
223 pub enum ExternalTrigger {
224 /// TIM1 compare channel 1
225 Tim_1_cc_1,
226 /// TIM1 compare channel 2
227 Tim_1_cc_2,
228 /// TIM1 compare channel 3
229 Tim_1_cc_3,
230 /// TIM2 compare channel 2
231 Tim_2_cc_2,
232 /// TIM2 compare channel 3
233 Tim_2_cc_3,
234 /// TIM2 compare channel 4
235 Tim_2_cc_4,
236 /// TIM2 trigger out
237 Tim_2_trgo,
238 /// TIM3 compare channel 1
239 Tim_3_cc_1,
240 /// TIM3 trigger out
241 Tim_3_trgo,
242 /// TIM4 compare channel 4
243 Tim_4_cc_4,
244 /// TIM5 compare channel 1
245 Tim_5_cc_1,
246 /// TIM5 compare channel 2
247 Tim_5_cc_2,
248 /// TIM5 compare channel 3
249 Tim_5_cc_3,
250 /// External interupt line 11
251 Exti_11,
252 }
253 impl From<ExternalTrigger> for u8 {
254 fn from(et: ExternalTrigger) -> u8 {
255 match et {
256 ExternalTrigger::Tim_1_cc_1 => 0b0000,
257 ExternalTrigger::Tim_1_cc_2 => 0b0001,
258 ExternalTrigger::Tim_1_cc_3 => 0b0010,
259 ExternalTrigger::Tim_2_cc_2 => 0b0011,
260 ExternalTrigger::Tim_2_cc_3 => 0b0100,
261 ExternalTrigger::Tim_2_cc_4 => 0b0101,
262 ExternalTrigger::Tim_2_trgo => 0b0110,
263 ExternalTrigger::Tim_3_cc_1 => 0b0111,
264 ExternalTrigger::Tim_3_trgo => 0b1000,
265 ExternalTrigger::Tim_4_cc_4 => 0b1001,
266 ExternalTrigger::Tim_5_cc_1 => 0b1010,
267 ExternalTrigger::Tim_5_cc_2 => 0b1011,
268 ExternalTrigger::Tim_5_cc_3 => 0b1100,
269 ExternalTrigger::Exti_11 => 0b1111,
270 }
271 }
272 }
273
274 /// Possible trigger modes
275 #[derive(Debug, Clone, Copy)]
276 pub enum TriggerMode {
277 /// Don't listen to external trigger
278 Disabled,
279 /// Listen for rising edges of external trigger
280 RisingEdge,
281 /// Listen for falling edges of external trigger
282 FallingEdge,
283 /// Listen for both rising and falling edges of external trigger
284 BothEdges,
285 }
286 impl From<TriggerMode> for u8 {
287 fn from(tm: TriggerMode) -> u8 {
288 match tm {
289 TriggerMode::Disabled => 0,
290 TriggerMode::RisingEdge => 1,
291 TriggerMode::FallingEdge => 2,
292 TriggerMode::BothEdges => 3,
293 }
294 }
295 }
296
297 /// Data register alignment
298 #[derive(Debug, Clone, Copy)]
299 pub enum Align {
300 /// Right align output data
301 Right,
302 /// Left align output data
303 Left,
304 }
305 impl From<Align> for bool {
306 fn from(a: Align) -> bool {
307 match a {
308 Align::Right => false,
309 Align::Left => true,
310 }
311 }
312 }
313
314 /// Scan enable/disable
315 #[derive(Debug, Clone, Copy)]
316 pub enum Scan {
317 /// Scan mode disabled
318 Disabled,
319 /// Scan mode enabled
320 Enabled,
321 }
322 impl From<Scan> for bool {
323 fn from(s: Scan) -> bool {
324 match s {
325 Scan::Disabled => false,
326 Scan::Enabled => true,
327 }
328 }
329 }
330
331 /// Continuous mode enable/disable
332 #[derive(Debug, Clone, Copy)]
333 pub enum Continuous {
334 /// Single mode, continuous disabled
335 Single,
336 /// Continuous mode enabled
337 Continuous,
338 }
339 impl From<Continuous> for bool {
340 fn from(c: Continuous) -> bool {
341 match c {
342 Continuous::Single => false,
343 Continuous::Continuous => true,
344 }
345 }
346 }
347
348 /// DMA mode
349 #[derive(Debug, Clone, Copy)]
350 pub enum Dma {
351 /// No DMA, disabled
352 Disabled,
353 /// Single DMA, DMA will be disabled after each conversion sequence
354 Single,
355 /// Continuous DMA, DMA will remain enabled after conversion
356 Continuous,
357 }
358
359 /// End-of-conversion interrupt enabled/disabled
360 #[derive(Debug, Clone, Copy)]
361 pub enum Eoc {
362 /// End-of-conversion interrupt disabled
363 Disabled,
364 /// End-of-conversion interrupt enabled per conversion
365 Conversion,
366 /// End-of-conversion interrupt enabled per sequence
367 Sequence,
368 }
369
370 /// Configuration for the adc.
371 /// There are some additional parameters on the adc peripheral that can be
372 /// added here when needed but this covers several basic usecases.
373 #[derive(Debug, Clone, Copy)]
374 pub struct AdcConfig {
375 pub(crate) clock: Clock,
376 pub(crate) resolution: Resolution,
377 pub(crate) align: Align,
378 pub(crate) scan: Scan,
379 pub(crate) external_trigger: (TriggerMode, ExternalTrigger),
380 pub(crate) continuous: Continuous,
381 pub(crate) dma: Dma,
382 pub(crate) end_of_conversion_interrupt: Eoc,
383 pub(crate) default_sample_time: SampleTime,
384 }
385
386 impl AdcConfig {
387 /// change the clock field
388 pub fn clock(mut self, clock: Clock) -> Self {
389 self.clock = clock;
390 self
391 }
392 /// change the resolution field
393 pub fn resolution(mut self, resolution: Resolution) -> Self {
394 self.resolution = resolution;
395 self
396 }
397 /// change the align field
398 pub fn align(mut self, align: Align) -> Self {
399 self.align = align;
400 self
401 }
402 /// change the scan field
403 pub fn scan(mut self, scan: Scan) -> Self {
404 self.scan = scan;
405 self
406 }
407 /// change the external_trigger field
408 pub fn external_trigger(
409 mut self,
410 trigger_mode: TriggerMode,
411 trigger: ExternalTrigger,
412 ) -> Self {
413 self.external_trigger = (trigger_mode, trigger);
414 self
415 }
416 /// change the continuous field
417 pub fn continuous(mut self, continuous: Continuous) -> Self {
418 self.continuous = continuous;
419 self
420 }
421 /// change the dma field
422 pub fn dma(mut self, dma: Dma) -> Self {
423 self.dma = dma;
424 self
425 }
426 /// change the end_of_conversion_interrupt field
427 pub fn end_of_conversion_interrupt(mut self, end_of_conversion_interrupt: Eoc) -> Self {
428 self.end_of_conversion_interrupt = end_of_conversion_interrupt;
429 self
430 }
431 /// change the default_sample_time field
432 pub fn default_sample_time(mut self, default_sample_time: SampleTime) -> Self {
433 self.default_sample_time = default_sample_time;
434 self
435 }
436 }
437
438 impl Default for AdcConfig {
439 fn default() -> Self {
440 Self {
441 clock: Clock::Pclk2_div_2,
442 resolution: Resolution::Twelve,
443 align: Align::Right,
444 scan: Scan::Disabled,
445 external_trigger: (TriggerMode::Disabled, ExternalTrigger::Tim_1_cc_1),
446 continuous: Continuous::Single,
447 dma: Dma::Disabled,
448 end_of_conversion_interrupt: Eoc::Disabled,
449 default_sample_time: SampleTime::Cycles_480,
450 }
451 }
452 }
453}
454
455/// Analog to Digital Converter
456/// # Status
457/// Most options relating to regular conversions are implemented. One-shot and sequences of conversions
458/// have been tested and work as expected.
459///
460/// GPIO to channel mapping should be correct for all supported F4 devices. The mappings were taken from
461/// CubeMX. The mappings are feature gated per 4xx device but there are actually sub variants for some
462/// devices and some pins may be missing on some variants. The implementation has been split up and commented
463/// to show which pins are available on certain device variants but currently the library doesn't enforce this.
464/// To fully support the right pins would require 10+ more features for the various variants.
465/// ## Todo
466/// * Injected conversions
467/// * Analog watchdog config
468/// * Discontinuous mode
469/// # Examples
470/// ## One-shot conversion
471/// ```
472/// use stm32f7x7_hal::{
473/// gpio::gpioa,
474/// adc::{
475/// Adc,
476/// config::AdcConfig,
477/// config::SampleTime,
478/// },
479/// };
480///
481/// fn main() {
482/// let mut adc = Adc::adc1(device.ADC1, true, AdcConfig::default());
483/// let pa3 = gpioa.pa3.into_analog();
484/// let sample = adc.convert(&pa3, SampleTime::Cycles_480);
485/// let millivolts = adc.sample_to_millivolts(sample);
486/// info!("pa3: {}mV", millivolts);
487/// }
488/// ```
489///
490/// ## Sequence conversion
491/// ```
492/// use stm32f7x7_hal::{
493/// gpio::gpioa,
494/// adc::{
495/// Adc,
496/// config::AdcConfig,
497/// config::SampleTime,
498/// config::Sequence,
499/// config::Eoc,
500/// config::Scan,
501/// config::Clock,
502/// },
503/// };
504///
505/// fn main() {
506/// let config = AdcConfig::default()
507/// //We'll either need DMA or an interrupt per conversion to convert
508/// //multiple values in a sequence
509/// .end_of_conversion_interrupt(Eoc::Conversion);
510/// //Scan mode is also required to convert a sequence
511/// .scan(Scan::Enabled)
512/// //And since we're looking for one interrupt per conversion the
513/// //clock will need to be fairly slow to avoid overruns breaking
514/// //the sequence. If you are running in debug mode and logging in
515/// //the interrupt, good luck... try setting pclk2 really low.
516/// //(Better yet use DMA)
517/// .clock(Clock::Pclk2_div_8);
518/// let mut adc = Adc::adc1(device.ADC1, true, config);
519/// let pa0 = gpioa.pa0.into_analog();
520/// let pa3 = gpioa.pa3.into_analog();
521/// adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_112);
522/// adc.configure_channel(&pa3, Sequence::Two, SampleTime::Cycles_480);
523/// adc.configure_channel(&pa0, Sequence::Three, SampleTime::Cycles_112);
524/// adc.start_conversion();
525/// }
526/// ```
527///
528/// ## External trigger
529///
530/// A common mistake on STM forums is enabling continuous mode but that causes it to start
531/// capturing on the first trigger and capture as fast as possible forever, regardless of
532/// future triggers. Continuous mode is disabled by default but I thought it was worth
533/// highlighting.
534///
535/// Getting the timer config right to make sure it's sending the event the ADC is listening
536/// to can be a bit of a pain but the key fields are highlighted below. Try hooking a timer
537/// channel up to an external pin with an LED or oscilloscope attached to check it's really
538/// generating pulses if the ADC doesn't seem to be triggering.
539/// ```
540/// use stm32f7x7_hal::{
541/// gpio::gpioa,
542/// adc::{
543/// Adc,
544/// config::AdcConfig,
545/// config::SampleTime,
546/// config::Sequence,
547/// config::Eoc,
548/// config::Scan,
549/// config::Clock,
550/// },
551/// };
552///
553/// fn main() {
554/// let config = AdcConfig::default()
555/// //Set the trigger you want
556/// .external_trigger(TriggerMode::RisingEdge, ExternalTrigger::Tim_1_cc_1);
557/// let mut adc = Adc::adc1(device.ADC1, true, config);
558/// let pa0 = gpioa.pa0.into_analog();
559/// adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_112);
560/// //Make sure it's enabled but don't start the conversion
561/// adc.enable();
562///
563/// //Configure the timer
564/// let mut tim = Timer::tim1(device.TIM1, 1.hz(), clocks);
565/// unsafe {
566/// let tim = &(*TIM1::ptr());
567///
568/// //This is pwm mode 1, the default mode is "frozen" which won't work
569/// let mode = 0b0110;
570///
571/// //Channel 1
572/// //Disable the channel before configuring it
573/// tim.ccer.modify(|_, w| w.cc1e().clear_bit());
574///
575/// tim.ccmr1_output.modify(|_, w| w
576/// //Preload enable for channel
577/// .oc1pe().set_bit()
578///
579/// //Set mode for channel
580/// .oc1m().bits(mode)
581/// );
582///
583/// //Set the duty cycle, 0 won't work in pwm mode but might be ok in
584/// //toggle mode or match mode
585/// let max_duty = tim.arr.read().arr().bits() as u16;
586/// tim.ccr1.modify(|_, w| w.ccr1().bits(max_duty / 2));
587///
588/// //Enable the channel
589/// tim.ccer.modify(|_, w| w.cc1e().set_bit());
590///
591/// //Enable the TIM main Output
592/// tim.bdtr.modify(|_, w| w.moe().set_bit());
593/// }
594/// ```
595#[derive(Clone, Copy)]
596pub struct Adc<ADC> {
597 /// Current config of the ADC, kept up to date by the various set methods
598 config: config::AdcConfig,
599 /// The adc peripheral
600 adc_reg: ADC,
601 /// VDDA in millivolts calculated from the factory calibration and vrefint
602 calibrated_vdda: u32,
603 /// Maximum sample value possible for the configured resolution
604 max_sample: u32,
605}
606impl<ADC> fmt::Debug for Adc<ADC> {
607 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
608 write!(
609 f,
610 "Adc: {{ calibrated_vdda: {:?}, max_sample: {:?}, config: {:?}, ... }}",
611 self.calibrated_vdda, self.max_sample, self.config
612 )
613 }
614}
615
616macro_rules! adc {
617 ($($adc_type:ident => ($constructor_fn_name:ident, $common_type:ident, $rcc_enr_reg:ident, $rcc_enr_field: ident, $rcc_rst_reg: ident, $rcc_rst_field: ident)),+ $(,)*) => {
618 $(
619 impl Adc<stm32::$adc_type> {
620 /// Enables the ADC clock, resets the peripheral (optionally), runs calibration and applies the supplied config
621 /// # Arguments
622 /// * `reset` - should a reset be performed. This is provided because on some devices multiple ADCs share the same common reset
623 pub fn $constructor_fn_name(adc: stm32::$adc_type, reset: bool, config: config::AdcConfig) -> Adc<stm32::$adc_type> {
624 unsafe {
625 let rcc = &(*stm32::RCC::ptr());
626 //Enable the common clock
627 rcc.$rcc_enr_reg.modify(|_, w| w.$rcc_enr_field().set_bit());
628 if reset {
629 //Reset the peripheral(s)
630 rcc.$rcc_rst_reg.modify(|_, w| w.$rcc_rst_field().set_bit());
631 rcc.$rcc_rst_reg.modify(|_, w| w.$rcc_rst_field().clear_bit());
632 }
633 }
634
635 let mut s = Self {
636 config,
637 adc_reg: adc,
638 calibrated_vdda: VDDA_CALIB,
639 max_sample: 0,
640 };
641
642 //Probably unnecessary to disable the ADC in most cases but it shouldn't do any harm either
643 s.disable();
644 s.apply_config(config);
645
646 s.enable();
647 s.calibrate();
648
649 s
650 }
651
652 /// Applies all fields in AdcConfig
653 pub fn apply_config(&mut self, config: config::AdcConfig) {
654 self.set_clock(config.clock);
655 self.set_resolution(config.resolution);
656 self.set_align(config.align);
657 self.set_scan(config.scan);
658 self.set_external_trigger(config.external_trigger);
659 self.set_continuous(config.continuous);
660 self.set_dma(config.dma);
661 self.set_end_of_conversion_interrupt(config.end_of_conversion_interrupt);
662 self.set_default_sample_time(config.default_sample_time);
663 }
664
665 /// Calculates the system VDDA by sampling the internal VREF channel and comparing
666 /// the result with the value stored at the factory.
667 pub fn calibrate(&mut self) {
668 self.enable();
669
670 let vref_en = self.temperature_and_vref_enabled();
671 if !vref_en {
672 self.enable_temperature_and_vref();
673 }
674
675 let vref_cal = VrefCal::get().read();
676 let vref_samp = self.read(&mut Vref).unwrap(); //This can't actually fail, it's just in a result to satisfy hal trait
677
678 self.calibrated_vdda = (VDDA_CALIB * u32::from(vref_cal)) / u32::from(vref_samp);
679 if !vref_en {
680 self.disable_temperature_and_vref();
681 }
682 }
683
684 /// Enables the vbat internal channel
685 pub fn enable_vbat(&self) {
686 unsafe {
687 let common = &(*stm32::$common_type::ptr());
688 common.ccr.modify(|_, w| w.vbate().set_bit());
689 }
690 }
691
692 /// Enables the vbat internal channel
693 pub fn disable_vbat(&self) {
694 unsafe {
695 let common = &(*stm32::$common_type::ptr());
696 common.ccr.modify(|_, w| w.vbate().clear_bit());
697 }
698 }
699
700 /// Enables the temp and vref internal channels.
701 /// They can't work while vbat is also enabled so this method also disables vbat.
702 pub fn enable_temperature_and_vref(&mut self) {
703 //VBAT prevents TS and VREF from being sampled
704 self.disable_vbat();
705 unsafe {
706 let common = &(*stm32::$common_type::ptr());
707 common.ccr.modify(|_, w| w.tsvrefe().set_bit());
708 }
709 }
710
711 /// Disables the temp and vref internal channels
712 pub fn disable_temperature_and_vref(&mut self) {
713 unsafe {
714 let common = &(*stm32::$common_type::ptr());
715 common.ccr.modify(|_, w| w.tsvrefe().clear_bit());
716 }
717 }
718
719 /// Returns if the temp and vref internal channels are enabled
720 pub fn temperature_and_vref_enabled(&mut self) -> bool {
721 unsafe {
722 let common = &(*stm32::$common_type::ptr());
723 common.ccr.read().tsvrefe().bit_is_set()
724 }
725 }
726
727 /// Returns if the adc is enabled
728 pub fn is_enabled(&self) -> bool {
729 self.adc_reg.cr2.read().adon().bit_is_set()
730 }
731
732 /// Enables the adc
733 pub fn enable(&mut self) {
734 self.adc_reg.cr2.modify(|_, w| w.adon().set_bit());
735 }
736
737 /// Disables the adc
738 /// # Note
739 /// The ADC in the f4 has few restrictions on what can be configured while the ADC
740 /// is enabled. If any bugs are found where some settings aren't "sticking" try disabling
741 /// the ADC before changing them. The reference manual for the chip I'm using only states
742 /// that the sequence registers are locked when they are being converted.
743 pub fn disable(&mut self) {
744 self.adc_reg.cr2.modify(|_, w| w.adon().clear_bit());
745 }
746
747 /// Starts conversion sequence. Waits for the hardware to indicate it's actually started.
748 pub fn start_conversion(&mut self) {
749 self.enable();
750 self.clear_end_of_conversion_flag();
751 //Start conversion
752 self.adc_reg.cr2.modify(|_, w| w.swstart().set_bit());
753
754 while !self.adc_reg.sr.read().strt().bit_is_set() {}
755 }
756
757 /// Sets the clock for the adc
758 pub fn set_clock(&mut self, clock: config::Clock) {
759 self.config.clock = clock;
760 unsafe {
761 let common = &(*stm32::$common_type::ptr());
762 common.ccr.modify(|_, w| w.adcpre().bits(clock.into()));
763 }
764 }
765
766 /// Sets the sampling resolution
767 pub fn set_resolution(&mut self, resolution: config::Resolution) {
768 self.max_sample = match resolution {
769 config::Resolution::Twelve => (1 << 12) - 1,
770 config::Resolution::Ten => (1 << 10) - 1,
771 config::Resolution::Eight => (1 << 8) - 1,
772 config::Resolution::Six => (1 << 6) -1,
773 };
774 self.config.resolution = resolution;
775 self.adc_reg.cr1.modify(|_, w| w.res().bits(resolution.into()));
776 }
777
778 /// Sets the DR register alignment to left or right
779 pub fn set_align(&mut self, align: config::Align) {
780 self.config.align = align;
781 self.adc_reg.cr2.modify(|_, w| w.align().bit(align.into()));
782 }
783
784 /// Enables and disables scan mode
785 pub fn set_scan(&mut self, scan: config::Scan) {
786 self.config.scan = scan;
787 self.adc_reg.cr1.modify(|_, w| w.scan().bit(scan.into()));
788 }
789
790 /// Sets which external trigger to use and if it is disabled, rising, falling or both
791 pub fn set_external_trigger(&mut self, (edge, extsel): (config::TriggerMode, config::ExternalTrigger)) {
792 self.config.external_trigger = (edge, extsel);
793 self.adc_reg.cr2.modify(|_, w| unsafe { w
794 .extsel().bits(extsel.into())
795 .exten().bits(edge.into())
796 });
797 }
798
799 /// Enables and disables continuous mode
800 pub fn set_continuous(&mut self, continuous: config::Continuous) {
801 self.config.continuous = continuous;
802 self.adc_reg.cr2.modify(|_, w| w.cont().bit(continuous.into()));
803 }
804
805 /// Sets DMA to disabled, single or continuous
806 pub fn set_dma(&mut self, dma: config::Dma) {
807 self.config.dma = dma;
808 let (dds, en) = match dma {
809 config::Dma::Disabled => (false, false),
810 config::Dma::Single => (false, true),
811 config::Dma::Continuous => (true, true),
812 };
813 self.adc_reg.cr2.modify(|_, w| w
814 //DDS stands for "DMA disable selection"
815 //0 means do one DMA then stop
816 //1 means keep sending DMA requests as long as DMA=1
817 .dds().bit(dds)
818 .dma().bit(en)
819 );
820 }
821
822 /// Sets if the end-of-conversion behaviour.
823 /// The end-of-conversion interrupt occur either per conversion or for the whole sequence.
824 pub fn set_end_of_conversion_interrupt(&mut self, eoc: config::Eoc) {
825 self.config.end_of_conversion_interrupt = eoc;
826 let (en, eocs) = match eoc {
827 config::Eoc::Disabled => (false, false),
828 config::Eoc::Conversion => (true, true),
829 config::Eoc::Sequence => (true, false),
830 };
831 self.adc_reg.cr1.modify(|_, w| w.eocie().bit(en));
832 self.adc_reg.cr2.modify(|_, w| w.eocs().bit(eocs));
833 }
834
835 /// Resets the end-of-conversion flag
836 pub fn clear_end_of_conversion_flag(&mut self) {
837 self.adc_reg.sr.modify(|_, w| w.eoc().clear_bit());
838 }
839
840 /// Sets the default sample time that is used for one-shot conversions.
841 /// [configure_channel](#method.configure_channel) and [start_conversion](#method.start_conversion) can be \
842 /// used for configurations where different sampling times are required per channel.
843 pub fn set_default_sample_time(&mut self, sample_time: config::SampleTime) {
844 self.config.default_sample_time = sample_time;
845 }
846
847 /// Returns the current sequence length. Primarily useful for configuring DMA.
848 pub fn sequence_length(&mut self) -> u8 {
849 self.adc_reg.sqr1.read().l().bits() + 1
850 }
851
852 /// Reset the sequence
853 pub fn reset_sequence(&mut self) {
854 //The reset state is One conversion selected
855 self.adc_reg.sqr1.modify(|_, w| w.l().bits(config::Sequence::One.into()));
856 }
857
858 /// Returns the address of the ADC data register. Primarily useful for configuring DMA.
859 pub fn data_register_address(&mut self) -> u32 {
860 &self.adc_reg.dr as *const _ as u32
861 }
862
863 /// Configure a channel for sampling.
864 /// It will make sure the sequence is at least as long as the `sequence` provided.
865 /// # Arguments
866 /// * `channel` - channel to configure
867 /// * `sequence` - where in the sequence to sample the channel. Also called rank in some STM docs/code
868 /// * `sample_time` - how long to sample for. See datasheet and ref manual to work out how long you need\
869 /// to sample for at a given ADC clock frequency
870 pub fn configure_channel<CHANNEL>(&mut self, _channel: &CHANNEL, sequence: config::Sequence, sample_time: config::SampleTime)
871 where
872 CHANNEL: Channel<stm32::$adc_type, ID=u8>
873 {
874 //Check the sequence is long enough
875 self.adc_reg.sqr1.modify(|r, w| {
876 let prev: config::Sequence = r.l().bits().into();
877 if prev < sequence {
878 w.l().bits(sequence.into())
879 } else {
880 w
881 }
882 });
883
884 let channel = CHANNEL::channel();
885
886 //Set the channel in the right sequence field
887 match sequence {
888 config::Sequence::One => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq1().bits(channel) }),
889 config::Sequence::Two => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq2().bits(channel) }),
890 config::Sequence::Three => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq3().bits(channel) }),
891 config::Sequence::Four => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq4().bits(channel) }),
892 config::Sequence::Five => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq5().bits(channel) }),
893 config::Sequence::Six => self.adc_reg.sqr3.modify(|_, w| unsafe {w.sq6().bits(channel) }),
894 config::Sequence::Seven => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq7().bits(channel) }),
895 config::Sequence::Eight => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq8().bits(channel) }),
896 config::Sequence::Nine => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq9().bits(channel) }),
897 config::Sequence::Ten => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq10().bits(channel) }),
898 config::Sequence::Eleven => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq11().bits(channel) }),
899 config::Sequence::Twelve => self.adc_reg.sqr2.modify(|_, w| unsafe {w.sq12().bits(channel) }),
900 config::Sequence::Thirteen => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq13().bits(channel) }),
901 config::Sequence::Fourteen => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq14().bits(channel) }),
902 config::Sequence::Fifteen => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq15().bits(channel) }),
903 config::Sequence::Sixteen => self.adc_reg.sqr1.modify(|_, w| unsafe {w.sq16().bits(channel) }),
904 }
905
906 fn replace_bits(mut v: u32, offset: u32, width: u32, value: u32) -> u32 {
907 let mask = !(((1 << width) -1) << (offset * width));
908 v &= mask;
909 v |= value << (offset * width);
910 v
911 }
912
913 //Set the sample time for the channel
914 let st = u8::from(sample_time);
915 let st = u32::from(st);
916 let ch = u32::from(channel);
917 match channel {
918 0...9 => self.adc_reg.smpr2.modify(|r, w| unsafe { w.bits(replace_bits(r.bits(), ch, 3, st)) }),
919 10...18 => self.adc_reg.smpr1.modify(|r, w| unsafe { w.bits(replace_bits(r.bits(), ch-10, 3, st)) }),
920 _ => unimplemented!(),
921 }
922 }
923
924 /// Returns the current sample stored in the ADC data register
925 pub fn current_sample(&self) -> u16 {
926 self.adc_reg.dr.read().data().bits()
927 }
928
929 /// Converts a sample value to millivolts using calibrated VDDA and configured resolution
930 pub fn sample_to_millivolts(&self, sample: u16) -> u16 {
931 ((u32::from(sample) * self.calibrated_vdda) / self.max_sample) as u16
932 }
933
934 /// Block until the conversion is completed
935 /// # Panics
936 /// Will panic if there is no conversion started and the end-of-conversion bit is not set
937 pub fn wait_for_conversion_sequence(&self) {
938 if !self.adc_reg.sr.read().strt().bit_is_set() && !self.adc_reg.sr.read().eoc().bit_is_set() {
939 panic!("Waiting for end-of-conversion but no conversion started");
940 }
941 while !self.adc_reg.sr.read().eoc().bit_is_set() {}
942 //Clear the conversion started flag
943 self.adc_reg.sr.modify(|_, w| w.strt().clear_bit());
944 }
945
946 /// Synchronously convert a single sample
947 /// Note that it reconfigures the adc sequence and doesn't restore it
948 pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: config::SampleTime) -> u16
949 where
950 PIN: Channel<stm32::$adc_type, ID=u8>
951 {
952 self.adc_reg.cr2.modify(|_, w| w
953 .dma().clear_bit() //Disable dma
954 .cont().clear_bit() //Disable continuous mode
955 .exten().bits(config::TriggerMode::Disabled.into()) //Disable trigger
956 .eocs().clear_bit() //EOC is set at the end of the sequence
957 );
958 self.adc_reg.cr1.modify(|_, w| w
959 .scan().clear_bit() //Disable scan mode
960 .eocie().clear_bit() //Disable end of conversion interrupt
961 );
962
963 self.reset_sequence();
964 self.configure_channel(pin, config::Sequence::One, sample_time);
965 self.enable();
966 self.clear_end_of_conversion_flag();
967 self.start_conversion();
968
969 //Wait for the sequence to complete
970 self.wait_for_conversion_sequence();
971
972 let result = self.current_sample();
973
974 //Reset the config
975 self.apply_config(self.config);
976
977 result
978 }
979 }
980
981 impl<PIN> OneShot<stm32::$adc_type, u16, PIN> for Adc<stm32::$adc_type>
982 where
983 PIN: Channel<stm32::$adc_type, ID=u8>,
984 {
985 type Error = ();
986
987 fn read(&mut self, pin: &mut PIN) -> nb::Result<u16, Self::Error> {
988 let enabled = self.is_enabled();
989 if !enabled {
990 self.enable();
991 }
992
993 let sample = self.convert(pin, self.config.default_sample_time);
994
995 if !enabled {
996 self.disable();
997 }
998
999 Ok(sample)
1000 }
1001 }
1002 )+
1003 };
1004}
1005
1006adc!(ADC1 => (adc1, ADC_COMMON, apb2enr, adc1en, apb2rstr, adcrst));
1007adc!(ADC2 => (adc2, ADC_COMMON, apb2enr, adc2en, apb2rstr, adcrst));
1008adc!(ADC3 => (adc3, ADC_COMMON, apb2enr, adc3en, apb2rstr, adcrst));
1009
1010adc_pins!(
1011 gpioa::PA0<Analog> => (ADC1, 0),
1012 gpioa::PA0<Analog> => (ADC2, 0),
1013 gpioa::PA0<Analog> => (ADC3, 0),
1014 gpioa::PA1<Analog> => (ADC1, 1),
1015 gpioa::PA1<Analog> => (ADC2, 1),
1016 gpioa::PA1<Analog> => (ADC3, 1),
1017 gpioa::PA2<Analog> => (ADC1, 2),
1018 gpioa::PA2<Analog> => (ADC2, 2),
1019 gpioa::PA2<Analog> => (ADC3, 2),
1020 gpioa::PA3<Analog> => (ADC1, 3),
1021 gpioa::PA3<Analog> => (ADC2, 3),
1022 gpioa::PA3<Analog> => (ADC3, 3),
1023 gpioa::PA4<Analog> => (ADC1, 4),
1024 gpioa::PA4<Analog> => (ADC2, 4),
1025 gpioa::PA5<Analog> => (ADC1, 5),
1026 gpioa::PA5<Analog> => (ADC2, 5),
1027 gpioa::PA6<Analog> => (ADC1, 6),
1028 gpioa::PA6<Analog> => (ADC2, 6),
1029 gpioa::PA7<Analog> => (ADC1, 7),
1030 gpioa::PA7<Analog> => (ADC2, 7),
1031 gpiob::PB0<Analog> => (ADC1, 8),
1032 gpiob::PB0<Analog> => (ADC2, 8),
1033 gpiob::PB1<Analog> => (ADC1, 9),
1034 gpiob::PB1<Analog> => (ADC2, 9),
1035 gpioc::PC0<Analog> => (ADC1, 10),
1036 gpioc::PC0<Analog> => (ADC2, 10),
1037 gpioc::PC0<Analog> => (ADC3, 10),
1038 gpioc::PC1<Analog> => (ADC1, 11),
1039 gpioc::PC1<Analog> => (ADC2, 11),
1040 gpioc::PC1<Analog> => (ADC3, 11),
1041 gpioc::PC2<Analog> => (ADC1, 12),
1042 gpioc::PC2<Analog> => (ADC2, 12),
1043 gpioc::PC2<Analog> => (ADC3, 12),
1044 gpioc::PC3<Analog> => (ADC1, 13),
1045 gpioc::PC3<Analog> => (ADC2, 13),
1046 gpioc::PC3<Analog> => (ADC3, 13),
1047 gpioc::PC4<Analog> => (ADC1, 14),
1048 gpioc::PC4<Analog> => (ADC2, 14),
1049 gpioc::PC5<Analog> => (ADC1, 15),
1050 gpioc::PC5<Analog> => (ADC2, 15),
1051 Temperature => (ADC1, 18),
1052 Temperature => (ADC2, 18),
1053 Temperature => (ADC3, 18),
1054 Vbat => (ADC1, 18),
1055 Vbat => (ADC2, 18),
1056 Vbat => (ADC3, 18),
1057 Vref => (ADC1, 17),
1058 Vref => (ADC2, 17),
1059 Vref => (ADC3, 17),
1060);
1061
1062adc_pins!(
1063 gpiof::PF10<Analog> => (ADC3, 8),
1064 gpiof::PF3<Analog> => (ADC3, 9),
1065 gpiof::PF4<Analog> => (ADC3, 14),
1066 gpiof::PF5<Analog> => (ADC3, 15),
1067 gpiof::PF6<Analog> => (ADC3, 4),
1068 gpiof::PF7<Analog> => (ADC3, 5),
1069 gpiof::PF8<Analog> => (ADC3, 6),
1070 gpiof::PF9<Analog> => (ADC3, 7),
1071);