aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/adc/v1.rs116
1 files changed, 62 insertions, 54 deletions
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 224d17178..f787f72ac 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -48,25 +48,33 @@ impl Resolution {
48 } 48 }
49} 49}
50 50
51pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
52
53mod sealed {
54 pub trait InternalChannel<T> {
55 fn channel(&self) -> u8;
56 }
57}
58
51pub struct Vbat; 59pub struct Vbat;
52impl<T: Instance> AdcPin<T> for Vbat {} 60impl<T: Instance> InternalChannel<T> for Vbat {}
53impl<T: Instance> super::sealed::AdcPin<T> for Vbat { 61impl<T: Instance> sealed::InternalChannel<T> for Vbat {
54 fn channel(&self) -> u8 { 62 fn channel(&self) -> u8 {
55 18 63 18
56 } 64 }
57} 65}
58 66
59pub struct Vref; 67pub struct Vref;
60impl<T: Instance> AdcPin<T> for Vref {} 68impl<T: Instance> InternalChannel<T> for Vref {}
61impl<T: Instance> super::sealed::AdcPin<T> for Vref { 69impl<T: Instance> sealed::InternalChannel<T> for Vref {
62 fn channel(&self) -> u8 { 70 fn channel(&self) -> u8 {
63 17 71 17
64 } 72 }
65} 73}
66 74
67pub struct Temperature; 75pub struct Temperature;
68impl<T: Instance> AdcPin<T> for Temperature {} 76impl<T: Instance> InternalChannel<T> for Temperature {}
69impl<T: Instance> super::sealed::AdcPin<T> for Temperature { 77impl<T: Instance> sealed::InternalChannel<T> for Temperature {
70 fn channel(&self) -> u8 { 78 fn channel(&self) -> u8 {
71 16 79 16
72 } 80 }
@@ -219,64 +227,64 @@ impl<'d, T: Instance> Adc<'d, T> {
219 ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 227 ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
220 } 228 }
221 229
222 fn convert(&mut self) -> u16 {
223 unsafe {
224 T::regs().isr().modify(|reg| {
225 reg.set_eoc(true);
226 reg.set_eosmp(true);
227 });
228
229 // A.7.5 Single conversion sequence code example - Software trigger
230 T::regs().cr().modify(|reg| reg.set_adstart(true));
231 while !T::regs().isr().read().eoc() {
232 // spin
233 }
234
235 T::regs().dr().read().0 as u16
236 }
237 }
238
239 pub fn read<P>(&mut self, pin: &mut P) -> u16 230 pub fn read<P>(&mut self, pin: &mut P) -> u16
240 where 231 where
241 P: AdcPin<T> + crate::gpio::sealed::Pin, 232 P: AdcPin<T> + crate::gpio::sealed::Pin,
242 { 233 {
234 let channel = pin.channel();
243 unsafe { 235 unsafe {
244 // A.7.2 ADC enable sequence code example
245 if T::regs().isr().read().adrdy() {
246 T::regs().isr().modify(|reg| reg.set_adrdy(true));
247 }
248 T::regs().cr().modify(|reg| reg.set_aden(true));
249 while !T::regs().isr().read().adrdy() {
250 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
251 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
252 // ADEN bit until the ADRDY flag goes high.
253 T::regs().cr().modify(|reg| reg.set_aden(true));
254 }
255
256 T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res()));
257 Self::set_channel_sample_time(pin.channel(), self.sample_time);
258 pin.set_as_analog(); 236 pin.set_as_analog();
259 T::regs() 237 self.read_channel(channel)
260 .chselr() 238 }
261 .write(|reg| reg.set_chselx(pin.channel() as usize, true)); 239 }
262 240
263 let value = self.convert(); 241 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
242 let channel = channel.channel();
243 unsafe {
244 self.read_channel(channel)
245 }
246 }
264 247
265 // A.7.3 ADC disable code example 248 unsafe fn read_channel(&mut self, channel: u8) -> u16 {
266 T::regs().cr().modify(|reg| reg.set_adstp(true)); 249 // A.7.2 ADC enable sequence code example
267 while T::regs().cr().read().adstp() { 250 if T::regs().isr().read().adrdy() {
268 // spin 251 T::regs().isr().modify(|reg| reg.set_adrdy(true));
269 } 252 }
270 T::regs().cr().modify(|reg| reg.set_addis(true)); 253 T::regs().cr().modify(|reg| reg.set_aden(true));
271 while T::regs().cr().read().aden() { 254 while !T::regs().isr().read().adrdy() {
272 // spin 255 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
273 } 256 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
257 // ADEN bit until the ADRDY flag goes high.
258 T::regs().cr().modify(|reg| reg.set_aden(true));
259 }
274 260
275 value 261 T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res()));
262 T::regs().isr().modify(|reg| {
263 reg.set_eoc(true);
264 reg.set_eosmp(true);
265 });
266
267 // A.7.5 Single conversion sequence code example - Software trigger
268 T::regs()
269 .chselr()
270 .write(|reg| reg.set_chselx(channel as usize, true));
271 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.sample_time()));
272 T::regs().cr().modify(|reg| reg.set_adstart(true));
273 while !T::regs().isr().read().eoc() {
274 // spin
275 }
276 let value = T::regs().dr().read().0 as u16;
277
278 // A.7.3 ADC disable code example
279 T::regs().cr().modify(|reg| reg.set_adstp(true));
280 while T::regs().cr().read().adstp() {
281 // spin
282 }
283 T::regs().cr().modify(|reg| reg.set_addis(true));
284 while T::regs().cr().read().aden() {
285 // spin
276 } 286 }
277 }
278 287
279 unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 288 value
280 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.sample_time()));
281 } 289 }
282} 290}