1
1
//! # Analog to Digital converter
2
2
3
3
use core:: convert:: Infallible ;
4
+ use core:: ptr;
4
5
5
6
use crate :: {
6
7
gpio:: Analog ,
@@ -33,6 +34,9 @@ impl ADC {
33
34
ccipr : & mut CCIPR ,
34
35
delay : & mut impl DelayUs < u32 > ,
35
36
) -> Self {
37
+ // Enable peripheral
38
+ ahb. enr ( ) . modify ( |_, w| w. adcen ( ) . set_bit ( ) ) ;
39
+
36
40
// Reset peripheral
37
41
ahb. rstr ( ) . modify ( |_, w| w. adcrst ( ) . set_bit ( ) ) ;
38
42
ahb. rstr ( ) . modify ( |_, w| w. adcrst ( ) . clear_bit ( ) ) ;
@@ -47,22 +51,16 @@ impl ADC {
47
51
w
48
52
} ) ;
49
53
50
- // Enable peripheral
51
- ahb. enr ( ) . modify ( |_, w| w. adcen ( ) . set_bit ( ) ) ;
52
-
53
54
// Initialize the ADC, according to the STM32L4xx Reference Manual,
54
55
// section 16.4.6.
55
- inner. cr . write ( |w| {
56
- w. deeppwd ( ) . clear_bit ( ) ; // exit deep-power-down mode
57
- w. advregen ( ) . set_bit ( ) ; // enable internal voltage regulator
58
-
59
- w
60
- } ) ;
56
+ inner. cr . write ( |w| w. deeppwd ( ) . clear_bit ( ) ) ; // exit deep-power-down mode
57
+ inner. cr . modify ( |_, w| w. advregen ( ) . set_bit ( ) ) ; // enable internal voltage regulator
61
58
62
59
// According to the STM32L4xx Reference Manual, section 16.4.6, we need
63
60
// to wait for T_ADCVREG_STUP after enabling the internal voltage
64
- // regulator. For the STM32L433, this is 20 us.
65
- delay. delay_us ( 20 ) ;
61
+ // regulator. For the STM32L433, this is 20 us. We choose 25 us to
62
+ // account for bad clocks.
63
+ delay. delay_us ( 25 ) ;
66
64
67
65
// Calibration procedure according to section 16.4.8.
68
66
inner. cr . modify ( |_, w| {
@@ -71,8 +69,12 @@ impl ADC {
71
69
72
70
w
73
71
} ) ;
72
+
74
73
while inner. cr . read ( ) . adcal ( ) . bit_is_set ( ) { }
75
74
75
+ // We need to wait 4 ADC clock after ADCAL goes low, 1 us is more than enough
76
+ delay. delay_us ( 1 ) ;
77
+
76
78
Self {
77
79
inner,
78
80
resolution : Resolution :: default ( ) ,
@@ -106,6 +108,9 @@ where
106
108
type Error = Infallible ;
107
109
108
110
fn read ( & mut self , channel : & mut C ) -> nb:: Result < u16 , Self :: Error > {
111
+ // Make sure bits are off
112
+ while self . inner . cr . read ( ) . addis ( ) . bit_is_set ( ) { }
113
+
109
114
// Enable ADC
110
115
self . inner . isr . write ( |w| w. adrdy ( ) . set_bit ( ) ) ;
111
116
self . inner . cr . modify ( |_, w| w. aden ( ) . set_bit ( ) ) ;
@@ -132,7 +137,20 @@ where
132
137
} ) ;
133
138
134
139
// Start conversion
135
- self . inner . isr . modify ( |_, w| w. eos ( ) . set_bit ( ) ) ;
140
+ self . inner
141
+ . isr
142
+ . modify ( |_, w| w. eos ( ) . set_bit ( ) . eoc ( ) . set_bit ( ) ) ;
143
+ self . inner . cr . modify ( |_, w| w. adstart ( ) . set_bit ( ) ) ;
144
+ while self . inner . isr . read ( ) . eos ( ) . bit_is_clear ( ) { }
145
+
146
+ // Read ADC value first time and discard it, as per errata sheet.
147
+ // The errata states that if we do conversions slower than 1 kHz, the
148
+ // first read ADC value can be corrupted, so we discard it and measure again.
149
+ let _ = unsafe { ptr:: read_volatile ( & self . inner . dr . read ( ) . bits ( ) ) } ;
150
+
151
+ self . inner
152
+ . isr
153
+ . modify ( |_, w| w. eos ( ) . set_bit ( ) . eoc ( ) . set_bit ( ) ) ;
136
154
self . inner . cr . modify ( |_, w| w. adstart ( ) . set_bit ( ) ) ;
137
155
while self . inner . isr . read ( ) . eos ( ) . bit_is_clear ( ) { }
138
156
0 commit comments