diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-02-13 11:44:59 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-02-13 11:44:59 +0000 |
| commit | eb922c4655db4b22acf808855e3bc003d3b8ba89 (patch) | |
| tree | 996cc09254953299cb310285bf05195774be5441 | |
| parent | b74ccf2d348e9bba1e201e196381f772197e3257 (diff) | |
| parent | 7a3d34c1ed3db330c6db55b81cd535747181c3cb (diff) | |
Merge #608
608: stm32f4: add adc + example r=Dirbaio a=ain101
Example tested on stm32f407vg Discovery Board.
minimal adc: no vref, dma, complex sequence
Co-authored-by: Frederik <[email protected]>
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 239 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/adc.rs | 26 |
2 files changed, 265 insertions, 0 deletions
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 8b1378917..e79680493 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -1 +1,240 @@ | |||
| 1 | use crate::adc::{AdcPin, Instance}; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use embassy::util::Unborrow; | ||
| 4 | use embassy_hal_common::unborrow; | ||
| 5 | use embedded_hal_02::blocking::delay::DelayUs; | ||
| 1 | 6 | ||
| 7 | pub const VDDA_CALIB_MV: u32 = 3000; | ||
| 8 | |||
| 9 | #[cfg(not(rcc_f4))] | ||
| 10 | unsafe fn enable() { | ||
| 11 | todo!() | ||
| 12 | } | ||
| 13 | |||
| 14 | #[cfg(rcc_f4)] | ||
| 15 | unsafe fn enable() { | ||
| 16 | // TODO do not enable all adc clocks if not needed | ||
| 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adc1en(true)); | ||
| 18 | crate::pac::RCC.apb2enr().modify(|w| w.set_adc2en(true)); | ||
| 19 | crate::pac::RCC.apb2enr().modify(|w| w.set_adc3en(true)); | ||
| 20 | } | ||
| 21 | |||
| 22 | pub enum Resolution { | ||
| 23 | TwelveBit, | ||
| 24 | TenBit, | ||
| 25 | EightBit, | ||
| 26 | SixBit, | ||
| 27 | } | ||
| 28 | |||
| 29 | impl Default for Resolution { | ||
| 30 | fn default() -> Self { | ||
| 31 | Self::TwelveBit | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | impl Resolution { | ||
| 36 | fn res(&self) -> crate::pac::adc::vals::Res { | ||
| 37 | match self { | ||
| 38 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, | ||
| 39 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, | ||
| 40 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, | ||
| 41 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | fn to_max_count(&self) -> u32 { | ||
| 46 | match self { | ||
| 47 | Resolution::TwelveBit => (1 << 12) - 1, | ||
| 48 | Resolution::TenBit => (1 << 10) - 1, | ||
| 49 | Resolution::EightBit => (1 << 8) - 1, | ||
| 50 | Resolution::SixBit => (1 << 6) - 1, | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | pub struct Vref; | ||
| 56 | impl<T: Instance> AdcPin<T> for Vref {} | ||
| 57 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | ||
| 58 | fn channel(&self) -> u8 { | ||
| 59 | 17 | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | pub struct Temperature; | ||
| 64 | impl<T: Instance> AdcPin<T> for Temperature {} | ||
| 65 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | ||
| 66 | fn channel(&self) -> u8 { | ||
| 67 | 16 | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | pub struct Vbat; | ||
| 72 | impl<T: Instance> AdcPin<T> for Vbat {} | ||
| 73 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { | ||
| 74 | fn channel(&self) -> u8 { | ||
| 75 | 18 | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | /// ADC sample time | ||
| 80 | /// | ||
| 81 | /// The default setting is 3 ADC clock cycles. | ||
| 82 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] | ||
| 83 | pub enum SampleTime { | ||
| 84 | Cycles3 = 0b000, | ||
| 85 | Cycles15 = 0b001, | ||
| 86 | Cycles28 = 0b010, | ||
| 87 | Cycles56 = 0b011, | ||
| 88 | Cycles85 = 0b100, | ||
| 89 | Cycles112 = 0b101, | ||
| 90 | Cycles144 = 0b110, | ||
| 91 | Cycles480 = 0b111, | ||
| 92 | } | ||
| 93 | |||
| 94 | impl SampleTime { | ||
| 95 | pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp { | ||
| 96 | match self { | ||
| 97 | SampleTime::Cycles3 => crate::pac::adc::vals::Smp::CYCLES3, | ||
| 98 | SampleTime::Cycles15 => crate::pac::adc::vals::Smp::CYCLES15, | ||
| 99 | SampleTime::Cycles28 => crate::pac::adc::vals::Smp::CYCLES28, | ||
| 100 | SampleTime::Cycles56 => crate::pac::adc::vals::Smp::CYCLES56, | ||
| 101 | SampleTime::Cycles85 => crate::pac::adc::vals::Smp::CYCLES84, | ||
| 102 | SampleTime::Cycles112 => crate::pac::adc::vals::Smp::CYCLES112, | ||
| 103 | SampleTime::Cycles144 => crate::pac::adc::vals::Smp::CYCLES144, | ||
| 104 | SampleTime::Cycles480 => crate::pac::adc::vals::Smp::CYCLES480, | ||
| 105 | } | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | impl Default for SampleTime { | ||
| 110 | fn default() -> Self { | ||
| 111 | Self::Cycles3 | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | pub struct Adc<'d, T: Instance> { | ||
| 116 | sample_time: SampleTime, | ||
| 117 | calibrated_vdda: u32, | ||
| 118 | resolution: Resolution, | ||
| 119 | phantom: PhantomData<&'d mut T>, | ||
| 120 | } | ||
| 121 | |||
| 122 | impl<'d, T> Adc<'d, T> | ||
| 123 | where | ||
| 124 | T: Instance, | ||
| 125 | { | ||
| 126 | pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | ||
| 127 | unborrow!(_peri); | ||
| 128 | unsafe { | ||
| 129 | enable(); | ||
| 130 | // disable before config is set | ||
| 131 | T::regs().cr2().modify(|reg| { | ||
| 132 | reg.set_adon(crate::pac::adc::vals::Adon::DISABLED); | ||
| 133 | }); | ||
| 134 | } | ||
| 135 | |||
| 136 | delay.delay_us(20); // TODO? | ||
| 137 | |||
| 138 | Self { | ||
| 139 | sample_time: Default::default(), | ||
| 140 | resolution: Resolution::default(), | ||
| 141 | calibrated_vdda: VDDA_CALIB_MV, | ||
| 142 | phantom: PhantomData, | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | ||
| 147 | self.sample_time = sample_time; | ||
| 148 | } | ||
| 149 | |||
| 150 | pub fn set_resolution(&mut self, resolution: Resolution) { | ||
| 151 | self.resolution = resolution; | ||
| 152 | } | ||
| 153 | |||
| 154 | /// Convert a measurement to millivolts | ||
| 155 | pub fn to_millivolts(&self, sample: u16) -> u16 { | ||
| 156 | ((u32::from(sample) * self.calibrated_vdda) / self.resolution.to_max_count()) as u16 | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Perform a single conversion. | ||
| 160 | fn convert(&mut self) -> u16 { | ||
| 161 | unsafe { | ||
| 162 | // clear end of conversion flag | ||
| 163 | T::regs().sr().modify(|reg| { | ||
| 164 | reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); | ||
| 165 | }); | ||
| 166 | |||
| 167 | // Start conversion | ||
| 168 | T::regs().cr2().modify(|reg| { | ||
| 169 | reg.set_swstart(true); | ||
| 170 | }); | ||
| 171 | |||
| 172 | while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { | ||
| 173 | // spin //wait for actual start | ||
| 174 | } | ||
| 175 | while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE { | ||
| 176 | // spin //wait for finish | ||
| 177 | } | ||
| 178 | |||
| 179 | T::regs().dr().read().0 as u16 | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | ||
| 184 | where | ||
| 185 | P: AdcPin<T>, | ||
| 186 | P: crate::gpio::sealed::Pin, | ||
| 187 | { | ||
| 188 | unsafe { | ||
| 189 | // dissable ADC | ||
| 190 | T::regs().cr2().modify(|reg| { | ||
| 191 | reg.set_swstart(false); | ||
| 192 | }); | ||
| 193 | T::regs().cr2().modify(|reg| { | ||
| 194 | reg.set_adon(crate::pac::adc::vals::Adon::DISABLED); | ||
| 195 | }); | ||
| 196 | |||
| 197 | pin.set_as_analog(); | ||
| 198 | |||
| 199 | // Configure ADC | ||
| 200 | T::regs() | ||
| 201 | .cr1() | ||
| 202 | .modify(|reg| reg.set_res(self.resolution.res())); | ||
| 203 | |||
| 204 | // Select channel | ||
| 205 | T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); | ||
| 206 | |||
| 207 | // Configure channel | ||
| 208 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||
| 209 | |||
| 210 | // enable adc | ||
| 211 | T::regs().cr2().modify(|reg| { | ||
| 212 | reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); | ||
| 213 | }); | ||
| 214 | |||
| 215 | let val = self.convert(); | ||
| 216 | |||
| 217 | // dissable ADC | ||
| 218 | T::regs().cr2().modify(|reg| { | ||
| 219 | reg.set_swstart(false); | ||
| 220 | }); | ||
| 221 | T::regs().cr2().modify(|reg| { | ||
| 222 | reg.set_adon(crate::pac::adc::vals::Adon::DISABLED); | ||
| 223 | }); | ||
| 224 | |||
| 225 | val | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||
| 230 | if ch <= 9 { | ||
| 231 | T::regs() | ||
| 232 | .smpr2() | ||
| 233 | .modify(|reg| reg.set_smp(ch as _, sample_time.sample_time())); | ||
| 234 | } else { | ||
| 235 | T::regs() | ||
| 236 | .smpr1() | ||
| 237 | .modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time())); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs new file mode 100644 index 000000000..0a6ddbbca --- /dev/null +++ b/examples/stm32f4/src/bin/adc.rs | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | |||
| 8 | use embassy::executor::Spawner; | ||
| 9 | use embassy::time::{Delay, Duration, Timer}; | ||
| 10 | use embassy_stm32::adc::Adc; | ||
| 11 | use embassy_stm32::Peripherals; | ||
| 12 | use example_common::*; | ||
| 13 | |||
| 14 | #[embassy::main] | ||
| 15 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 16 | info!("Hello World!"); | ||
| 17 | |||
| 18 | let mut adc = Adc::new(p.ADC1, &mut Delay); | ||
| 19 | let mut pin = p.PC1; | ||
| 20 | |||
| 21 | loop { | ||
| 22 | let v = adc.read(&mut pin); | ||
| 23 | info!("--> {} - {} mV", v, adc.to_millivolts(v)); | ||
| 24 | Timer::after(Duration::from_millis(100)).await; | ||
| 25 | } | ||
| 26 | } | ||
