aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc
diff options
context:
space:
mode:
authorklownfish <[email protected]>2024-09-11 11:55:16 +0200
committerklownfish <[email protected]>2024-09-11 11:55:16 +0200
commit0ba91ca555efc75dca603adbb51355c92b2fdb80 (patch)
tree5900ed4e048e4a3a515bf7d1201e3758049c0ff3 /embassy-stm32/src/adc
parente2f9a48457c5d54546a3861fb067071ce93f9742 (diff)
WIP: u5 adc
Diffstat (limited to 'embassy-stm32/src/adc')
-rw-r--r--embassy-stm32/src/adc/mod.rs13
-rw-r--r--embassy-stm32/src/adc/u5.rs375
2 files changed, 383 insertions, 5 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 7a7d7cd8e..8ba586f5c 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -13,6 +13,7 @@
13#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] 13#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")]
14#[cfg_attr(adc_v4, path = "v4.rs")] 14#[cfg_attr(adc_v4, path = "v4.rs")]
15#[cfg_attr(adc_g4, path = "g4.rs")] 15#[cfg_attr(adc_g4, path = "g4.rs")]
16#[cfg_attr(adc_u5, path = "u5.rs")]
16mod _version; 17mod _version;
17 18
18use core::marker::PhantomData; 19use core::marker::PhantomData;
@@ -63,7 +64,7 @@ trait SealedInstance {
63} 64}
64 65
65pub(crate) trait SealedAdcChannel<T> { 66pub(crate) trait SealedAdcChannel<T> {
66 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] 67 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
67 fn setup(&mut self) {} 68 fn setup(&mut self) {}
68 69
69 #[allow(unused)] 70 #[allow(unused)]
@@ -97,7 +98,8 @@ pub(crate) fn blocking_delay_us(us: u32) {
97 adc_f3_v1_1, 98 adc_f3_v1_1,
98 adc_g0, 99 adc_g0,
99 adc_u0, 100 adc_u0,
100 adc_h5 101 adc_h5,
102 adc_u5
101)))] 103)))]
102#[allow(private_bounds)] 104#[allow(private_bounds)]
103pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { 105pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
@@ -116,7 +118,8 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
116 adc_f3_v1_1, 118 adc_f3_v1_1,
117 adc_g0, 119 adc_g0,
118 adc_u0, 120 adc_u0,
119 adc_h5 121 adc_h5,
122 adc_u5
120))] 123))]
121#[allow(private_bounds)] 124#[allow(private_bounds)]
122pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral { 125pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {
@@ -128,7 +131,7 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::R
128pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { 131pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
129 #[allow(unused_mut)] 132 #[allow(unused_mut)]
130 fn degrade_adc(mut self) -> AnyAdcChannel<T> { 133 fn degrade_adc(mut self) -> AnyAdcChannel<T> {
131 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] 134 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
132 self.setup(); 135 self.setup();
133 136
134 AnyAdcChannel { 137 AnyAdcChannel {
@@ -183,7 +186,7 @@ macro_rules! impl_adc_pin {
183 ($inst:ident, $pin:ident, $ch:expr) => { 186 ($inst:ident, $pin:ident, $ch:expr) => {
184 impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {} 187 impl crate::adc::AdcChannel<peripherals::$inst> for crate::peripherals::$pin {}
185 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin { 188 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::peripherals::$pin {
186 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] 189 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))]
187 fn setup(&mut self) { 190 fn setup(&mut self) {
188 <Self as crate::gpio::SealedPin>::set_as_analog(self); 191 <Self as crate::gpio::SealedPin>::set_as_analog(self);
189 } 192 }
diff --git a/embassy-stm32/src/adc/u5.rs b/embassy-stm32/src/adc/u5.rs
new file mode 100644
index 000000000..9e6a94e5d
--- /dev/null
+++ b/embassy-stm32/src/adc/u5.rs
@@ -0,0 +1,375 @@
1#[allow(unused)]
2use pac::adc::vals::{Difsel, Exten, Pcsel};
3use pac::adccommon::vals::Presc;
4use crate::peripherals::ADC4;
5
6use super::{
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel
8};
9use crate::time::Hertz;
10use crate::{pac, rcc, Peripheral};
11
12// TODO: not correct
13const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
14const VREF_CHANNEL: u8 = 19;
15const TEMP_CHANNEL: u8 = 18;
16const VBAT_CHANNEL: u8 = 17;
17
18/// Default VREF voltage used for sample conversion to millivolts.
19pub const VREF_DEFAULT_MV: u32 = 3300;
20/// VREF voltage used for factory calibration of VREFINTCAL register.
21pub const VREF_CALIB_MV: u32 = 3300;
22
23
24// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
25/// Internal voltage reference channel.
26pub struct VrefInt;
27impl<T: Instance> AdcChannel<T> for VrefInt {}
28impl<T: Instance> SealedAdcChannel<T> for VrefInt {
29 fn channel(&self) -> u8 {
30 VREF_CHANNEL
31 }
32}
33
34/// Internal temperature channel.
35pub struct Temperature;
36impl<T: Instance> AdcChannel<T> for Temperature {}
37impl<T: Instance> SealedAdcChannel<T> for Temperature {
38 fn channel(&self) -> u8 {
39 TEMP_CHANNEL
40 }
41}
42
43/// Internal battery voltage channel.
44pub struct Vbat;
45impl<T: Instance> AdcChannel<T> for Vbat {}
46impl<T: Instance> SealedAdcChannel<T> for Vbat {
47 fn channel(&self) -> u8 {
48 VBAT_CHANNEL
49 }
50}
51
52// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
53// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
54#[allow(unused)]
55enum Prescaler {
56 NotDivided,
57 DividedBy2,
58 DividedBy4,
59 DividedBy6,
60 DividedBy8,
61 DividedBy10,
62 DividedBy12,
63 DividedBy16,
64 DividedBy32,
65 DividedBy64,
66 DividedBy128,
67 DividedBy256,
68}
69
70impl Prescaler {
71 fn from_ker_ck(frequency: Hertz) -> Self {
72 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
73 match raw_prescaler {
74 0 => Self::NotDivided,
75 1 => Self::DividedBy2,
76 2..=3 => Self::DividedBy4,
77 4..=5 => Self::DividedBy6,
78 6..=7 => Self::DividedBy8,
79 8..=9 => Self::DividedBy10,
80 10..=11 => Self::DividedBy12,
81 _ => unimplemented!(),
82 }
83 }
84
85 fn divisor(&self) -> u32 {
86 match self {
87 Prescaler::NotDivided => 1,
88 Prescaler::DividedBy2 => 2,
89 Prescaler::DividedBy4 => 4,
90 Prescaler::DividedBy6 => 6,
91 Prescaler::DividedBy8 => 8,
92 Prescaler::DividedBy10 => 10,
93 Prescaler::DividedBy12 => 12,
94 Prescaler::DividedBy16 => 16,
95 Prescaler::DividedBy32 => 32,
96 Prescaler::DividedBy64 => 64,
97 Prescaler::DividedBy128 => 128,
98 Prescaler::DividedBy256 => 256,
99 }
100 }
101
102 fn presc(&self) -> Presc {
103 match self {
104 Prescaler::NotDivided => Presc::DIV1,
105 Prescaler::DividedBy2 => Presc::DIV2,
106 Prescaler::DividedBy4 => Presc::DIV4,
107 Prescaler::DividedBy6 => Presc::DIV6,
108 Prescaler::DividedBy8 => Presc::DIV8,
109 Prescaler::DividedBy10 => Presc::DIV10,
110 Prescaler::DividedBy12 => Presc::DIV12,
111 Prescaler::DividedBy16 => Presc::DIV16,
112 Prescaler::DividedBy32 => Presc::DIV32,
113 Prescaler::DividedBy64 => Presc::DIV64,
114 Prescaler::DividedBy128 => Presc::DIV128,
115 Prescaler::DividedBy256 => Presc::DIV256,
116 }
117 }
118}
119
120/// Number of samples used for averaging.
121pub enum Averaging {
122 Disabled,
123 Samples2,
124 Samples4,
125 Samples8,
126 Samples16,
127 Samples32,
128 Samples64,
129 Samples128,
130 Samples256,
131 Samples512,
132 Samples1024,
133}
134
135// TODO
136// impl Instance for ADC4 {
137
138// }
139
140impl<'d, T: Instance> Adc<'d, T> {
141 /// Create a new ADC driver.
142 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
143 embassy_hal_internal::into_ref!(adc);
144 rcc::enable_and_reset::<T>();
145
146 let prescaler = Prescaler::from_ker_ck(T::frequency());
147
148 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
149
150 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
151 info!("ADC frequency set to {} Hz", frequency.0);
152
153 if frequency > MAX_ADC_CLK_FREQ {
154 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
155 }
156
157 let mut s = Self {
158 adc,
159 sample_time: SampleTime::from_bits(0),
160 };
161 crate::pac::RCC.ahb2enr1().modify(|w| {
162 w.set_adc12en(true);
163 });
164 blocking_delay_us(100);
165
166 info!("chungus {}", line!());
167 s.power_up();
168 info!("chungus {}", line!());
169 s.configure_differential_inputs();
170
171 info!("chungus {}", line!());
172 s.calibrate();
173 info!("chungus {}", line!());
174 blocking_delay_us(1);
175
176 info!("chungus {}", line!());
177 s.enable();
178 info!("chungus {}", line!());
179 s.configure();
180 info!("chungus {}", line!());
181
182 s
183 }
184
185 fn power_up(&mut self) {
186 T::regs().isr().modify(|reg| {
187 reg.set_ldordy(true);
188 });
189 info!("yummmum {}", T::regs().cr().as_ptr() as u32);
190 T::regs().cr().modify(|reg| {
191 info!("bajssis {}", reg.0);
192 reg.set_deeppwd(false);
193 info!("bajssis {}", reg.0);
194 reg.set_advregen(true);
195 info!("bajssis {}", reg.0);
196 });
197 info!("kissis {}", T::regs().as_ptr() as u32);
198 info!("basdsadasadjsisssss{}", T::regs().isr().as_ptr() as u32);
199 while !T::regs().isr().read().ldordy() {
200 // info!("bajsisssss{}", T::regs().isr().read().0);
201 };
202
203 T::regs().isr().modify(|reg| {
204 reg.set_ldordy(true);
205 });
206 }
207
208 fn configure_differential_inputs(&mut self) {
209 T::regs().difsel().modify(|w| {
210 for n in 0..20 {
211 w.set_difsel(n, Difsel::SINGLEENDED);
212 }
213 });
214 }
215
216 fn calibrate(&mut self) {
217 T::regs().cr().modify(|w| {
218 w.set_adcallin(true);
219 w.set_aden(false)
220 });
221 T::regs().calfact().modify(|w| {
222 w.set_capture_coef(false);
223 w.set_latch_coef(false)
224 });
225
226 T::regs().cr().modify(|w| w.set_adcal(true));
227 while T::regs().cr().read().adcal() {}
228 }
229
230 fn enable(&mut self) {
231 T::regs().isr().write(|w| w.set_adrdy(true));
232 T::regs().cr().modify(|w| w.set_aden(true));
233 while !T::regs().isr().read().adrdy() {}
234 T::regs().isr().write(|w| w.set_adrdy(true));
235 }
236
237 fn configure(&mut self) {
238 // single conversion mode, software trigger
239 T::regs().cfgr().modify(|w| {
240 w.set_cont(false);
241 w.set_exten(Exten::DISABLED);
242 });
243 }
244
245 /// Enable reading the voltage reference internal channel.
246 pub fn enable_vrefint(&self) -> VrefInt {
247 T::common_regs().ccr().modify(|reg| {
248 reg.set_vrefen(true);
249 });
250
251 VrefInt {}
252 }
253
254 /// Enable reading the temperature internal channel.
255 pub fn enable_temperature(&self) -> Temperature {
256 T::common_regs().ccr().modify(|reg| {
257 reg.set_vsenseen(true);
258 });
259
260 Temperature {}
261 }
262
263 /// Enable reading the vbat internal channel.
264 pub fn enable_vbat(&self) -> Vbat {
265 T::common_regs().ccr().modify(|reg| {
266 reg.set_vbaten(true);
267 });
268
269 Vbat {}
270 }
271
272 /// Set the ADC sample time.
273 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
274 self.sample_time = sample_time;
275 }
276
277 /// Get the ADC sample time.
278 pub fn sample_time(&self) -> SampleTime {
279 self.sample_time
280 }
281
282 /// Set the ADC resolution.
283 pub fn set_resolution(&mut self, resolution: Resolution) {
284 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
285 }
286
287 /// Set hardware averaging.
288 pub fn set_averaging(&mut self, averaging: Averaging) {
289 let (enable, samples, right_shift) = match averaging {
290 Averaging::Disabled => (false, 0, 0),
291 Averaging::Samples2 => (true, 1, 1),
292 Averaging::Samples4 => (true, 3, 2),
293 Averaging::Samples8 => (true, 7, 3),
294 Averaging::Samples16 => (true, 15, 4),
295 Averaging::Samples32 => (true, 31, 5),
296 Averaging::Samples64 => (true, 63, 6),
297 Averaging::Samples128 => (true, 127, 7),
298 Averaging::Samples256 => (true, 255, 8),
299 Averaging::Samples512 => (true, 511, 9),
300 Averaging::Samples1024 => (true, 1023, 10),
301 };
302
303 T::regs().cfgr2().modify(|reg| {
304 reg.set_rovse(enable);
305 reg.set_osvr(samples);
306 reg.set_ovss(right_shift);
307 })
308 }
309
310 /// Perform a single conversion.
311 fn convert(&mut self) -> u16 {
312 T::regs().isr().modify(|reg| {
313 reg.set_eos(true);
314 reg.set_eoc(true);
315 });
316
317 // Start conversion
318 T::regs().cr().modify(|reg| {
319 reg.set_adstart(true);
320 });
321
322 while !T::regs().isr().read().eos() {
323 // spin
324 }
325
326 T::regs().dr().read().0 as u16
327 }
328
329 /// Read an ADC channel.
330 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
331 self.read_channel(channel)
332 }
333
334 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
335 channel.setup();
336
337 let channel = channel.channel();
338
339 Self::set_channel_sample_time(channel, sample_time);
340
341 T::regs().cfgr2().modify(|w| w.set_lshift(0));
342 T::regs()
343 .pcsel()
344 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
345 }
346
347 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
348 Self::configure_channel(channel, self.sample_time);
349
350 T::regs().sqr1().modify(|reg| {
351 reg.set_sq(0, channel.channel());
352 reg.set_l(0);
353 });
354
355 self.convert()
356 }
357
358 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
359 let sample_time = sample_time.into();
360 if ch <= 9 {
361 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
362 } else {
363 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
364 }
365 }
366
367 fn cancel_conversions() {
368 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
369 T::regs().cr().modify(|reg| {
370 reg.set_adstp(true);
371 });
372 while T::regs().cr().read().adstart() {}
373 }
374 }
375}