diff options
| author | xoviat <[email protected]> | 2023-09-05 21:48:44 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-05 21:48:44 +0000 |
| commit | 9d76a6e933259be6783b2ba06b6cefa85f3a6732 (patch) | |
| tree | 7c21e40361d021dbace579264f9e9792ae64e37a | |
| parent | e2f8bf19ea55341f274c6cb9c3650a96f4a09fe4 (diff) | |
| parent | f5022719401ef15b02bfefadcf7e10719e48f06e (diff) | |
Merge pull request #1849 from xoviat/adc-f3
Add adc f3
| -rw-r--r-- | embassy-stm32/build.rs | 11 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f3.rs | 126 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 59 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/resolution.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/sample_time.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f3.rs | 93 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 5 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/adc.rs | 34 |
8 files changed, 331 insertions, 23 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index aef0668a2..d3bfd24fb 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -309,14 +309,17 @@ fn main() { | |||
| 309 | // Generate RccPeripheral impls | 309 | // Generate RccPeripheral impls |
| 310 | 310 | ||
| 311 | // TODO: maybe get this from peripheral kind? Not sure | 311 | // TODO: maybe get this from peripheral kind? Not sure |
| 312 | let refcounted_peripherals = HashSet::from(["USART"]); | 312 | let mut refcounted_peripherals = HashSet::from(["usart"]); |
| 313 | let mut refcount_statics = HashSet::new(); | 313 | let mut refcount_statics = HashSet::new(); |
| 314 | 314 | ||
| 315 | if chip_name.starts_with("stm32f3") { | ||
| 316 | refcounted_peripherals.insert("adc"); | ||
| 317 | } | ||
| 318 | |||
| 315 | for p in METADATA.peripherals { | 319 | for p in METADATA.peripherals { |
| 316 | // generating RccPeripheral impl for H7 ADC3 would result in bad frequency | 320 | // generating RccPeripheral impl for H7 ADC3 would result in bad frequency |
| 317 | if !singletons.contains(&p.name.to_string()) | 321 | if !singletons.contains(&p.name.to_string()) |
| 318 | || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) | 322 | || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) |
| 319 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "f3")) | ||
| 320 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4")) | 323 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4")) |
| 321 | { | 324 | { |
| 322 | continue; | 325 | continue; |
| @@ -348,13 +351,13 @@ fn main() { | |||
| 348 | TokenStream::new() | 351 | TokenStream::new() |
| 349 | }; | 352 | }; |
| 350 | 353 | ||
| 351 | let ptype = (if let Some(reg) = &p.registers { reg.kind } else { "" }).to_ascii_uppercase(); | 354 | let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; |
| 352 | let pname = format_ident!("{}", p.name); | 355 | let pname = format_ident!("{}", p.name); |
| 353 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); | 356 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); |
| 354 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); | 357 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); |
| 355 | let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); | 358 | let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); |
| 356 | 359 | ||
| 357 | let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.as_str()) { | 360 | let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { |
| 358 | let refcount_static = | 361 | let refcount_static = |
| 359 | format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); | 362 | format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); |
| 360 | 363 | ||
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs new file mode 100644 index 000000000..458573c05 --- /dev/null +++ b/embassy-stm32/src/adc/f3.rs | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | use embassy_hal_internal::into_ref; | ||
| 2 | use embedded_hal_02::blocking::delay::DelayUs; | ||
| 3 | |||
| 4 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | use crate::Peripheral; | ||
| 7 | |||
| 8 | pub const VDDA_CALIB_MV: u32 = 3300; | ||
| 9 | pub const ADC_MAX: u32 = (1 << 12) - 1; | ||
| 10 | // No calibration data for F103, voltage should be 1.2v | ||
| 11 | pub const VREF_INT: u32 = 1200; | ||
| 12 | |||
| 13 | pub struct Vref; | ||
| 14 | impl<T: Instance> AdcPin<T> for Vref {} | ||
| 15 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | ||
| 16 | fn channel(&self) -> u8 { | ||
| 17 | 18 | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | pub struct Temperature; | ||
| 22 | impl<T: Instance> AdcPin<T> for Temperature {} | ||
| 23 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | ||
| 24 | fn channel(&self) -> u8 { | ||
| 25 | 16 | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 30 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | ||
| 31 | use crate::pac::adc::vals; | ||
| 32 | |||
| 33 | into_ref!(adc); | ||
| 34 | |||
| 35 | T::enable(); | ||
| 36 | T::reset(); | ||
| 37 | |||
| 38 | // Enable the adc regulator | ||
| 39 | T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); | ||
| 40 | T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); | ||
| 41 | |||
| 42 | // Wait for the regulator to stabilize | ||
| 43 | delay.delay_us(10); | ||
| 44 | |||
| 45 | assert!(!T::regs().cr().read().aden()); | ||
| 46 | |||
| 47 | // Begin calibration | ||
| 48 | T::regs().cr().modify(|w| w.set_adcaldif(false)); | ||
| 49 | T::regs().cr().modify(|w| w.set_adcal(true)); | ||
| 50 | |||
| 51 | while T::regs().cr().read().adcal() {} | ||
| 52 | |||
| 53 | // Enable the adc | ||
| 54 | T::regs().cr().modify(|w| w.set_aden(true)); | ||
| 55 | |||
| 56 | // Wait until the adc is ready | ||
| 57 | while !T::regs().isr().read().adrdy() {} | ||
| 58 | |||
| 59 | Self { | ||
| 60 | adc, | ||
| 61 | sample_time: Default::default(), | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | fn freq() -> Hertz { | ||
| 66 | <T as crate::adc::sealed::Instance>::frequency() | ||
| 67 | } | ||
| 68 | |||
| 69 | pub fn sample_time_for_us(&self, us: u32) -> SampleTime { | ||
| 70 | match us * Self::freq().0 / 1_000_000 { | ||
| 71 | 0..=1 => SampleTime::Cycles1_5, | ||
| 72 | 2..=4 => SampleTime::Cycles4_5, | ||
| 73 | 5..=7 => SampleTime::Cycles7_5, | ||
| 74 | 8..=19 => SampleTime::Cycles19_5, | ||
| 75 | 20..=61 => SampleTime::Cycles61_5, | ||
| 76 | 62..=181 => SampleTime::Cycles181_5, | ||
| 77 | _ => SampleTime::Cycles601_5, | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { | ||
| 82 | T::common_regs().ccr().modify(|w| w.set_vrefen(true)); | ||
| 83 | |||
| 84 | Vref {} | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn enable_temperature(&self) -> Temperature { | ||
| 88 | T::common_regs().ccr().modify(|w| w.set_tsen(true)); | ||
| 89 | |||
| 90 | Temperature {} | ||
| 91 | } | ||
| 92 | |||
| 93 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | ||
| 94 | self.sample_time = sample_time; | ||
| 95 | } | ||
| 96 | |||
| 97 | /// Perform a single conversion. | ||
| 98 | fn convert(&mut self) -> u16 { | ||
| 99 | T::regs().isr().write(|_| {}); | ||
| 100 | T::regs().cr().modify(|w| w.set_adstart(true)); | ||
| 101 | |||
| 102 | while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} | ||
| 103 | T::regs().isr().write(|_| {}); | ||
| 104 | |||
| 105 | T::regs().dr().read().0 as u16 | ||
| 106 | } | ||
| 107 | |||
| 108 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | ||
| 109 | // pin.set_as_analog(); | ||
| 110 | |||
| 111 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||
| 112 | |||
| 113 | // Configure the channel to sample | ||
| 114 | T::regs().sqr3().write(|w| w.set_sq(0, pin.channel())); | ||
| 115 | self.convert() | ||
| 116 | } | ||
| 117 | |||
| 118 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | ||
| 119 | let sample_time = sample_time.into(); | ||
| 120 | if ch <= 9 { | ||
| 121 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||
| 122 | } else { | ||
| 123 | T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e57889aa6..a127445d8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -1,23 +1,24 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 3 | #[cfg(not(adc_f3_v2))] |
| 4 | #[cfg_attr(adc_f1, path = "f1.rs")] | 4 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| 5 | #[cfg_attr(adc_f3, path = "f3.rs")] | ||
| 5 | #[cfg_attr(adc_v1, path = "v1.rs")] | 6 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 6 | #[cfg_attr(adc_v2, path = "v2.rs")] | 7 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| 7 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] | 8 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] |
| 8 | #[cfg_attr(adc_v4, path = "v4.rs")] | 9 | #[cfg_attr(adc_v4, path = "v4.rs")] |
| 9 | mod _version; | 10 | mod _version; |
| 10 | 11 | ||
| 11 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] | 12 | #[cfg(not(any(adc_f1, adc_f3_v2)))] |
| 12 | mod resolution; | 13 | mod resolution; |
| 13 | mod sample_time; | 14 | mod sample_time; |
| 14 | 15 | ||
| 15 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | ||
| 16 | #[allow(unused)] | 16 | #[allow(unused)] |
| 17 | #[cfg(not(adc_f3_v2))] | ||
| 17 | pub use _version::*; | 18 | pub use _version::*; |
| 18 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] | 19 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] |
| 19 | pub use resolution::Resolution; | 20 | pub use resolution::Resolution; |
| 20 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 21 | #[cfg(not(adc_f3_v2))] |
| 21 | pub use sample_time::SampleTime; | 22 | pub use sample_time::SampleTime; |
| 22 | 23 | ||
| 23 | use crate::peripherals; | 24 | use crate::peripherals; |
| @@ -25,15 +26,17 @@ use crate::peripherals; | |||
| 25 | pub struct Adc<'d, T: Instance> { | 26 | pub struct Adc<'d, T: Instance> { |
| 26 | #[allow(unused)] | 27 | #[allow(unused)] |
| 27 | adc: crate::PeripheralRef<'d, T>, | 28 | adc: crate::PeripheralRef<'d, T>, |
| 28 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 29 | #[cfg(not(adc_f3_v2))] |
| 29 | sample_time: SampleTime, | 30 | sample_time: SampleTime, |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | pub(crate) mod sealed { | 33 | pub(crate) mod sealed { |
| 33 | pub trait Instance { | 34 | pub trait Instance { |
| 34 | fn regs() -> crate::pac::adc::Adc; | 35 | fn regs() -> crate::pac::adc::Adc; |
| 35 | #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] | 36 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] |
| 36 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 37 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 38 | #[cfg(adc_f3)] | ||
| 39 | fn frequency() -> crate::time::Hertz; | ||
| 37 | } | 40 | } |
| 38 | 41 | ||
| 39 | pub trait AdcPin<T: Instance> { | 42 | pub trait AdcPin<T: Instance> { |
| @@ -45,22 +48,22 @@ pub(crate) mod sealed { | |||
| 45 | } | 48 | } |
| 46 | } | 49 | } |
| 47 | 50 | ||
| 48 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))] | 51 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))] |
| 49 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 52 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} |
| 50 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))] | 53 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))] |
| 51 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 54 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 52 | 55 | ||
| 53 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 56 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} |
| 54 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} | 57 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} |
| 55 | 58 | ||
| 56 | #[cfg(not(stm32h7))] | 59 | #[cfg(not(any(stm32h7, adc_f3)))] |
| 57 | foreach_peripheral!( | 60 | foreach_peripheral!( |
| 58 | (adc, $inst:ident) => { | 61 | (adc, $inst:ident) => { |
| 59 | impl crate::adc::sealed::Instance for peripherals::$inst { | 62 | impl crate::adc::sealed::Instance for peripherals::$inst { |
| 60 | fn regs() -> crate::pac::adc::Adc { | 63 | fn regs() -> crate::pac::adc::Adc { |
| 61 | crate::pac::$inst | 64 | crate::pac::$inst |
| 62 | } | 65 | } |
| 63 | #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] | 66 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] |
| 64 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 67 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 65 | foreach_peripheral!{ | 68 | foreach_peripheral!{ |
| 66 | (adccommon, $common_inst:ident) => { | 69 | (adccommon, $common_inst:ident) => { |
| @@ -74,7 +77,7 @@ foreach_peripheral!( | |||
| 74 | }; | 77 | }; |
| 75 | ); | 78 | ); |
| 76 | 79 | ||
| 77 | #[cfg(stm32h7)] | 80 | #[cfg(any(stm32h7, adc_f3))] |
| 78 | foreach_peripheral!( | 81 | foreach_peripheral!( |
| 79 | (adc, ADC3) => { | 82 | (adc, ADC3) => { |
| 80 | impl crate::adc::sealed::Instance for peripherals::ADC3 { | 83 | impl crate::adc::sealed::Instance for peripherals::ADC3 { |
| @@ -89,16 +92,43 @@ foreach_peripheral!( | |||
| 89 | }; | 92 | }; |
| 90 | } | 93 | } |
| 91 | } | 94 | } |
| 95 | |||
| 96 | #[cfg(adc_f3)] | ||
| 97 | fn frequency() -> crate::time::Hertz { | ||
| 98 | unsafe { crate::rcc::get_freqs() }.adc34.unwrap() | ||
| 99 | } | ||
| 92 | } | 100 | } |
| 93 | 101 | ||
| 94 | impl crate::adc::Instance for peripherals::ADC3 {} | 102 | impl crate::adc::Instance for peripherals::ADC3 {} |
| 95 | }; | 103 | }; |
| 104 | (adc, ADC4) => { | ||
| 105 | impl crate::adc::sealed::Instance for peripherals::ADC4 { | ||
| 106 | fn regs() -> crate::pac::adc::Adc { | ||
| 107 | crate::pac::ADC4 | ||
| 108 | } | ||
| 109 | #[cfg(not(any(adc_f1, adc_v1)))] | ||
| 110 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 111 | foreach_peripheral!{ | ||
| 112 | (adccommon, ADC3_COMMON) => { | ||
| 113 | return crate::pac::ADC3_COMMON | ||
| 114 | }; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | #[cfg(adc_f3)] | ||
| 119 | fn frequency() -> crate::time::Hertz { | ||
| 120 | unsafe { crate::rcc::get_freqs() }.adc34.unwrap() | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | impl crate::adc::Instance for peripherals::ADC4 {} | ||
| 125 | }; | ||
| 96 | (adc, $inst:ident) => { | 126 | (adc, $inst:ident) => { |
| 97 | impl crate::adc::sealed::Instance for peripherals::$inst { | 127 | impl crate::adc::sealed::Instance for peripherals::$inst { |
| 98 | fn regs() -> crate::pac::adc::Adc { | 128 | fn regs() -> crate::pac::adc::Adc { |
| 99 | crate::pac::$inst | 129 | crate::pac::$inst |
| 100 | } | 130 | } |
| 101 | #[cfg(all(not(adc_f1), not(adc_v1)))] | 131 | #[cfg(not(any(adc_f1, adc_v1)))] |
| 102 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 132 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 103 | foreach_peripheral!{ | 133 | foreach_peripheral!{ |
| 104 | (adccommon, ADC_COMMON) => { | 134 | (adccommon, ADC_COMMON) => { |
| @@ -106,6 +136,11 @@ foreach_peripheral!( | |||
| 106 | }; | 136 | }; |
| 107 | } | 137 | } |
| 108 | } | 138 | } |
| 139 | |||
| 140 | #[cfg(adc_f3)] | ||
| 141 | fn frequency() -> crate::time::Hertz { | ||
| 142 | unsafe { crate::rcc::get_freqs() }.adc.unwrap() | ||
| 143 | } | ||
| 109 | } | 144 | } |
| 110 | 145 | ||
| 111 | impl crate::adc::Instance for peripherals::$inst {} | 146 | impl crate::adc::Instance for peripherals::$inst {} |
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 67fb9b8c0..5668137b5 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 1 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 2 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 3 | pub enum Resolution { | 3 | pub enum Resolution { |
| 4 | TwelveBit, | 4 | TwelveBit, |
| @@ -19,7 +19,7 @@ pub enum Resolution { | |||
| 19 | 19 | ||
| 20 | impl Default for Resolution { | 20 | impl Default for Resolution { |
| 21 | fn default() -> Self { | 21 | fn default() -> Self { |
| 22 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 22 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 23 | { | 23 | { |
| 24 | Self::TwelveBit | 24 | Self::TwelveBit |
| 25 | } | 25 | } |
| @@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res { | |||
| 40 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, | 40 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, |
| 41 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, | 41 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, |
| 42 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, | 42 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, |
| 43 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 43 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 44 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, | 44 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, |
| 45 | } | 45 | } |
| 46 | } | 46 | } |
| @@ -56,7 +56,7 @@ impl Resolution { | |||
| 56 | Resolution::TwelveBit => (1 << 12) - 1, | 56 | Resolution::TwelveBit => (1 << 12) - 1, |
| 57 | Resolution::TenBit => (1 << 10) - 1, | 57 | Resolution::TenBit => (1 << 10) - 1, |
| 58 | Resolution::EightBit => (1 << 8) - 1, | 58 | Resolution::EightBit => (1 << 8) - 1, |
| 59 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] | 59 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] |
| 60 | Resolution::SixBit => (1 << 6) - 1, | 60 | Resolution::SixBit => (1 << 6) - 1, |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 5480e7a77..6a6619299 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #[cfg(not(any(adc_f3, adc_f3_v2)))] | 1 | #[cfg(not(adc_f3_v2))] |
| 2 | macro_rules! impl_sample_time { | 2 | macro_rules! impl_sample_time { |
| 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { | 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { |
| 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] | 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] |
| @@ -105,3 +105,19 @@ impl_sample_time!( | |||
| 105 | ("810.5", Cycles810_5, CYCLES810_5) | 105 | ("810.5", Cycles810_5, CYCLES810_5) |
| 106 | ) | 106 | ) |
| 107 | ); | 107 | ); |
| 108 | |||
| 109 | #[cfg(adc_f3)] | ||
| 110 | impl_sample_time!( | ||
| 111 | "1.5", | ||
| 112 | Cycles1_5, | ||
| 113 | ( | ||
| 114 | ("1.5", Cycles1_5, CYCLES1_5), | ||
| 115 | ("2.5", Cycles2_5, CYCLES2_5), | ||
| 116 | ("4.5", Cycles4_5, CYCLES4_5), | ||
| 117 | ("7.5", Cycles7_5, CYCLES7_5), | ||
| 118 | ("19.5", Cycles19_5, CYCLES19_5), | ||
| 119 | ("61.5", Cycles61_5, CYCLES61_5), | ||
| 120 | ("181.5", Cycles181_5, CYCLES181_5), | ||
| 121 | ("601.5", Cycles601_5, CYCLES601_5) | ||
| 122 | ) | ||
| 123 | ); | ||
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 7480c0393..f8726c24a 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::pac::flash::vals::Latency; | 1 | use crate::pac::flash::vals::Latency; |
| 2 | use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; | 2 | use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; |
| 3 | use crate::pac::{FLASH, RCC}; | 3 | use crate::pac::{FLASH, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 4 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::time::Hertz; | 5 | use crate::time::Hertz; |
| @@ -10,6 +10,46 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000); | |||
| 10 | /// LSI speed | 10 | /// LSI speed |
| 11 | pub const LSI_FREQ: Hertz = Hertz(40_000); | 11 | pub const LSI_FREQ: Hertz = Hertz(40_000); |
| 12 | 12 | ||
| 13 | #[repr(u16)] | ||
| 14 | #[derive(Clone, Copy)] | ||
| 15 | pub enum ADCPrescaler { | ||
| 16 | Div1 = 1, | ||
| 17 | Div2 = 2, | ||
| 18 | Div4 = 4, | ||
| 19 | Div6 = 6, | ||
| 20 | Div8 = 8, | ||
| 21 | Div12 = 12, | ||
| 22 | Div16 = 16, | ||
| 23 | Div32 = 32, | ||
| 24 | Div64 = 64, | ||
| 25 | Div128 = 128, | ||
| 26 | Div256 = 256, | ||
| 27 | } | ||
| 28 | |||
| 29 | impl From<ADCPrescaler> for Adcpres { | ||
| 30 | fn from(value: ADCPrescaler) -> Self { | ||
| 31 | match value { | ||
| 32 | ADCPrescaler::Div1 => Adcpres::DIV1, | ||
| 33 | ADCPrescaler::Div2 => Adcpres::DIV2, | ||
| 34 | ADCPrescaler::Div4 => Adcpres::DIV4, | ||
| 35 | ADCPrescaler::Div6 => Adcpres::DIV6, | ||
| 36 | ADCPrescaler::Div8 => Adcpres::DIV8, | ||
| 37 | ADCPrescaler::Div12 => Adcpres::DIV12, | ||
| 38 | ADCPrescaler::Div16 => Adcpres::DIV16, | ||
| 39 | ADCPrescaler::Div32 => Adcpres::DIV32, | ||
| 40 | ADCPrescaler::Div64 => Adcpres::DIV64, | ||
| 41 | ADCPrescaler::Div128 => Adcpres::DIV128, | ||
| 42 | ADCPrescaler::Div256 => Adcpres::DIV256, | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | #[derive(Clone, Copy)] | ||
| 48 | pub enum ADCClock { | ||
| 49 | AHB(ADCPrescaler), | ||
| 50 | PLL(ADCPrescaler), | ||
| 51 | } | ||
| 52 | |||
| 13 | /// Clocks configutation | 53 | /// Clocks configutation |
| 14 | #[non_exhaustive] | 54 | #[non_exhaustive] |
| 15 | #[derive(Default)] | 55 | #[derive(Default)] |
| @@ -36,9 +76,18 @@ pub struct Config { | |||
| 36 | /// - The System clock frequency is either 48MHz or 72MHz | 76 | /// - The System clock frequency is either 48MHz or 72MHz |
| 37 | /// - APB1 clock has a minimum frequency of 10MHz | 77 | /// - APB1 clock has a minimum frequency of 10MHz |
| 38 | pub pll48: bool, | 78 | pub pll48: bool, |
| 79 | #[cfg(rcc_f3)] | ||
| 80 | /// ADC clock setup | ||
| 81 | /// - For AHB, a psc of 4 or less must be used | ||
| 82 | pub adc: Option<ADCClock>, | ||
| 83 | #[cfg(rcc_f3)] | ||
| 84 | /// ADC clock setup | ||
| 85 | /// - For AHB, a psc of 4 or less must be used | ||
| 86 | pub adc34: Option<ADCClock>, | ||
| 39 | } | 87 | } |
| 40 | 88 | ||
| 41 | // Information required to setup the PLL clock | 89 | // Information required to setup the PLL clock |
| 90 | #[derive(Clone, Copy)] | ||
| 42 | struct PllConfig { | 91 | struct PllConfig { |
| 43 | pll_src: Pllsrc, | 92 | pll_src: Pllsrc, |
| 44 | pll_mul: Pllmul, | 93 | pll_mul: Pllmul, |
| @@ -148,6 +197,44 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 148 | }); | 197 | }); |
| 149 | } | 198 | } |
| 150 | 199 | ||
| 200 | #[cfg(rcc_f3)] | ||
| 201 | let adc = config.adc.map(|adc| match adc { | ||
| 202 | ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { | ||
| 203 | // Make sure that we're using the PLL | ||
| 204 | pll_config.unwrap(); | ||
| 205 | w.set_adc12pres(psc.into()); | ||
| 206 | |||
| 207 | Hertz(sysclk / psc as u32) | ||
| 208 | }), | ||
| 209 | ADCClock::AHB(psc) => { | ||
| 210 | assert!(psc as u16 <= 4); | ||
| 211 | assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); | ||
| 212 | |||
| 213 | // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be | ||
| 214 | // different from “00”. | ||
| 215 | todo!(); | ||
| 216 | } | ||
| 217 | }); | ||
| 218 | |||
| 219 | #[cfg(rcc_f3)] | ||
| 220 | let adc34 = config.adc34.map(|adc| match adc { | ||
| 221 | ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { | ||
| 222 | // Make sure that we're using the PLL | ||
| 223 | pll_config.unwrap(); | ||
| 224 | w.set_adc34pres(psc.into()); | ||
| 225 | |||
| 226 | Hertz(sysclk / psc as u32) | ||
| 227 | }), | ||
| 228 | ADCClock::AHB(psc) => { | ||
| 229 | assert!(psc as u16 <= 4); | ||
| 230 | assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); | ||
| 231 | |||
| 232 | // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be | ||
| 233 | // different from “00”. | ||
| 234 | todo!(); | ||
| 235 | } | ||
| 236 | }); | ||
| 237 | |||
| 151 | // Set prescalers | 238 | // Set prescalers |
| 152 | // CFGR has been written before (PLL, PLL48) don't overwrite these settings | 239 | // CFGR has been written before (PLL, PLL48) don't overwrite these settings |
| 153 | RCC.cfgr().modify(|w| { | 240 | RCC.cfgr().modify(|w| { |
| @@ -177,6 +264,10 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 177 | apb1_tim: Hertz(pclk1 * timer_mul1), | 264 | apb1_tim: Hertz(pclk1 * timer_mul1), |
| 178 | apb2_tim: Hertz(pclk2 * timer_mul2), | 265 | apb2_tim: Hertz(pclk2 * timer_mul2), |
| 179 | ahb1: Hertz(hclk), | 266 | ahb1: Hertz(hclk), |
| 267 | #[cfg(rcc_f3)] | ||
| 268 | adc: adc, | ||
| 269 | #[cfg(rcc_f3)] | ||
| 270 | adc34: adc34, | ||
| 180 | }); | 271 | }); |
| 181 | } | 272 | } |
| 182 | 273 | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0430e4a74..2e1f60358 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -74,9 +74,12 @@ pub struct Clocks { | |||
| 74 | #[cfg(stm32f1)] | 74 | #[cfg(stm32f1)] |
| 75 | pub adc: Hertz, | 75 | pub adc: Hertz, |
| 76 | 76 | ||
| 77 | #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] | 77 | #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3))] |
| 78 | pub adc: Option<Hertz>, | 78 | pub adc: Option<Hertz>, |
| 79 | 79 | ||
| 80 | #[cfg(rcc_f3)] | ||
| 81 | pub adc34: Option<Hertz>, | ||
| 82 | |||
| 80 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] | 83 | #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] |
| 81 | /// Set only if the lsi or lse is configured, indicates stop is supported | 84 | /// Set only if the lsi or lse is configured, indicates stop is supported |
| 82 | pub rtc: Option<Hertz>, | 85 | pub rtc: Option<Hertz>, |
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs new file mode 100644 index 000000000..729497e82 --- /dev/null +++ b/examples/stm32f334/src/bin/adc.rs | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::adc::Adc; | ||
| 8 | use embassy_stm32::rcc::{ADCClock, ADCPrescaler}; | ||
| 9 | use embassy_stm32::time::Hertz; | ||
| 10 | use embassy_stm32::Config; | ||
| 11 | use embassy_time::{Delay, Duration, Timer}; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) -> ! { | ||
| 16 | let mut config = Config::default(); | ||
| 17 | config.rcc.hse = Some(Hertz(8_000_000)); | ||
| 18 | config.rcc.sysclk = Some(Hertz(16_000_000)); | ||
| 19 | config.rcc.adc = Some(ADCClock::PLL(ADCPrescaler::Div1)); | ||
| 20 | |||
| 21 | let mut p = embassy_stm32::init(config); | ||
| 22 | |||
| 23 | let mut adc = Adc::new(p.ADC1, &mut Delay); | ||
| 24 | |||
| 25 | let mut vrefint = adc.enable_vref(&mut Delay); | ||
| 26 | |||
| 27 | let _vref = adc.read(&mut vrefint); | ||
| 28 | let _pin = adc.read(&mut p.PA0); | ||
| 29 | |||
| 30 | loop { | ||
| 31 | info!("Hello World!"); | ||
| 32 | Timer::after(Duration::from_secs(1)).await; | ||
| 33 | } | ||
| 34 | } | ||
