aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSjoerd Simons <[email protected]>2021-12-30 10:51:49 +0100
committerSjoerd Simons <[email protected]>2021-12-30 10:51:54 +0100
commit92f2c6d09c3bd2d11d8a5c7a56bd4208f9720895 (patch)
tree94b465d9b1dafbdbd51e9382103d2934bfc9f972
parenta93b1141e9ebcddc1286fe8b752db9fc7f18de0d (diff)
adc: Implement support for f1 ADC block
Add basic support for the STM32F1xx ADC blocks.
-rw-r--r--embassy-stm32/src/adc/f1.rs233
-rw-r--r--embassy-stm32/src/adc/mod.rs9
2 files changed, 242 insertions, 0 deletions
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
new file mode 100644
index 000000000..3ed1701fa
--- /dev/null
+++ b/embassy-stm32/src/adc/f1.rs
@@ -0,0 +1,233 @@
1use crate::adc::{AdcPin, Instance};
2use crate::rcc::get_freqs;
3use crate::time::Hertz;
4use core::marker::PhantomData;
5use embassy::util::Unborrow;
6use embassy_hal_common::unborrow;
7use embedded_hal::blocking::delay::DelayUs;
8
9pub const VDDA_CALIB_MV: u32 = 3300;
10pub const ADC_MAX: u32 = (1 << 12) - 1;
11// No calibration data for F103, voltage should be 1.2v
12pub const VREF_INT: u32 = 1200;
13
14pub struct Vref;
15impl<T: Instance> AdcPin<T> for Vref {}
16impl<T: Instance> super::sealed::AdcPin<T> for Vref {
17 fn channel(&self) -> u8 {
18 17
19 }
20}
21
22pub struct Temperature;
23impl<T: Instance> AdcPin<T> for Temperature {}
24impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
25 fn channel(&self) -> u8 {
26 16
27 }
28}
29
30mod sample_time {
31 /// ADC sample time
32 ///
33 /// The default setting is 1.5 ADC clock cycles.
34 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
35 pub enum SampleTime {
36 /// 1.5 ADC clock cycles
37 Cycles1_5 = 0b000,
38
39 /// 7.5 ADC clock cycles
40 Cycles7_5 = 0b001,
41
42 /// 13.5 ADC clock cycles
43 Cycles13_5 = 0b010,
44
45 /// 28.5 ADC clock cycles
46 Cycles28_5 = 0b011,
47
48 /// 41.5 ADC clock cycles
49 Cycles41_5 = 0b100,
50
51 /// 55.5 ADC clock cycles
52 Cycles55_5 = 0b101,
53
54 /// 71.5 ADC clock cycles
55 Cycles71_5 = 0b110,
56
57 /// 239.5 ADC clock cycles
58 Cycles239_5 = 0b111,
59 }
60
61 impl SampleTime {
62 pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
63 match self {
64 SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5,
65 SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5,
66 SampleTime::Cycles13_5 => crate::pac::adc::vals::SampleTime::CYCLES13_5,
67 SampleTime::Cycles28_5 => crate::pac::adc::vals::SampleTime::CYCLES28_5,
68 SampleTime::Cycles41_5 => crate::pac::adc::vals::SampleTime::CYCLES41_5,
69 SampleTime::Cycles55_5 => crate::pac::adc::vals::SampleTime::CYCLES55_5,
70 SampleTime::Cycles71_5 => crate::pac::adc::vals::SampleTime::CYCLES71_5,
71 SampleTime::Cycles239_5 => crate::pac::adc::vals::SampleTime::CYCLES239_5,
72 }
73 }
74 }
75
76 impl Default for SampleTime {
77 fn default() -> Self {
78 Self::Cycles28_5
79 }
80 }
81}
82
83pub use sample_time::SampleTime;
84
85pub struct Adc<'d, T: Instance> {
86 sample_time: SampleTime,
87 calibrated_vdda: u32,
88 phantom: PhantomData<&'d mut T>,
89}
90
91impl<'d, T: Instance> Adc<'d, T> {
92 pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
93 unborrow!(_peri);
94 T::enable();
95 T::reset();
96 unsafe {
97 T::regs().cr2().modify(|reg| reg.set_adon(true));
98 }
99
100 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
101 // for at least two ADC clock cycles
102 delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
103
104 unsafe {
105 // Reset calibration
106 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
107 while T::regs().cr2().read().rstcal() {
108 // spin
109 }
110
111 // Calibrate
112 T::regs().cr2().modify(|reg| reg.set_cal(true));
113 while T::regs().cr2().read().cal() {
114 // spin
115 }
116 }
117
118 // One cycle after calibration
119 delay.delay_us((1_000_000) / Self::freq().0 + 1);
120
121 Self {
122 sample_time: Default::default(),
123 calibrated_vdda: VDDA_CALIB_MV,
124 phantom: PhantomData,
125 }
126 }
127
128 fn freq() -> Hertz {
129 unsafe { get_freqs() }.adc
130 }
131
132 pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
133 match us * Self::freq().0 / 1_000_000 {
134 0..=1 => SampleTime::Cycles1_5,
135 2..=7 => SampleTime::Cycles7_5,
136 8..=13 => SampleTime::Cycles13_5,
137 14..=28 => SampleTime::Cycles28_5,
138 29..=41 => SampleTime::Cycles41_5,
139 42..=55 => SampleTime::Cycles55_5,
140 56..=71 => SampleTime::Cycles71_5,
141 _ => SampleTime::Cycles239_5,
142 }
143 }
144
145 pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
146 unsafe {
147 T::regs().cr2().modify(|reg| {
148 reg.set_tsvrefe(true);
149 })
150 }
151 Vref {}
152 }
153
154 pub fn enable_temperature(&self) -> Temperature {
155 unsafe {
156 T::regs().cr2().modify(|reg| {
157 reg.set_tsvrefe(true);
158 })
159 }
160 Temperature {}
161 }
162
163 /// Calculates the system VDDA by sampling the internal VREF channel and comparing
164 /// to the expected value. If the chip's VDDA is not stable, run this before each ADC
165 /// conversion.
166 pub fn calibrate(&mut self, vref: &mut Vref) -> u32 {
167 let old_sample_time = self.sample_time;
168 self.sample_time = SampleTime::Cycles239_5;
169
170 let vref_samp = self.read(vref);
171 self.sample_time = old_sample_time;
172
173 self.calibrated_vdda = (ADC_MAX * VREF_INT) / u32::from(vref_samp);
174 self.calibrated_vdda
175 }
176
177 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
178 self.sample_time = sample_time;
179 }
180
181 /// Convert a measurement to millivolts
182 pub fn to_millivolts(&self, sample: u16) -> u16 {
183 ((u32::from(sample) * self.calibrated_vdda) / ADC_MAX) as u16
184 }
185
186 /// Perform a single conversion.
187 fn convert(&mut self) -> u16 {
188 unsafe {
189 T::regs().cr2().modify(|reg| {
190 reg.set_adon(true);
191 reg.set_swstart(true);
192 });
193 while T::regs().cr2().read().swstart() {}
194 while !T::regs().sr().read().eoc() {}
195
196 T::regs().dr().read().0 as u16
197 }
198 }
199
200 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
201 unsafe {
202 Self::set_channel_sample_time(pin.channel(), self.sample_time);
203 T::regs().cr1().modify(|reg| {
204 reg.set_scan(false);
205 reg.set_discen(false);
206 });
207 T::regs().sqr1().modify(|reg| reg.set_l(0));
208
209 T::regs().cr2().modify(|reg| {
210 reg.set_cont(false);
211 reg.set_exttrig(true);
212 reg.set_swstart(false);
213 reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
214 });
215 }
216
217 // Configure the channel to sample
218 unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) }
219 self.convert()
220 }
221
222 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
223 if ch <= 9 {
224 T::regs()
225 .smpr2()
226 .modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
227 } else {
228 T::regs()
229 .smpr1()
230 .modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
231 }
232 }
233}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 9c3a30fbc..d0fc188d5 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -3,6 +3,7 @@
3#[cfg_attr(adc_v3, path = "v3.rs")] 3#[cfg_attr(adc_v3, path = "v3.rs")]
4#[cfg_attr(adc_v2, path = "v2.rs")] 4#[cfg_attr(adc_v2, path = "v2.rs")]
5#[cfg_attr(adc_g0, path = "v3.rs")] 5#[cfg_attr(adc_g0, path = "v3.rs")]
6#[cfg_attr(adc_f1, path = "f1.rs")]
6mod _version; 7mod _version;
7 8
8#[allow(unused)] 9#[allow(unused)]
@@ -13,9 +14,11 @@ use crate::peripherals;
13pub(crate) mod sealed { 14pub(crate) mod sealed {
14 pub trait Instance { 15 pub trait Instance {
15 fn regs() -> &'static crate::pac::adc::Adc; 16 fn regs() -> &'static crate::pac::adc::Adc;
17 #[cfg(not(adc_f1))]
16 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon; 18 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon;
17 } 19 }
18 20
21 #[cfg(not(adc_f1))]
19 pub trait Common { 22 pub trait Common {
20 fn regs() -> &'static crate::pac::adccommon::AdcCommon; 23 fn regs() -> &'static crate::pac::adccommon::AdcCommon;
21 } 24 }
@@ -25,7 +28,11 @@ pub(crate) mod sealed {
25 } 28 }
26} 29}
27 30
31#[cfg(not(adc_f1))]
28pub trait Instance: sealed::Instance + 'static {} 32pub trait Instance: sealed::Instance + 'static {}
33#[cfg(adc_f1)]
34pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral + 'static {}
35#[cfg(not(adc_f1))]
29pub trait Common: sealed::Common + 'static {} 36pub trait Common: sealed::Common + 'static {}
30pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 37pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
31 38
@@ -35,6 +42,7 @@ crate::pac::peripherals!(
35 fn regs() -> &'static crate::pac::adc::Adc { 42 fn regs() -> &'static crate::pac::adc::Adc {
36 &crate::pac::$inst 43 &crate::pac::$inst
37 } 44 }
45 #[cfg(not(adc_f1))]
38 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon { 46 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
39 crate::pac::peripherals!{ 47 crate::pac::peripherals!{
40 (adccommon, $common_inst:ident) => { 48 (adccommon, $common_inst:ident) => {
@@ -48,6 +56,7 @@ crate::pac::peripherals!(
48 }; 56 };
49); 57);
50 58
59#[cfg(not(adc_f1))]
51crate::pac::peripherals!( 60crate::pac::peripherals!(
52 (adccommon, $inst:ident) => { 61 (adccommon, $inst:ident) => {
53 impl sealed::Common for peripherals::$inst { 62 impl sealed::Common for peripherals::$inst {