3434//! ```
3535
3636#[ cfg( feature = "device-selected" ) ]
37- use embedded_hal :: adc :: { Channel , OneShot } ;
37+ const VREFCAL : * const u16 = 0x1FFF_F7BA as * const u16 ;
3838
3939#[ cfg( feature = "device-selected" ) ]
40- use crate :: { stm32, gpio:: * } ;
40+ const VTEMPCAL30 : * const u16 = 0x1FFF_F7B8 as * const u16 ;
41+
42+ #[ cfg( feature = "device-selected" ) ]
43+ const VTEMPCAL110 : * const u16 = 0x1FFF_F7C2 as * const u16 ;
44+
45+ #[ cfg( feature = "device-selected" ) ]
46+ const VDD_CALIB : u16 = 3300 ;
47+
48+ #[ cfg( feature = "device-selected" ) ]
49+ use core:: ptr;
50+
51+ #[ cfg( feature = "device-selected" ) ]
52+ use embedded_hal:: {
53+ adc:: { Channel , OneShot } ,
54+ blocking:: delay:: DelayUs ,
55+ } ;
56+
57+ #[ cfg( feature = "device-selected" ) ]
58+ use crate :: { delay:: Delay , gpio:: * , stm32} ;
4159
4260#[ cfg( feature = "device-selected" ) ]
4361/// Analog to Digital converter interface
@@ -48,7 +66,7 @@ pub struct Adc {
4866 precision : AdcPrecision ,
4967}
5068
51- #[ derive( Debug , PartialEq ) ]
69+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
5270/// ADC Sampling time
5371///
5472/// Options for the sampling time, each is T + 0.5 ADC clock cycles.
@@ -96,7 +114,7 @@ impl AdcSampleTime {
96114 }
97115}
98116
99- #[ derive( Debug , PartialEq ) ]
117+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
100118/// ADC Result Alignment
101119pub enum AdcAlign {
102120 /// Left aligned results (most significant bits)
@@ -137,7 +155,7 @@ impl AdcAlign {
137155 }
138156}
139157
140- #[ derive( Debug , PartialEq ) ]
158+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
141159/// ADC Sampling Precision
142160pub enum AdcPrecision {
143161 /// 12 bit precision
@@ -241,6 +259,59 @@ impl VTemp {
241259 pub fn disable ( & mut self , adc : & mut Adc ) {
242260 adc. rb . ccr . modify ( |_, w| w. tsen ( ) . clear_bit ( ) ) ;
243261 }
262+
263+ /// Checks if the temperature sensor is enabled, does not account for the
264+ /// t<sub>START</sub> time however.
265+ pub fn is_enabled ( & self , adc : & Adc ) -> bool {
266+ adc. rb . ccr . read ( ) . tsen ( ) . bit_is_set ( )
267+ }
268+
269+ fn convert_temp ( vtemp : u16 , vdda : u16 ) -> i16 {
270+ let vtemp30_cal = i32:: from ( unsafe { ptr:: read ( VTEMPCAL30 ) } ) * 100 ;
271+ let vtemp110_cal = i32:: from ( unsafe { ptr:: read ( VTEMPCAL110 ) } ) * 100 ;
272+
273+ let mut temperature: i32 = ( vtemp as i32 ) * 100 ;
274+ temperature = ( temperature * ( vdda as i32 ) / ( VDD_CALIB as i32 ) ) - vtemp30_cal;
275+ temperature *= ( 110 - 30 ) * 100 ;
276+ temperature /= vtemp110_cal - vtemp30_cal;
277+ temperature += 3000 ;
278+ temperature as i16
279+ }
280+
281+ /// Read the value of the internal temperature sensor and return the
282+ /// result in 100ths of a degree centigrade.
283+ ///
284+ /// Given a delay reference it will attempt to restrict to the
285+ /// minimum delay needed to ensure a 10 us t<sub>START</sub> value.
286+ /// Otherwise it will approximate the required delay using ADC reads.
287+ pub fn read ( adc : & mut Adc , delay : Option < & mut Delay > ) -> i16 {
288+ let mut vtemp = Self :: new ( ) ;
289+ let vtemp_preenable = vtemp. is_enabled ( & adc) ;
290+
291+ if !vtemp_preenable {
292+ vtemp. enable ( adc) ;
293+
294+ if let Some ( dref) = delay {
295+ dref. delay_us ( 2_u16 ) ;
296+ } else {
297+ // Double read of vdda to allow sufficient startup time for the temp sensor
298+ VRef :: read_vdda ( adc) ;
299+ }
300+ }
301+ let vdda = VRef :: read_vdda ( adc) ;
302+
303+ let prev_cfg = adc. default_cfg ( ) ;
304+
305+ let vtemp_val = adc. read ( & mut vtemp) . unwrap ( ) ;
306+
307+ if !vtemp_preenable {
308+ vtemp. disable ( adc) ;
309+ }
310+
311+ adc. restore_cfg ( prev_cfg) ;
312+
313+ Self :: convert_temp ( vtemp_val, vdda)
314+ }
244315}
245316
246317#[ cfg( feature = "device-selected" ) ]
@@ -259,6 +330,34 @@ impl VRef {
259330 pub fn disable ( & mut self , adc : & mut Adc ) {
260331 adc. rb . ccr . modify ( |_, w| w. vrefen ( ) . clear_bit ( ) ) ;
261332 }
333+
334+ /// Returns if the internal voltage reference is enabled.
335+ pub fn is_enabled ( & self , adc : & Adc ) -> bool {
336+ adc. rb . ccr . read ( ) . vrefen ( ) . bit_is_set ( )
337+ }
338+
339+ /// Reads the value of VDDA in milli-volts
340+ pub fn read_vdda ( adc : & mut Adc ) -> u16 {
341+ let vrefint_cal = u32:: from ( unsafe { ptr:: read ( VREFCAL ) } ) ;
342+ let mut vref = Self :: new ( ) ;
343+
344+ let prev_cfg = adc. default_cfg ( ) ;
345+
346+ let vref_val: u32 = if vref. is_enabled ( & adc) {
347+ adc. read ( & mut vref) . unwrap ( )
348+ } else {
349+ vref. enable ( adc) ;
350+
351+ let ret = adc. read ( & mut vref) . unwrap ( ) ;
352+
353+ vref. disable ( adc) ;
354+ ret
355+ } ;
356+
357+ adc. restore_cfg ( prev_cfg) ;
358+
359+ ( ( VDD_CALIB as u32 ) * vrefint_cal / vref_val) as u16
360+ }
262361}
263362
264363#[ cfg( feature = "stm32f042" ) ]
@@ -288,8 +387,35 @@ impl VBat {
288387 pub fn disable ( & mut self , adc : & mut Adc ) {
289388 adc. rb . ccr . modify ( |_, w| w. vbaten ( ) . clear_bit ( ) ) ;
290389 }
390+
391+ /// Returns if the internal VBat sense is enabled
392+ pub fn is_enabled ( & self , adc : & Adc ) -> bool {
393+ adc. rb . ccr . read ( ) . vbaten ( ) . bit_is_set ( )
394+ }
395+
396+ /// Reads the value of VBat in milli-volts
397+ pub fn read ( adc : & mut Adc ) -> u16 {
398+ let mut vbat = Self :: new ( ) ;
399+
400+ let vbat_val: u16 = if vbat. is_enabled ( & adc) {
401+ adc. read_abs_mv ( & mut vbat)
402+ } else {
403+ vbat. enable ( adc) ;
404+
405+ let ret = adc. read_abs_mv ( & mut vbat) ;
406+
407+ vbat. disable ( adc) ;
408+ ret
409+ } ;
410+
411+ vbat_val * 2
412+ }
291413}
292414
415+ /// A stored ADC config, can be restored by using the `Adc::restore_cfg` method
416+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
417+ pub struct StoredConfig ( AdcSampleTime , AdcAlign , AdcPrecision ) ;
418+
293419#[ cfg( feature = "device-selected" ) ]
294420impl Adc {
295421 /// Init a new Adc
@@ -309,6 +435,28 @@ impl Adc {
309435 s
310436 }
311437
438+ /// Saves a copy of the current ADC config
439+ pub fn save_cfg ( & mut self ) -> StoredConfig {
440+ StoredConfig ( self . sample_time , self . align , self . precision )
441+ }
442+
443+ /// Restores a stored config
444+ pub fn restore_cfg ( & mut self , cfg : StoredConfig ) {
445+ self . sample_time = cfg. 0 ;
446+ self . align = cfg. 1 ;
447+ self . precision = cfg. 2 ;
448+ }
449+
450+ /// Resets the ADC config to default, returning the existing config as
451+ /// a stored config.
452+ pub fn default_cfg ( & mut self ) -> StoredConfig {
453+ let cfg = self . save_cfg ( ) ;
454+ self . sample_time = AdcSampleTime :: default ( ) ;
455+ self . align = AdcAlign :: default ( ) ;
456+ self . precision = AdcPrecision :: default ( ) ;
457+ cfg
458+ }
459+
312460 /// Set the Adc sampling time
313461 ///
314462 /// Options can be found in [AdcSampleTime](crate::adc::AdcSampleTime).
@@ -330,6 +478,32 @@ impl Adc {
330478 self . precision = precision;
331479 }
332480
481+ /// Returns the largest possible sample value for the current settings
482+ pub fn max_sample ( & self ) -> u16 {
483+ match self . align {
484+ AdcAlign :: Left => u16:: max_value ( ) ,
485+ AdcAlign :: LeftAsRM => match self . precision {
486+ AdcPrecision :: B_6 => u8:: max_value ( ) as u16 ,
487+ _ => u16:: max_value ( ) ,
488+ } ,
489+ AdcAlign :: Right => match self . precision {
490+ AdcPrecision :: B_12 => ( 1 << 12 ) - 1 ,
491+ AdcPrecision :: B_10 => ( 1 << 10 ) - 1 ,
492+ AdcPrecision :: B_8 => ( 1 << 8 ) - 1 ,
493+ AdcPrecision :: B_6 => ( 1 << 6 ) - 1 ,
494+ } ,
495+ }
496+ }
497+
498+ /// Read the value of a channel and converts the result to milli-volts
499+ pub fn read_abs_mv < PIN : Channel < Adc , ID = u8 > > ( & mut self , pin : & mut PIN ) -> u16 {
500+ let vdda = VRef :: read_vdda ( self ) as u32 ;
501+ let v: u32 = self . read ( pin) . unwrap ( ) ;
502+ let max_samp = self . max_sample ( ) as u32 ;
503+
504+ ( v * vdda / max_samp) as u16
505+ }
506+
333507 fn calibrate ( & mut self ) {
334508 /* Ensure that ADEN = 0 */
335509 if self . rb . cr . read ( ) . aden ( ) . bit_is_set ( ) {
0 commit comments