Skip to content

Commit a1f9055

Browse files
authored
Fixed so the ADC driver is working on STM32L412 as well (#181)
1 parent 730d74f commit a1f9055

File tree

1 file changed

+30
-12
lines changed

1 file changed

+30
-12
lines changed

src/adc.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! # Analog to Digital converter
22
33
use core::convert::Infallible;
4+
use core::ptr;
45

56
use crate::{
67
gpio::Analog,
@@ -33,6 +34,9 @@ impl ADC {
3334
ccipr: &mut CCIPR,
3435
delay: &mut impl DelayUs<u32>,
3536
) -> Self {
37+
// Enable peripheral
38+
ahb.enr().modify(|_, w| w.adcen().set_bit());
39+
3640
// Reset peripheral
3741
ahb.rstr().modify(|_, w| w.adcrst().set_bit());
3842
ahb.rstr().modify(|_, w| w.adcrst().clear_bit());
@@ -47,22 +51,16 @@ impl ADC {
4751
w
4852
});
4953

50-
// Enable peripheral
51-
ahb.enr().modify(|_, w| w.adcen().set_bit());
52-
5354
// Initialize the ADC, according to the STM32L4xx Reference Manual,
5455
// 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
6158

6259
// According to the STM32L4xx Reference Manual, section 16.4.6, we need
6360
// 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);
6664

6765
// Calibration procedure according to section 16.4.8.
6866
inner.cr.modify(|_, w| {
@@ -71,8 +69,12 @@ impl ADC {
7169

7270
w
7371
});
72+
7473
while inner.cr.read().adcal().bit_is_set() {}
7574

75+
// We need to wait 4 ADC clock after ADCAL goes low, 1 us is more than enough
76+
delay.delay_us(1);
77+
7678
Self {
7779
inner,
7880
resolution: Resolution::default(),
@@ -106,6 +108,9 @@ where
106108
type Error = Infallible;
107109

108110
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+
109114
// Enable ADC
110115
self.inner.isr.write(|w| w.adrdy().set_bit());
111116
self.inner.cr.modify(|_, w| w.aden().set_bit());
@@ -132,7 +137,20 @@ where
132137
});
133138

134139
// 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());
136154
self.inner.cr.modify(|_, w| w.adstart().set_bit());
137155
while self.inner.isr.read().eos().bit_is_clear() {}
138156

0 commit comments

Comments
 (0)