diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-09-06 16:32:12 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-06 16:32:12 +0000 |
| commit | af7c93abba768057f1d3299c7b4f4aa4501b3e56 (patch) | |
| tree | ef6a688c53d3742f37171d4cb9b1aa4ba2d430d3 | |
| parent | a05afc54262e180fbbbe5b9369246c5275a5c4a3 (diff) | |
| parent | c356585a5918f1c66f5fc0e12edd82094dacd5c9 (diff) | |
Merge pull request #1864 from oll3/feat/stm32wl-adc
ADC support for STM32WLx
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 41 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/wl.rs | 29 |
4 files changed, 61 insertions, 17 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 306945962..ded58aee3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -58,7 +58,7 @@ sdio-host = "0.5.0" | |||
| 58 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 58 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 59 | critical-section = "1.1" | 59 | critical-section = "1.1" |
| 60 | atomic-polyfill = "1.0.1" | 60 | atomic-polyfill = "1.0.1" |
| 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-eaa4987e523408dfb31c1b76765dd345d2761373" } |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -77,7 +77,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 77 | [build-dependencies] | 77 | [build-dependencies] |
| 78 | proc-macro2 = "1.0.36" | 78 | proc-macro2 = "1.0.36" |
| 79 | quote = "1.0.15" | 79 | quote = "1.0.15" |
| 80 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0", default-features = false, features = ["metadata"]} | 80 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-eaa4987e523408dfb31c1b76765dd345d2761373", default-features = false, features = ["metadata"]} |
| 81 | 81 | ||
| 82 | [features] | 82 | [features] |
| 83 | default = ["rt"] | 83 | default = ["rt"] |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 0eeadfa93..013debca8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -33,7 +33,7 @@ pub struct Adc<'d, T: Instance> { | |||
| 33 | pub(crate) mod sealed { | 33 | pub(crate) mod sealed { |
| 34 | pub trait Instance { | 34 | pub trait Instance { |
| 35 | fn regs() -> crate::pac::adc::Adc; | 35 | fn regs() -> crate::pac::adc::Adc; |
| 36 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] | 36 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] |
| 37 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 37 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 38 | #[cfg(adc_f3)] | 38 | #[cfg(adc_f3)] |
| 39 | fn frequency() -> crate::time::Hertz; | 39 | fn frequency() -> crate::time::Hertz; |
| @@ -63,7 +63,7 @@ foreach_peripheral!( | |||
| 63 | fn regs() -> crate::pac::adc::Adc { | 63 | fn regs() -> crate::pac::adc::Adc { |
| 64 | crate::pac::$inst | 64 | crate::pac::$inst |
| 65 | } | 65 | } |
| 66 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] | 66 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] |
| 67 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 67 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 68 | foreach_peripheral!{ | 68 | foreach_peripheral!{ |
| 69 | (adccommon, $common_inst:ident) => { | 69 | (adccommon, $common_inst:ident) => { |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 821cc7f6a..011ecc281 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -13,7 +13,7 @@ pub const VREF_CALIB_MV: u32 = 3000; | |||
| 13 | /// configuration. | 13 | /// configuration. |
| 14 | fn enable() { | 14 | fn enable() { |
| 15 | critical_section::with(|_| { | 15 | critical_section::with(|_| { |
| 16 | #[cfg(stm32h7)] | 16 | #[cfg(any(stm32h7, stm32wl))] |
| 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); | 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); |
| 18 | #[cfg(stm32g0)] | 18 | #[cfg(stm32g0)] |
| 19 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); | 19 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); |
| @@ -26,9 +26,9 @@ pub struct VrefInt; | |||
| 26 | impl<T: Instance> AdcPin<T> for VrefInt {} | 26 | impl<T: Instance> AdcPin<T> for VrefInt {} |
| 27 | impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { | 27 | impl<T: Instance> super::sealed::AdcPin<T> for VrefInt { |
| 28 | fn channel(&self) -> u8 { | 28 | fn channel(&self) -> u8 { |
| 29 | #[cfg(not(stm32g0))] | 29 | #[cfg(not(adc_g0))] |
| 30 | let val = 0; | 30 | let val = 0; |
| 31 | #[cfg(stm32g0)] | 31 | #[cfg(adc_g0)] |
| 32 | let val = 13; | 32 | let val = 13; |
| 33 | val | 33 | val |
| 34 | } | 34 | } |
| @@ -38,9 +38,9 @@ pub struct Temperature; | |||
| 38 | impl<T: Instance> AdcPin<T> for Temperature {} | 38 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 39 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 39 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { |
| 40 | fn channel(&self) -> u8 { | 40 | fn channel(&self) -> u8 { |
| 41 | #[cfg(not(stm32g0))] | 41 | #[cfg(not(adc_g0))] |
| 42 | let val = 17; | 42 | let val = 17; |
| 43 | #[cfg(stm32g0)] | 43 | #[cfg(adc_g0)] |
| 44 | let val = 12; | 44 | let val = 12; |
| 45 | val | 45 | val |
| 46 | } | 46 | } |
| @@ -50,9 +50,9 @@ pub struct Vbat; | |||
| 50 | impl<T: Instance> AdcPin<T> for Vbat {} | 50 | impl<T: Instance> AdcPin<T> for Vbat {} |
| 51 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { | 51 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { |
| 52 | fn channel(&self) -> u8 { | 52 | fn channel(&self) -> u8 { |
| 53 | #[cfg(not(stm32g0))] | 53 | #[cfg(not(adc_g0))] |
| 54 | let val = 18; | 54 | let val = 18; |
| 55 | #[cfg(stm32g0)] | 55 | #[cfg(adc_g0)] |
| 56 | let val = 14; | 56 | let val = 14; |
| 57 | val | 57 | val |
| 58 | } | 58 | } |
| @@ -92,9 +92,14 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { | 94 | pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { |
| 95 | #[cfg(not(adc_g0))] | ||
| 95 | T::common_regs().ccr().modify(|reg| { | 96 | T::common_regs().ccr().modify(|reg| { |
| 96 | reg.set_vrefen(true); | 97 | reg.set_vrefen(true); |
| 97 | }); | 98 | }); |
| 99 | #[cfg(adc_g0)] | ||
| 100 | T::regs().ccr().modify(|reg| { | ||
| 101 | reg.set_vrefen(true); | ||
| 102 | }); | ||
| 98 | 103 | ||
| 99 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us | 104 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us |
| 100 | // to stabilize the internal voltage reference, we wait a little more. | 105 | // to stabilize the internal voltage reference, we wait a little more. |
| @@ -106,17 +111,27 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 106 | } | 111 | } |
| 107 | 112 | ||
| 108 | pub fn enable_temperature(&self) -> Temperature { | 113 | pub fn enable_temperature(&self) -> Temperature { |
| 114 | #[cfg(not(adc_g0))] | ||
| 109 | T::common_regs().ccr().modify(|reg| { | 115 | T::common_regs().ccr().modify(|reg| { |
| 110 | reg.set_ch17sel(true); | 116 | reg.set_ch17sel(true); |
| 111 | }); | 117 | }); |
| 118 | #[cfg(adc_g0)] | ||
| 119 | T::regs().ccr().modify(|reg| { | ||
| 120 | reg.set_tsen(true); | ||
| 121 | }); | ||
| 112 | 122 | ||
| 113 | Temperature {} | 123 | Temperature {} |
| 114 | } | 124 | } |
| 115 | 125 | ||
| 116 | pub fn enable_vbat(&self) -> Vbat { | 126 | pub fn enable_vbat(&self) -> Vbat { |
| 127 | #[cfg(not(adc_g0))] | ||
| 117 | T::common_regs().ccr().modify(|reg| { | 128 | T::common_regs().ccr().modify(|reg| { |
| 118 | reg.set_ch18sel(true); | 129 | reg.set_ch18sel(true); |
| 119 | }); | 130 | }); |
| 131 | #[cfg(adc_g0)] | ||
| 132 | T::regs().ccr().modify(|reg| { | ||
| 133 | reg.set_vbaten(true); | ||
| 134 | }); | ||
| 120 | 135 | ||
| 121 | Vbat {} | 136 | Vbat {} |
| 122 | } | 137 | } |
| @@ -126,9 +141,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 126 | } | 141 | } |
| 127 | 142 | ||
| 128 | pub fn set_resolution(&mut self, resolution: Resolution) { | 143 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 129 | #[cfg(not(stm32g0))] | 144 | #[cfg(not(adc_g0))] |
| 130 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | 145 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
| 131 | #[cfg(stm32g0)] | 146 | #[cfg(adc_g0)] |
| 132 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | 147 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 133 | } | 148 | } |
| 134 | 149 | ||
| @@ -182,9 +197,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 182 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | 197 | Self::set_channel_sample_time(pin.channel(), self.sample_time); |
| 183 | 198 | ||
| 184 | // Select channel | 199 | // Select channel |
| 185 | #[cfg(not(stm32g0))] | 200 | #[cfg(not(adc_g0))] |
| 186 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | 201 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); |
| 187 | #[cfg(stm32g0)] | 202 | #[cfg(adc_g0)] |
| 188 | T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | 203 | T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); |
| 189 | 204 | ||
| 190 | // Some models are affected by an erratum: | 205 | // Some models are affected by an erratum: |
| @@ -203,12 +218,12 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 203 | val | 218 | val |
| 204 | } | 219 | } |
| 205 | 220 | ||
| 206 | #[cfg(stm32g0)] | 221 | #[cfg(adc_g0)] |
| 207 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | 222 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { |
| 208 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | 223 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); |
| 209 | } | 224 | } |
| 210 | 225 | ||
| 211 | #[cfg(not(stm32g0))] | 226 | #[cfg(not(adc_g0))] |
| 212 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 227 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 213 | let sample_time = sample_time.into(); | 228 | let sample_time = sample_time.into(); |
| 214 | T::regs() | 229 | T::regs() |
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index e33690d10..47be00ad8 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; | 1 | pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; |
| 2 | use crate::pac::rcc::vals::Adcsel; | ||
| 2 | use crate::pac::{FLASH, PWR, RCC}; | 3 | use crate::pac::{FLASH, PWR, RCC}; |
| 3 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; | 4 | use crate::rcc::bd::{BackupDomain, RtcClockSource}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 5 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -106,6 +107,29 @@ impl Into<u8> for MSIRange { | |||
| 106 | } | 107 | } |
| 107 | } | 108 | } |
| 108 | 109 | ||
| 110 | #[derive(Clone, Copy)] | ||
| 111 | pub enum AdcClockSource { | ||
| 112 | HSI16, | ||
| 113 | PLLPCLK, | ||
| 114 | SYSCLK, | ||
| 115 | } | ||
| 116 | |||
| 117 | impl AdcClockSource { | ||
| 118 | pub fn adcsel(&self) -> Adcsel { | ||
| 119 | match self { | ||
| 120 | AdcClockSource::HSI16 => Adcsel::HSI16, | ||
| 121 | AdcClockSource::PLLPCLK => Adcsel::PLLPCLK, | ||
| 122 | AdcClockSource::SYSCLK => Adcsel::SYSCLK, | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | impl Default for AdcClockSource { | ||
| 128 | fn default() -> Self { | ||
| 129 | Self::HSI16 | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 109 | /// Clocks configutation | 133 | /// Clocks configutation |
| 110 | pub struct Config { | 134 | pub struct Config { |
| 111 | pub mux: ClockSrc, | 135 | pub mux: ClockSrc, |
| @@ -116,6 +140,7 @@ pub struct Config { | |||
| 116 | pub enable_lsi: bool, | 140 | pub enable_lsi: bool, |
| 117 | pub enable_rtc_apb: bool, | 141 | pub enable_rtc_apb: bool, |
| 118 | pub rtc_mux: RtcClockSource, | 142 | pub rtc_mux: RtcClockSource, |
| 143 | pub adc_clock_source: AdcClockSource, | ||
| 119 | } | 144 | } |
| 120 | 145 | ||
| 121 | impl Default for Config { | 146 | impl Default for Config { |
| @@ -130,6 +155,7 @@ impl Default for Config { | |||
| 130 | enable_lsi: false, | 155 | enable_lsi: false, |
| 131 | enable_rtc_apb: false, | 156 | enable_rtc_apb: false, |
| 132 | rtc_mux: RtcClockSource::LSI, | 157 | rtc_mux: RtcClockSource::LSI, |
| 158 | adc_clock_source: AdcClockSource::default(), | ||
| 133 | } | 159 | } |
| 134 | } | 160 | } |
| 135 | } | 161 | } |
| @@ -299,6 +325,9 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 299 | w.set_ppre2(config.apb2_pre.into()); | 325 | w.set_ppre2(config.apb2_pre.into()); |
| 300 | }); | 326 | }); |
| 301 | 327 | ||
| 328 | // ADC clock MUX | ||
| 329 | RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); | ||
| 330 | |||
| 302 | // TODO: switch voltage range | 331 | // TODO: switch voltage range |
| 303 | 332 | ||
| 304 | if config.enable_lsi { | 333 | if config.enable_lsi { |
