Skip to content

Commit 2d59e5b

Browse files
committed
ADC: Add free() function and fix enable disable functions
1 parent da62a18 commit 2d59e5b

File tree

4 files changed

+81
-61
lines changed

4 files changed

+81
-61
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1818
- Support for GPIO interrupts ([#189])
1919
- `ld` feature, which enables the memory.x generation ([#216])
2020
- Implement `DelayMs` for `Milliseconds` and `DelayUs` for `Microseconds` ([#234])
21+
- ADC can now be `free()`'d ([#212])
2122

2223
### Changed
2324

@@ -329,6 +330,7 @@ let clocks = rcc
329330
[#220]: https://github.com/stm32-rs/stm32f3xx-hal/pull/220
330331
[#217]: https://github.com/stm32-rs/stm32f3xx-hal/pull/217
331332
[#216]: https://github.com/stm32-rs/stm32f3xx-hal/pull/216
333+
[#212]: https://github.com/stm32-rs/stm32f3xx-hal/pull/212
332334
[#210]: https://github.com/stm32-rs/stm32f3xx-hal/pull/210
333335
[#208]: https://github.com/stm32-rs/stm32f3xx-hal/pull/208
334336
[#203]: https://github.com/stm32-rs/stm32f3xx-hal/issues/203

examples/adc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ fn main() -> ! {
3232

3333
// Set up pin PA0 as analog pin.
3434
// This pin is connected to the user button on the stm32f3discovery board.
35-
let mut gpio_a = dp.GPIOA.split(&mut rcc.ahb);
36-
let mut adc1_in1_pin = gpio_a.pa0.into_analog(&mut gpio_a.moder, &mut gpio_a.pupdr);
35+
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
36+
let mut adc1_in1_pin = gpioa.pa0.into_analog(&mut gpioa.moder, &mut gpioa.pupdr);
3737

3838
// Be aware that the values in the table below depend on the input of VREF.
3939
// To have a stable VREF input, put a condensator and a volt limiting diode in front of it.

src/adc.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ macro_rules! adc_hal {
339339
this_adc
340340
}
341341

342+
/// Releases the ADC peripheral and associated pins
343+
pub fn free(mut self) -> $ADC {
344+
self.disable();
345+
self.rb
346+
}
347+
342348
/// Software can use CkMode::SYNCDIV1 only if
343349
/// hclk and sysclk are the same. (see reference manual 15.3.3)
344350
fn clocks_welldefined(&self, clocks: Clocks) -> bool {
@@ -373,16 +379,47 @@ macro_rules! adc_hal {
373379
self.rb.cfgr.modify(|_, w| w.align().variant(align.into()));
374380
}
375381

382+
/// Software procedure to enable the ADC
383+
/// According to RM0316 15.3.9
376384
fn enable(&mut self) {
377-
self.rb.cr.modify(|_, w| w.aden().enable());
378-
while self.rb.isr.read().adrdy().is_not_ready() {}
385+
// This check assumes, that the ADC was enabled before and it was waited until
386+
// ADRDY=1 was set.
387+
// This assumption is true, if the peripheral was initially enabled through
388+
// this method.
389+
if !self.rb.cr.read().aden().is_enable() {
390+
// Set ADEN=1
391+
self.rb.cr.modify(|_, w| w.aden().enable());
392+
// Wait until ADRDY=1 (ADRDY is set after the ADC startup time). This can be
393+
// done using the associated interrupt (setting ADRDYIE=1).
394+
while self.rb.isr.read().adrdy().is_not_ready() {}
395+
}
379396
}
380397

398+
/// Disable according to RM0316 15.3.9
381399
fn disable(&mut self) {
382-
self.rb.cr.modify(|_, w| w.addis().disable());
400+
// NOTE: Software is allowed to set ADSTP only when ADSTART=1 and ADDIS=0
401+
// (ADC is enabled and eventually converting a regular conversion and there is no
402+
// pending request to disable the ADC)
403+
if self.rb.cr.read().addis().bit() == false
404+
&& (self.rb.cr.read().adstart().bit() || self.rb.cr.read().jadstart().bit()) {
405+
self.rb.cr.modify(|_, w| w.adstp().stop());
406+
// NOTE: In auto-injection mode (JAUTO=1), setting ADSTP bit aborts both
407+
// regular and injected conversions (do not use JADSTP)
408+
if !self.rb.cfgr.read().jauto().is_enabled() {
409+
self.rb.cr.modify(|_, w| w.jadstp().stop());
410+
}
411+
while self.rb.cr.read().adstp().bit() || self.rb.cr.read().jadstp().bit() { }
412+
}
413+
414+
// NOTE: Software is allowed to set ADDIS only when ADEN=1 and both ADSTART=0
415+
// and JADSTART=0 (which ensures that no conversion is ongoing)
416+
if self.rb.cr.read().aden().is_enable() {
417+
self.rb.cr.modify(|_, w| w.addis().disable());
418+
while self.rb.cr.read().addis().bit() { }
419+
}
383420
}
384421

385-
/// Calibrate according to 15.3.8 in the Reference Manual
422+
/// Calibrate according to RM0316 15.3.8
386423
fn calibrate(&mut self) {
387424
if !self.rb.cr.read().advregen().is_enabled() {
388425
self.advregen_enable();
@@ -425,7 +462,9 @@ macro_rules! adc_hal {
425462

426463
/// busy ADC read
427464
fn convert_one(&mut self, chan: u8) -> u16 {
428-
self.ensure_oneshot();
465+
if self.operation_mode != Some(OperationMode::OneShot) {
466+
self.setup_oneshot();
467+
}
429468
self.set_chan_smps(chan, SampleTime::default());
430469
self.select_single_chan(chan);
431470

@@ -435,12 +474,6 @@ macro_rules! adc_hal {
435474
return self.rb.dr.read().rdata().bits();
436475
}
437476

438-
fn ensure_oneshot(&mut self) {
439-
if self.operation_mode != Some(OperationMode::OneShot) {
440-
self.setup_oneshot();
441-
}
442-
}
443-
444477
/// This should only be invoked with the defined channels for the particular
445478
/// device. (See Pin/Channel mapping above)
446479
fn select_single_chan(&self, chan: u8) {
@@ -477,15 +510,16 @@ macro_rules! adc_hal {
477510

478511
}
479512

480-
impl<WORD, PIN> OneShot<$ADC, WORD, PIN> for Adc<$ADC>
513+
impl<Word, Pin> OneShot<$ADC, Word, Pin> for Adc<$ADC>
481514
where
482-
WORD: From<u16>,
483-
PIN: Channel<$ADC, ID = u8>,
515+
Word: From<u16>,
516+
Pin: Channel<$ADC, ID = u8>,
484517
{
485518
type Error = ();
486519

487-
fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
488-
let res = self.convert_one(PIN::channel());
520+
fn read(&mut self, _pin: &mut Pin) -> nb::Result<Word, Self::Error> {
521+
// TODO: Convert back to previous mode after use.
522+
let res = self.convert_one(Pin::channel());
489523
return Ok(res.into());
490524
}
491525
}

testsuite/tests/adc.rs

Lines changed: 27 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#![no_std]
22
#![no_main]
33

4-
// TODO: Get pa9 and pa10 because these also implement spi and uart
54
use defmt_rtt as _;
65
use panic_probe as _;
76

@@ -11,37 +10,25 @@ use hal::adc;
1110
use hal::gpio::{Analog, Output, PushPull};
1211
use hal::pac;
1312
use hal::prelude::*;
14-
use hal::serial::{Rx, Serial, Tx};
1513
use hal::{
16-
gpio::{
17-
gpioa::{PA10, PA2, PA3, PA9},
18-
gpiob::{PB10, PB11},
19-
gpioc::{PC0, PC1},
20-
},
14+
gpio::gpioc::{PC0, PC1},
2115
pac::ADC1_2,
22-
rcc::{Clocks, Rcc, AHB},
16+
rcc::{Clocks, AHB},
2317
};
2418

25-
use core::array::IntoIter;
26-
27-
use hal::serial::Error;
28-
2919
struct State {
3020
adc: Option<adc::Adc<pac::ADC1>>,
3121
analog: PC0<Analog>,
3222
output: PC1<Output<PushPull>>,
3323
ahb: AHB,
34-
flash: hal::flash::Parts,
3524
clocks: Clocks,
3625
adc1_2: ADC1_2,
3726
}
3827

39-
const TEST_MSG: [u8; 8] = [0xD, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF];
40-
4128
#[defmt_test::tests]
4229
mod tests {
4330
use super::*;
44-
use defmt::{self, assert, assert_eq, unwrap};
31+
use defmt::{self, assert, unwrap};
4532

4633
#[init]
4734
fn init() -> State {
@@ -54,9 +41,7 @@ mod tests {
5441

5542
State {
5643
adc: Some(adc::Adc::adc1(
57-
dp.ADC1, // The ADC we are going to control
58-
// The following is only needed to make sure the clock signal for the ADC is set up
59-
// correctly.
44+
dp.ADC1,
6045
&mut dp.ADC1_2,
6146
&mut rcc.ahb,
6247
adc::CkMode::default(),
@@ -67,7 +52,6 @@ mod tests {
6752
.pc1
6853
.into_push_pull_output(&mut gpioc.moder, &mut gpioc.otyper),
6954
ahb: rcc.ahb,
70-
flash,
7155
clocks,
7256
adc1_2: dp.ADC1_2,
7357
}
@@ -76,40 +60,40 @@ mod tests {
7660
#[test]
7761
fn measure_pin_high_low(state: &mut State) {
7862
let mut adc = defmt::unwrap!(state.adc.take());
79-
for _ in 1..10 {
63+
for _ in 0..10 {
8064
defmt::unwrap!(state.output.set_high());
8165
let adc_level: u16 = defmt::unwrap!(adc.read(&mut state.analog).ok());
8266
defmt::info!("{}", adc_level);
8367
defmt::unwrap!(state.output.set_low());
8468
// Vref is 3V so output should reach the maximum.
85-
defmt::assert!(adc_level >= 4070 && adc_level <= 4100);
69+
assert!(adc_level >= 3900 && adc_level <= 4100);
8670
let adc_level: u16 = defmt::unwrap!(adc.read(&mut state.analog).ok());
8771
defmt::info!("{}", adc_level);
88-
defmt::assert_eq!(adc_level, 0);
72+
// nearly zero (always zero can not be guaranteed)
73+
assert!(adc_level <= 100);
8974
}
9075

9176
// put adc back in place
9277
state.adc.replace(adc);
9378
}
9479

95-
// #[test]
96-
// fn free_and_reconfigure(state: &mut State) {
97-
// let mut adc = defmt::unwrap!(state.adc.take());
98-
// defmt::debug!("Free");
99-
// let adc1 = adc.free();
100-
101-
// // FIXME: This is not working (stuck on this function)
102-
// defmt::debug!("Reconfigure");
103-
// let new_adc = adc::Adc::adc1(
104-
// adc1,
105-
// &mut state.adc1_2,
106-
// &mut state.ahb,
107-
// adc::CkMode::default(),
108-
// state.clocks,
109-
// );
110-
111-
// defmt::debug!("Replace");
112-
// // put adc back in place
113-
// state.adc.replace(new_adc);
114-
// }
80+
#[test]
81+
fn free_and_reconfigure(state: &mut State) {
82+
let adc = defmt::unwrap!(state.adc.take());
83+
defmt::debug!("Free");
84+
let adc1 = adc.free();
85+
86+
defmt::debug!("Reconfigure");
87+
let new_adc = adc::Adc::adc1(
88+
adc1,
89+
&mut state.adc1_2,
90+
&mut state.ahb,
91+
adc::CkMode::default(),
92+
state.clocks,
93+
);
94+
95+
defmt::debug!("Replace");
96+
// put adc back in place
97+
state.adc.replace(new_adc);
98+
}
11599
}

0 commit comments

Comments
 (0)