diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-03-27 17:18:30 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-03-27 17:18:30 +0000 |
| commit | a211003021dee1cf1035557706e2e55d2c3608c9 (patch) | |
| tree | d841b2c4d87e851fa2951e3b7039b72c305e1244 | |
| parent | 5c68f0bae7c4091ad34fb2a671e08a614d9beb9a (diff) | |
| parent | 55a9bf98c56e3a03cdd79e9607fc964e78badf62 (diff) | |
Merge #678
678: Add minimal F2 family support r=Dirbaio a=Gekkio
Here's the bare minimum to support F2 family (207/217/205/215). A lot is missing in RCC (e.g. PLL support), but this is enough to have a working blinky example. The example is set up for a NUCLEO-F207ZG board which I don't have, but I've tested it on my custom board with a F215 and different pinout :sweat_smile:
After looking at other RCC implementation, I noticed there's two main API styles: a "low-level" API (e.g. L0) where the `Config` struct has dividers and other low-level "knobs", and a "high-level" API (e.g. F0) where it has desired clock frequencies and the RCC implementation figures out how to achieve them. Which one is preferred? Personally I like the low-level API slightly more, because it gives you the most control and it would be easy to also provide some functions to calculate the required parameters based on desired clock frequencies.
F2 has a nasty errata: a delay or DSB instruction must be added after every RCC peripheral clock enable. I've added this workaround to build.rs, but am not sure if this is the best approach. Any comments?
I'm planning to add PLL support too once I know which kind of API is preferred. Would you prefer a separate pull request for that, or should I continue working on this one?
Co-authored-by: Joonas Javanainen <[email protected]>
| -rwxr-xr-x | ci.sh | 2 | ||||
| -rwxr-xr-x | ci_stable.sh | 2 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 38 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f2.rs | 303 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 5 | ||||
| -rw-r--r-- | examples/stm32f2/.cargo/config | 6 | ||||
| -rw-r--r-- | examples/stm32f2/Cargo.toml | 21 | ||||
| -rw-r--r-- | examples/stm32f2/build.rs | 5 | ||||
| -rw-r--r-- | examples/stm32f2/src/bin/blinky.rs | 29 | ||||
| -rw-r--r-- | examples/stm32f2/src/example_common.rs | 19 | ||||
| -rw-r--r-- | stm32-gen-features/src/lib.rs | 3 |
12 files changed, 441 insertions, 4 deletions
| @@ -53,6 +53,7 @@ cargo batch \ | |||
| 53 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ | 53 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ |
| 54 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ | 54 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ |
| 55 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ | 55 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ |
| 56 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ | ||
| 56 | --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ | 57 | --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ |
| 57 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ | 58 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ |
| 58 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ | 59 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ |
| @@ -63,6 +64,7 @@ cargo batch \ | |||
| 63 | --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ | 64 | --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ |
| 64 | --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ | 65 | --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ |
| 65 | --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ | 66 | --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ |
| 67 | --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ | ||
| 66 | --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \ | 68 | --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \ |
| 67 | --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ | 69 | --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ |
| 68 | --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \ | 70 | --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \ |
diff --git a/ci_stable.sh b/ci_stable.sh index a1c6bd26e..4f604057d 100755 --- a/ci_stable.sh +++ b/ci_stable.sh | |||
| @@ -58,5 +58,7 @@ cargo batch \ | |||
| 58 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ | 58 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ |
| 59 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any \ | 59 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any \ |
| 60 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ | 60 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ |
| 61 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any \ | ||
| 62 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ | ||
| 61 | --- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf --bin raw_spawn \ | 63 | --- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf --bin raw_spawn \ |
| 62 | --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \ | 64 | --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \ |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 44c78dfef..8efa9a810 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -265,6 +265,44 @@ stm32f107rb = [ "stm32-metapac/stm32f107rb" ] | |||
| 265 | stm32f107rc = [ "stm32-metapac/stm32f107rc" ] | 265 | stm32f107rc = [ "stm32-metapac/stm32f107rc" ] |
| 266 | stm32f107vb = [ "stm32-metapac/stm32f107vb" ] | 266 | stm32f107vb = [ "stm32-metapac/stm32f107vb" ] |
| 267 | stm32f107vc = [ "stm32-metapac/stm32f107vc" ] | 267 | stm32f107vc = [ "stm32-metapac/stm32f107vc" ] |
| 268 | stm32f205rb = [ "stm32-metapac/stm32f205rb" ] | ||
| 269 | stm32f205rc = [ "stm32-metapac/stm32f205rc" ] | ||
| 270 | stm32f205re = [ "stm32-metapac/stm32f205re" ] | ||
| 271 | stm32f205rf = [ "stm32-metapac/stm32f205rf" ] | ||
| 272 | stm32f205rg = [ "stm32-metapac/stm32f205rg" ] | ||
| 273 | stm32f205vb = [ "stm32-metapac/stm32f205vb" ] | ||
| 274 | stm32f205vc = [ "stm32-metapac/stm32f205vc" ] | ||
| 275 | stm32f205ve = [ "stm32-metapac/stm32f205ve" ] | ||
| 276 | stm32f205vf = [ "stm32-metapac/stm32f205vf" ] | ||
| 277 | stm32f205vg = [ "stm32-metapac/stm32f205vg" ] | ||
| 278 | stm32f205zc = [ "stm32-metapac/stm32f205zc" ] | ||
| 279 | stm32f205ze = [ "stm32-metapac/stm32f205ze" ] | ||
| 280 | stm32f205zf = [ "stm32-metapac/stm32f205zf" ] | ||
| 281 | stm32f205zg = [ "stm32-metapac/stm32f205zg" ] | ||
| 282 | stm32f207ic = [ "stm32-metapac/stm32f207ic" ] | ||
| 283 | stm32f207ie = [ "stm32-metapac/stm32f207ie" ] | ||
| 284 | stm32f207if = [ "stm32-metapac/stm32f207if" ] | ||
| 285 | stm32f207ig = [ "stm32-metapac/stm32f207ig" ] | ||
| 286 | stm32f207vc = [ "stm32-metapac/stm32f207vc" ] | ||
| 287 | stm32f207ve = [ "stm32-metapac/stm32f207ve" ] | ||
| 288 | stm32f207vf = [ "stm32-metapac/stm32f207vf" ] | ||
| 289 | stm32f207vg = [ "stm32-metapac/stm32f207vg" ] | ||
| 290 | stm32f207zc = [ "stm32-metapac/stm32f207zc" ] | ||
| 291 | stm32f207ze = [ "stm32-metapac/stm32f207ze" ] | ||
| 292 | stm32f207zf = [ "stm32-metapac/stm32f207zf" ] | ||
| 293 | stm32f207zg = [ "stm32-metapac/stm32f207zg" ] | ||
| 294 | stm32f215re = [ "stm32-metapac/stm32f215re" ] | ||
| 295 | stm32f215rg = [ "stm32-metapac/stm32f215rg" ] | ||
| 296 | stm32f215ve = [ "stm32-metapac/stm32f215ve" ] | ||
| 297 | stm32f215vg = [ "stm32-metapac/stm32f215vg" ] | ||
| 298 | stm32f215ze = [ "stm32-metapac/stm32f215ze" ] | ||
| 299 | stm32f215zg = [ "stm32-metapac/stm32f215zg" ] | ||
| 300 | stm32f217ie = [ "stm32-metapac/stm32f217ie" ] | ||
| 301 | stm32f217ig = [ "stm32-metapac/stm32f217ig" ] | ||
| 302 | stm32f217ve = [ "stm32-metapac/stm32f217ve" ] | ||
| 303 | stm32f217vg = [ "stm32-metapac/stm32f217vg" ] | ||
| 304 | stm32f217ze = [ "stm32-metapac/stm32f217ze" ] | ||
| 305 | stm32f217zg = [ "stm32-metapac/stm32f217zg" ] | ||
| 268 | stm32f301c6 = [ "stm32-metapac/stm32f301c6" ] | 306 | stm32f301c6 = [ "stm32-metapac/stm32f301c6" ] |
| 269 | stm32f301c8 = [ "stm32-metapac/stm32f301c8" ] | 307 | stm32f301c8 = [ "stm32-metapac/stm32f301c8" ] |
| 270 | stm32f301k6 = [ "stm32-metapac/stm32f301k6" ] | 308 | stm32f301k6 = [ "stm32-metapac/stm32f301k6" ] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 4cba1c669..2c8409a35 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -166,6 +166,15 @@ fn main() { | |||
| 166 | None => TokenStream::new(), | 166 | None => TokenStream::new(), |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
| 169 | let after_enable = if chip_name.starts_with("stm32f2") { | ||
| 170 | // Errata: ES0005 - 2.1.11 Delay after an RCC peripheral clock enabling | ||
| 171 | quote! { | ||
| 172 | cortex_m::asm::dsb(); | ||
| 173 | } | ||
| 174 | } else { | ||
| 175 | TokenStream::new() | ||
| 176 | }; | ||
| 177 | |||
| 169 | let pname = format_ident!("{}", p.name); | 178 | let pname = format_ident!("{}", p.name); |
| 170 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); | 179 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); |
| 171 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); | 180 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); |
| @@ -180,7 +189,8 @@ fn main() { | |||
| 180 | } | 189 | } |
| 181 | fn enable() { | 190 | fn enable() { |
| 182 | critical_section::with(|_| unsafe { | 191 | critical_section::with(|_| unsafe { |
| 183 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)) | 192 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); |
| 193 | #after_enable | ||
| 184 | }) | 194 | }) |
| 185 | } | 195 | } |
| 186 | fn disable() { | 196 | fn disable() { |
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs new file mode 100644 index 000000000..bece046f8 --- /dev/null +++ b/embassy-stm32/src/rcc/f2.rs | |||
| @@ -0,0 +1,303 @@ | |||
| 1 | use core::ops::Div; | ||
| 2 | |||
| 3 | use crate::pac::flash::vals::Latency; | ||
| 4 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; | ||
| 5 | use crate::pac::{FLASH, RCC}; | ||
| 6 | use crate::rcc::{set_freqs, Clocks}; | ||
| 7 | use crate::time::Hertz; | ||
| 8 | |||
| 9 | /// HSI speed | ||
| 10 | pub const HSI: Hertz = Hertz(16_000_000); | ||
| 11 | |||
| 12 | /// System clock mux source | ||
| 13 | #[derive(Clone, Copy)] | ||
| 14 | pub enum ClockSrc { | ||
| 15 | HSE(Hertz, HSESrc), | ||
| 16 | HSI, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// HSE clock source | ||
| 20 | #[derive(Clone, Copy)] | ||
| 21 | pub enum HSESrc { | ||
| 22 | /// Crystal/ceramic resonator | ||
| 23 | Crystal, | ||
| 24 | /// External clock source, HSE bypassed | ||
| 25 | Bypass, | ||
| 26 | } | ||
| 27 | |||
| 28 | /// AHB prescaler | ||
| 29 | #[derive(Clone, Copy, PartialEq)] | ||
| 30 | pub enum AHBPrescaler { | ||
| 31 | NotDivided, | ||
| 32 | Div2, | ||
| 33 | Div4, | ||
| 34 | Div8, | ||
| 35 | Div16, | ||
| 36 | Div64, | ||
| 37 | Div128, | ||
| 38 | Div256, | ||
| 39 | Div512, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl Div<AHBPrescaler> for Hertz { | ||
| 43 | type Output = Hertz; | ||
| 44 | |||
| 45 | fn div(self, rhs: AHBPrescaler) -> Self::Output { | ||
| 46 | let divisor = match rhs { | ||
| 47 | AHBPrescaler::NotDivided => 1, | ||
| 48 | AHBPrescaler::Div2 => 2, | ||
| 49 | AHBPrescaler::Div4 => 4, | ||
| 50 | AHBPrescaler::Div8 => 8, | ||
| 51 | AHBPrescaler::Div16 => 16, | ||
| 52 | AHBPrescaler::Div64 => 64, | ||
| 53 | AHBPrescaler::Div128 => 128, | ||
| 54 | AHBPrescaler::Div256 => 256, | ||
| 55 | AHBPrescaler::Div512 => 512, | ||
| 56 | }; | ||
| 57 | Hertz(self.0 / divisor) | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | /// APB prescaler | ||
| 62 | #[derive(Clone, Copy)] | ||
| 63 | pub enum APBPrescaler { | ||
| 64 | NotDivided, | ||
| 65 | Div2, | ||
| 66 | Div4, | ||
| 67 | Div8, | ||
| 68 | Div16, | ||
| 69 | } | ||
| 70 | |||
| 71 | impl Div<APBPrescaler> for Hertz { | ||
| 72 | type Output = Hertz; | ||
| 73 | |||
| 74 | fn div(self, rhs: APBPrescaler) -> Self::Output { | ||
| 75 | let divisor = match rhs { | ||
| 76 | APBPrescaler::NotDivided => 1, | ||
| 77 | APBPrescaler::Div2 => 2, | ||
| 78 | APBPrescaler::Div4 => 4, | ||
| 79 | APBPrescaler::Div8 => 8, | ||
| 80 | APBPrescaler::Div16 => 16, | ||
| 81 | }; | ||
| 82 | Hertz(self.0 / divisor) | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | impl Into<Ppre> for APBPrescaler { | ||
| 87 | fn into(self) -> Ppre { | ||
| 88 | match self { | ||
| 89 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 90 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 91 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 92 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 93 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | impl Into<Hpre> for AHBPrescaler { | ||
| 99 | fn into(self) -> Hpre { | ||
| 100 | match self { | ||
| 101 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 102 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 103 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 104 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 105 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 106 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 107 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 108 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 109 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Voltage Range | ||
| 115 | /// | ||
| 116 | /// Represents the system supply voltage range | ||
| 117 | #[derive(Copy, Clone, PartialEq)] | ||
| 118 | pub enum VoltageRange { | ||
| 119 | /// 1.8 to 3.6 V | ||
| 120 | Min1V8, | ||
| 121 | /// 2.1 to 3.6 V | ||
| 122 | Min2V1, | ||
| 123 | /// 2.4 to 3.6 V | ||
| 124 | Min2V4, | ||
| 125 | /// 2.7 to 3.6 V | ||
| 126 | Min2V7, | ||
| 127 | } | ||
| 128 | |||
| 129 | impl VoltageRange { | ||
| 130 | const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> { | ||
| 131 | let ahb_freq = ahb_freq.0; | ||
| 132 | // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock | ||
| 133 | // frequency | ||
| 134 | match self { | ||
| 135 | VoltageRange::Min1V8 => { | ||
| 136 | if ahb_freq <= 16_000_000 { | ||
| 137 | Some(Latency::WS0) | ||
| 138 | } else if ahb_freq <= 32_000_000 { | ||
| 139 | Some(Latency::WS1) | ||
| 140 | } else if ahb_freq <= 48_000_000 { | ||
| 141 | Some(Latency::WS2) | ||
| 142 | } else if ahb_freq <= 64_000_000 { | ||
| 143 | Some(Latency::WS3) | ||
| 144 | } else if ahb_freq <= 80_000_000 { | ||
| 145 | Some(Latency::WS4) | ||
| 146 | } else if ahb_freq <= 96_000_000 { | ||
| 147 | Some(Latency::WS5) | ||
| 148 | } else if ahb_freq <= 112_000_000 { | ||
| 149 | Some(Latency::WS6) | ||
| 150 | } else if ahb_freq <= 120_000_000 { | ||
| 151 | Some(Latency::WS7) | ||
| 152 | } else { | ||
| 153 | None | ||
| 154 | } | ||
| 155 | } | ||
| 156 | VoltageRange::Min2V1 => { | ||
| 157 | if ahb_freq <= 18_000_000 { | ||
| 158 | Some(Latency::WS0) | ||
| 159 | } else if ahb_freq <= 36_000_000 { | ||
| 160 | Some(Latency::WS1) | ||
| 161 | } else if ahb_freq <= 54_000_000 { | ||
| 162 | Some(Latency::WS2) | ||
| 163 | } else if ahb_freq <= 72_000_000 { | ||
| 164 | Some(Latency::WS3) | ||
| 165 | } else if ahb_freq <= 90_000_000 { | ||
| 166 | Some(Latency::WS4) | ||
| 167 | } else if ahb_freq <= 108_000_000 { | ||
| 168 | Some(Latency::WS5) | ||
| 169 | } else if ahb_freq <= 120_000_000 { | ||
| 170 | Some(Latency::WS6) | ||
| 171 | } else { | ||
| 172 | None | ||
| 173 | } | ||
| 174 | } | ||
| 175 | VoltageRange::Min2V4 => { | ||
| 176 | if ahb_freq <= 24_000_000 { | ||
| 177 | Some(Latency::WS0) | ||
| 178 | } else if ahb_freq <= 48_000_000 { | ||
| 179 | Some(Latency::WS1) | ||
| 180 | } else if ahb_freq <= 72_000_000 { | ||
| 181 | Some(Latency::WS2) | ||
| 182 | } else if ahb_freq <= 96_000_000 { | ||
| 183 | Some(Latency::WS3) | ||
| 184 | } else if ahb_freq <= 120_000_000 { | ||
| 185 | Some(Latency::WS4) | ||
| 186 | } else { | ||
| 187 | None | ||
| 188 | } | ||
| 189 | } | ||
| 190 | VoltageRange::Min2V7 => { | ||
| 191 | if ahb_freq <= 30_000_000 { | ||
| 192 | Some(Latency::WS0) | ||
| 193 | } else if ahb_freq <= 60_000_000 { | ||
| 194 | Some(Latency::WS1) | ||
| 195 | } else if ahb_freq <= 90_000_000 { | ||
| 196 | Some(Latency::WS2) | ||
| 197 | } else if ahb_freq <= 120_000_000 { | ||
| 198 | Some(Latency::WS3) | ||
| 199 | } else { | ||
| 200 | None | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Clocks configuration | ||
| 208 | pub struct Config { | ||
| 209 | pub mux: ClockSrc, | ||
| 210 | pub voltage: VoltageRange, | ||
| 211 | pub ahb_pre: AHBPrescaler, | ||
| 212 | pub apb1_pre: APBPrescaler, | ||
| 213 | pub apb2_pre: APBPrescaler, | ||
| 214 | } | ||
| 215 | |||
| 216 | impl Default for Config { | ||
| 217 | #[inline] | ||
| 218 | fn default() -> Config { | ||
| 219 | Config { | ||
| 220 | voltage: VoltageRange::Min1V8, | ||
| 221 | mux: ClockSrc::HSI, | ||
| 222 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 223 | apb1_pre: APBPrescaler::NotDivided, | ||
| 224 | apb2_pre: APBPrescaler::NotDivided, | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | #[inline] | ||
| 230 | unsafe fn enable_hse(source: HSESrc) { | ||
| 231 | RCC.cr().write(|w| { | ||
| 232 | w.set_hsebyp(match source { | ||
| 233 | HSESrc::Bypass => true, | ||
| 234 | HSESrc::Crystal => false, | ||
| 235 | }); | ||
| 236 | w.set_hseon(true) | ||
| 237 | }); | ||
| 238 | while !RCC.cr().read().hserdy() {} | ||
| 239 | } | ||
| 240 | |||
| 241 | pub(crate) unsafe fn init(config: Config) { | ||
| 242 | let (sys_clk, sw) = match config.mux { | ||
| 243 | ClockSrc::HSI => { | ||
| 244 | // Enable HSI | ||
| 245 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 246 | while !RCC.cr().read().hsirdy() {} | ||
| 247 | |||
| 248 | (HSI, Sw::HSI) | ||
| 249 | } | ||
| 250 | ClockSrc::HSE(freq, source) => { | ||
| 251 | enable_hse(source); | ||
| 252 | (freq, Sw::HSE) | ||
| 253 | } | ||
| 254 | }; | ||
| 255 | // RM0033 Figure 9. Clock tree suggests max SYSCLK/HCLK is 168 MHz, but datasheet specifies PLL | ||
| 256 | // max output to be 120 MHz, so there's no way to get higher frequencies | ||
| 257 | assert!(sys_clk <= Hertz(120_000_000)); | ||
| 258 | |||
| 259 | let ahb_freq = sys_clk / config.ahb_pre; | ||
| 260 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | ||
| 261 | assert!(ahb_freq <= Hertz(120_000_000)); | ||
| 262 | |||
| 263 | let flash_ws = config.voltage.wait_states(ahb_freq).expect("Invalid HCLK"); | ||
| 264 | FLASH.acr().modify(|w| w.set_latency(flash_ws)); | ||
| 265 | |||
| 266 | RCC.cfgr().modify(|w| { | ||
| 267 | w.set_sw(sw.into()); | ||
| 268 | w.set_hpre(config.ahb_pre.into()); | ||
| 269 | w.set_ppre1(config.apb1_pre.into()); | ||
| 270 | w.set_ppre2(config.apb2_pre.into()); | ||
| 271 | }); | ||
| 272 | |||
| 273 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 274 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 275 | pre => { | ||
| 276 | let freq = ahb_freq / pre; | ||
| 277 | (freq, Hertz(freq.0 * 2)) | ||
| 278 | } | ||
| 279 | }; | ||
| 280 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | ||
| 281 | assert!(apb1_freq <= Hertz(30_000_000)); | ||
| 282 | |||
| 283 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 284 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 285 | pre => { | ||
| 286 | let freq = ahb_freq / pre; | ||
| 287 | (freq, Hertz(freq.0 * 2)) | ||
| 288 | } | ||
| 289 | }; | ||
| 290 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | ||
| 291 | assert!(apb2_freq <= Hertz(60_000_000)); | ||
| 292 | |||
| 293 | set_freqs(Clocks { | ||
| 294 | sys: sys_clk, | ||
| 295 | ahb1: ahb_freq, | ||
| 296 | ahb2: ahb_freq, | ||
| 297 | ahb3: ahb_freq, | ||
| 298 | apb1: apb1_freq, | ||
| 299 | apb1_tim: apb1_tim_freq, | ||
| 300 | apb2: apb2_freq, | ||
| 301 | apb2_tim: apb2_tim_freq, | ||
| 302 | }); | ||
| 303 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 01c66f76f..3090b416c 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -5,6 +5,7 @@ use core::mem::MaybeUninit; | |||
| 5 | 5 | ||
| 6 | #[cfg_attr(rcc_f0, path = "f0.rs")] | 6 | #[cfg_attr(rcc_f0, path = "f0.rs")] |
| 7 | #[cfg_attr(rcc_f1, path = "f1.rs")] | 7 | #[cfg_attr(rcc_f1, path = "f1.rs")] |
| 8 | #[cfg_attr(rcc_f2, path = "f2.rs")] | ||
| 8 | #[cfg_attr(rcc_f3, path = "f3.rs")] | 9 | #[cfg_attr(rcc_f3, path = "f3.rs")] |
| 9 | #[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] | 10 | #[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] |
| 10 | #[cfg_attr(rcc_f7, path = "f7.rs")] | 11 | #[cfg_attr(rcc_f7, path = "f7.rs")] |
| @@ -39,11 +40,11 @@ pub struct Clocks { | |||
| 39 | // AHB | 40 | // AHB |
| 40 | pub ahb1: Hertz, | 41 | pub ahb1: Hertz, |
| 41 | #[cfg(any( | 42 | #[cfg(any( |
| 42 | rcc_l4, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, rcc_wl5 | 43 | rcc_l4, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, rcc_wl5 |
| 43 | ))] | 44 | ))] |
| 44 | pub ahb2: Hertz, | 45 | pub ahb2: Hertz, |
| 45 | #[cfg(any( | 46 | #[cfg(any( |
| 46 | rcc_l4, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5 | 47 | rcc_l4, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5 |
| 47 | ))] | 48 | ))] |
| 48 | pub ahb3: Hertz, | 49 | pub ahb3: Hertz, |
| 49 | #[cfg(any(rcc_h7, rcc_h7ab))] | 50 | #[cfg(any(rcc_h7, rcc_h7ab))] |
diff --git a/examples/stm32f2/.cargo/config b/examples/stm32f2/.cargo/config new file mode 100644 index 000000000..30b6d1909 --- /dev/null +++ b/examples/stm32f2/.cargo/config | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace STM32F207ZGTx with your chip as listed in `probe-run --list-chips` | ||
| 3 | runner = "probe-run --chip STM32F207ZGTx" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv7m-none-eabi" | ||
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml new file mode 100644 index 000000000..ee1d7ce2b --- /dev/null +++ b/examples/stm32f2/Cargo.toml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | [package] | ||
| 2 | authors = ["Dario Nieuwenhuis <[email protected]>"] | ||
| 3 | edition = "2018" | ||
| 4 | name = "embassy-stm32f2-examples" | ||
| 5 | version = "0.1.0" | ||
| 6 | resolver = "2" | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } | ||
| 10 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | ||
| 11 | |||
| 12 | defmt = "0.3" | ||
| 13 | defmt-rtt = "0.3" | ||
| 14 | |||
| 15 | cortex-m = "0.7.3" | ||
| 16 | cortex-m-rt = "0.7.0" | ||
| 17 | embedded-hal = "0.2.6" | ||
| 18 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 19 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
| 20 | heapless = { version = "0.7.5", default-features = false } | ||
| 21 | nb = "1.0.0" | ||
diff --git a/examples/stm32f2/build.rs b/examples/stm32f2/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32f2/build.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | fn main() { | ||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 5 | } | ||
diff --git a/examples/stm32f2/src/bin/blinky.rs b/examples/stm32f2/src/bin/blinky.rs new file mode 100644 index 000000000..637c2f4fd --- /dev/null +++ b/examples/stm32f2/src/bin/blinky.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 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::{Duration, Timer}; | ||
| 10 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 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 led = Output::new(p.PB14, Level::High, Speed::Low); | ||
| 19 | |||
| 20 | loop { | ||
| 21 | info!("high"); | ||
| 22 | led.set_high(); | ||
| 23 | Timer::after(Duration::from_millis(1000)).await; | ||
| 24 | |||
| 25 | info!("low"); | ||
| 26 | led.set_low(); | ||
| 27 | Timer::after(Duration::from_millis(1000)).await; | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/examples/stm32f2/src/example_common.rs b/examples/stm32f2/src/example_common.rs new file mode 100644 index 000000000..e14517033 --- /dev/null +++ b/examples/stm32f2/src/example_common.rs | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use defmt_rtt as _; // global logger | ||
| 4 | use panic_probe as _; | ||
| 5 | |||
| 6 | pub use defmt::*; | ||
| 7 | |||
| 8 | use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| 9 | |||
| 10 | defmt::timestamp! { | ||
| 11 | "{=u64}", | ||
| 12 | { | ||
| 13 | static COUNT: AtomicUsize = AtomicUsize::new(0); | ||
| 14 | // NOTE(no-CAS) `timestamps` runs with interrupts disabled | ||
| 15 | let n = COUNT.load(Ordering::Relaxed); | ||
| 16 | COUNT.store(n + 1, Ordering::Relaxed); | ||
| 17 | n as u64 | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs index 1ab4865a4..d184827cc 100644 --- a/stm32-gen-features/src/lib.rs +++ b/stm32-gen-features/src/lib.rs | |||
| @@ -5,6 +5,7 @@ use std::{iter::FilterMap, path::Path, slice::Iter}; | |||
| 5 | const SUPPORTED_FAMILIES: &[&str] = &[ | 5 | const SUPPORTED_FAMILIES: &[&str] = &[ |
| 6 | "stm32f0", | 6 | "stm32f0", |
| 7 | "stm32f1", | 7 | "stm32f1", |
| 8 | "stm32f2", | ||
| 8 | "stm32f3", | 9 | "stm32f3", |
| 9 | "stm32f4", | 10 | "stm32f4", |
| 10 | "stm32f7", | 11 | "stm32f7", |
| @@ -52,7 +53,7 @@ impl FilterSupported for &[(String, Vec<String>)] { | |||
| 52 | /// | 53 | /// |
| 53 | /// This function is slow because all the yaml files are parsed. | 54 | /// This function is slow because all the yaml files are parsed. |
| 54 | pub fn chip_names_and_cores() -> Vec<(String, Vec<String>)> { | 55 | pub fn chip_names_and_cores() -> Vec<(String, Vec<String>)> { |
| 55 | glob::glob("../stm32-data/data/chips/*.yaml") | 56 | glob::glob("../stm32-data/data/chips/*.json") |
| 56 | .unwrap() | 57 | .unwrap() |
| 57 | .filter_map(|entry| entry.map_err(|e| eprintln!("{:?}", e)).ok()) | 58 | .filter_map(|entry| entry.map_err(|e| eprintln!("{:?}", e)).ok()) |
| 58 | .filter_map(|entry| { | 59 | .filter_map(|entry| { |
