@@ -381,6 +381,7 @@ pub mod config {
381381 pub ( crate ) dma : Dma ,
382382 pub ( crate ) end_of_conversion_interrupt : Eoc ,
383383 pub ( crate ) default_sample_time : SampleTime ,
384+ pub ( crate ) vdda : Option < u32 > ,
384385 }
385386
386387 impl AdcConfig {
@@ -433,6 +434,15 @@ pub mod config {
433434 self . default_sample_time = default_sample_time;
434435 self
435436 }
437+
438+ /// Specify the reference voltage for the ADC.
439+ ///
440+ /// # Args
441+ /// * `vdda_mv` - The ADC reference voltage in millivolts.
442+ pub fn reference_voltage ( mut self , vdda_mv : u32 ) -> Self {
443+ self . vdda = Some ( vdda_mv) ;
444+ self
445+ }
436446 }
437447
438448 impl Default for AdcConfig {
@@ -447,6 +457,7 @@ pub mod config {
447457 dma : Dma :: Disabled ,
448458 end_of_conversion_interrupt : Eoc :: Disabled ,
449459 default_sample_time : SampleTime :: Cycles_480 ,
460+ vdda : None ,
450461 }
451462 }
452463 }
@@ -606,9 +617,82 @@ impl<ADC> fmt::Debug for Adc<ADC> {
606617}
607618
608619macro_rules! adc {
620+ // Note that only ADC1 supports measurement of VREF, VBAT, and the internal temperature sensor.
621+ ( additionals: ADC1 => ( $common_type: ident) ) => {
622+ /// Calculates the system VDDA by sampling the internal VREF channel and comparing
623+ /// the result with the value stored at the factory.
624+ pub fn calibrate( & mut self ) {
625+ self . enable( ) ;
626+
627+ let vref_en = self . temperature_and_vref_enabled( ) ;
628+ if !vref_en {
629+ self . enable_temperature_and_vref( ) ;
630+ }
631+
632+ let vref_cal = VrefCal :: get( ) . read( ) ;
633+ let vref_samp = self . read( & mut Vref ) . unwrap( ) ; //This can't actually fail, it's just in a result to satisfy hal trait
634+
635+ self . calibrated_vdda = ( VDDA_CALIB * u32 :: from( vref_cal) ) / u32 :: from( vref_samp) ;
636+ if !vref_en {
637+ self . disable_temperature_and_vref( ) ;
638+ }
639+ }
640+
641+ /// Enables the vbat internal channel
642+ pub fn enable_vbat( & self ) {
643+ unsafe {
644+ let common = & ( * pac:: $common_type:: ptr( ) ) ;
645+ common. ccr. modify( |_, w| w. vbate( ) . set_bit( ) ) ;
646+ }
647+ }
648+
649+ /// Enables the vbat internal channel
650+ pub fn disable_vbat( & self ) {
651+ unsafe {
652+ let common = & ( * pac:: $common_type:: ptr( ) ) ;
653+ common. ccr. modify( |_, w| w. vbate( ) . clear_bit( ) ) ;
654+ }
655+ }
656+
657+ /// Enables the temp and vref internal channels.
658+ /// They can't work while vbat is also enabled so this method also disables vbat.
659+ pub fn enable_temperature_and_vref( & mut self ) {
660+ //VBAT prevents TS and VREF from being sampled
661+ self . disable_vbat( ) ;
662+ unsafe {
663+ let common = & ( * pac:: $common_type:: ptr( ) ) ;
664+ common. ccr. modify( |_, w| w. tsvrefe( ) . set_bit( ) ) ;
665+ }
666+ }
667+
668+ /// Disables the temp and vref internal channels
669+ pub fn disable_temperature_and_vref( & mut self ) {
670+ unsafe {
671+ let common = & ( * pac:: $common_type:: ptr( ) ) ;
672+ common. ccr. modify( |_, w| w. tsvrefe( ) . clear_bit( ) ) ;
673+ }
674+ }
675+
676+ /// Returns if the temp and vref internal channels are enabled
677+ pub fn temperature_and_vref_enabled( & mut self ) -> bool {
678+ unsafe {
679+ let common = & ( * pac:: $common_type:: ptr( ) ) ;
680+ common. ccr. read( ) . tsvrefe( ) . bit_is_set( )
681+ }
682+ }
683+ } ;
684+
685+ // Provide a stub implementation for ADCs that do not have a means of sampling VREF.
686+ ( additionals: $adc_type: ident => ( $common_type: ident) ) => {
687+ fn calibrate( & mut self ) { }
688+ } ;
689+
609690 ( $( $adc_type: ident => ( $constructor_fn_name: ident, $common_type: ident, $en_bit: expr) ) ,+ $( , ) * ) => {
610691 $(
611692 impl Adc <pac:: $adc_type> {
693+
694+ adc!( additionals: $adc_type => ( $common_type) ) ;
695+
612696 /// Enables the ADC clock, resets the peripheral (optionally), runs calibration and applies the supplied config
613697 /// # Arguments
614698 /// * `reset` - should a reset be performed. This is provided because on some devices multiple ADCs share the same common reset
@@ -642,6 +726,11 @@ macro_rules! adc {
642726 s. enable( ) ;
643727 s. calibrate( ) ;
644728
729+ // If the user specified a VDDA, use that over the internally determined value.
730+ if let Some ( vdda) = s. config. vdda {
731+ s. calibrated_vdda = vdda;
732+ }
733+
645734 s
646735 }
647736
@@ -656,67 +745,9 @@ macro_rules! adc {
656745 self . set_dma( config. dma) ;
657746 self . set_end_of_conversion_interrupt( config. end_of_conversion_interrupt) ;
658747 self . set_default_sample_time( config. default_sample_time) ;
659- }
660-
661- /// Calculates the system VDDA by sampling the internal VREF channel and comparing
662- /// the result with the value stored at the factory.
663- pub fn calibrate( & mut self ) {
664- self . enable( ) ;
665-
666- let vref_en = self . temperature_and_vref_enabled( ) ;
667- if !vref_en {
668- self . enable_temperature_and_vref( ) ;
669- }
670-
671- let vref_cal = VrefCal :: get( ) . read( ) ;
672- let vref_samp = self . read( & mut Vref ) . unwrap( ) ; //This can't actually fail, it's just in a result to satisfy hal trait
673-
674- self . calibrated_vdda = ( VDDA_CALIB * u32 :: from( vref_cal) ) / u32 :: from( vref_samp) ;
675- if !vref_en {
676- self . disable_temperature_and_vref( ) ;
677- }
678- }
679-
680- /// Enables the vbat internal channel
681- pub fn enable_vbat( & self ) {
682- unsafe {
683- let common = & ( * pac:: $common_type:: ptr( ) ) ;
684- common. ccr. modify( |_, w| w. vbate( ) . set_bit( ) ) ;
685- }
686- }
687-
688- /// Enables the vbat internal channel
689- pub fn disable_vbat( & self ) {
690- unsafe {
691- let common = & ( * pac:: $common_type:: ptr( ) ) ;
692- common. ccr. modify( |_, w| w. vbate( ) . clear_bit( ) ) ;
693- }
694- }
695-
696- /// Enables the temp and vref internal channels.
697- /// They can't work while vbat is also enabled so this method also disables vbat.
698- pub fn enable_temperature_and_vref( & mut self ) {
699- //VBAT prevents TS and VREF from being sampled
700- self . disable_vbat( ) ;
701- unsafe {
702- let common = & ( * pac:: $common_type:: ptr( ) ) ;
703- common. ccr. modify( |_, w| w. tsvrefe( ) . set_bit( ) ) ;
704- }
705- }
706748
707- /// Disables the temp and vref internal channels
708- pub fn disable_temperature_and_vref( & mut self ) {
709- unsafe {
710- let common = & ( * pac:: $common_type:: ptr( ) ) ;
711- common. ccr. modify( |_, w| w. tsvrefe( ) . clear_bit( ) ) ;
712- }
713- }
714-
715- /// Returns if the temp and vref internal channels are enabled
716- pub fn temperature_and_vref_enabled( & mut self ) -> bool {
717- unsafe {
718- let common = & ( * pac:: $common_type:: ptr( ) ) ;
719- common. ccr. read( ) . tsvrefe( ) . bit_is_set( )
749+ if let Some ( vdda) = config. vdda {
750+ self . calibrated_vdda = vdda;
720751 }
721752 }
722753
@@ -1365,14 +1396,8 @@ adc_pins!(
13651396 gpioc:: PC5 <Analog > => ( ADC1 , 15 ) ,
13661397 gpioc:: PC5 <Analog > => ( ADC2 , 15 ) ,
13671398 Temperature => ( ADC1 , 18 ) ,
1368- Temperature => ( ADC2 , 18 ) ,
1369- Temperature => ( ADC3 , 18 ) ,
13701399 Vbat => ( ADC1 , 18 ) ,
1371- Vbat => ( ADC2 , 18 ) ,
1372- Vbat => ( ADC3 , 18 ) ,
13731400 Vref => ( ADC1 , 17 ) ,
1374- Vref => ( ADC2 , 17 ) ,
1375- Vref => ( ADC3 , 17 ) ,
13761401) ;
13771402
13781403// Not available on V variant
@@ -1436,14 +1461,8 @@ adc_pins!(
14361461 gpioc:: PC5 <Analog > => ( ADC1 , 15 ) ,
14371462 gpioc:: PC5 <Analog > => ( ADC2 , 15 ) ,
14381463 Temperature => ( ADC1 , 18 ) ,
1439- Temperature => ( ADC2 , 18 ) ,
1440- Temperature => ( ADC3 , 18 ) ,
14411464 Vbat => ( ADC1 , 18 ) ,
1442- Vbat => ( ADC2 , 18 ) ,
1443- Vbat => ( ADC3 , 18 ) ,
14441465 Vref => ( ADC1 , 17 ) ,
1445- Vref => ( ADC2 , 17 ) ,
1446- Vref => ( ADC3 , 17 ) ,
14471466) ;
14481467
14491468// Not available on V variant
@@ -1502,14 +1521,8 @@ adc_pins!(
15021521 gpioc:: PC4 <Analog > => ( ADC1 , 14 ) ,
15031522 gpioc:: PC4 <Analog > => ( ADC2 , 14 ) ,
15041523 Temperature => ( ADC1 , 18 ) ,
1505- Temperature => ( ADC2 , 18 ) ,
1506- Temperature => ( ADC3 , 18 ) ,
15071524 Vbat => ( ADC1 , 18 ) ,
1508- Vbat => ( ADC2 , 18 ) ,
1509- Vbat => ( ADC3 , 18 ) ,
15101525 Vref => ( ADC1 , 17 ) ,
1511- Vref => ( ADC2 , 17 ) ,
1512- Vref => ( ADC3 , 17 ) ,
15131526) ;
15141527
15151528// Not available on M variant
@@ -1569,14 +1582,8 @@ adc_pins!(
15691582 gpioc:: PC1 <Analog > => ( ADC2 , 11 ) ,
15701583 gpioc:: PC1 <Analog > => ( ADC3 , 11 ) ,
15711584 Temperature => ( ADC1 , 18 ) ,
1572- Temperature => ( ADC2 , 18 ) ,
1573- Temperature => ( ADC3 , 18 ) ,
15741585 Vbat => ( ADC1 , 18 ) ,
1575- Vbat => ( ADC2 , 18 ) ,
1576- Vbat => ( ADC3 , 18 ) ,
15771586 Vref => ( ADC1 , 17 ) ,
1578- Vref => ( ADC2 , 17 ) ,
1579- Vref => ( ADC3 , 17 ) ,
15801587) ;
15811588
15821589// Not available on A variant
0 commit comments