diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-02-09 15:27:35 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-02-09 15:27:35 +0000 |
| commit | 1d265b73b2f46baf60a481c8b8036e50c2b6583f (patch) | |
| tree | 862f3b9d41b38048d555e40e6e6425da29b0cf1d | |
| parent | 3d6b8bd9832d5a29cab4aa21434663e6ea6f4488 (diff) | |
| parent | 8160af6af99573d3ef66aede8c4b0aac033b0ff3 (diff) | |
Merge #601
601: [part 1/n] Change macrotables to build.rs codegen r=lulf a=Dirbaio
This PR replaces the "macrotables" (the macros like `stm32_data::peripherals!`) with a `const METADATA`.
Macrotables had some problems:
- Hard to debug
- Somewhat footgunny (typo the "pattern" and then nothing matches and the macro now expands to nothing, silently!)
- Limited power
- Can't count, so we had to add a [special macrotable for that](https://github.com/embassy-rs/embassy/blob/f50f3f0a73a41275e6ea21d8661081acad381e05/embassy-stm32/src/dma/bdma.rs#L26).
- Can't remove duplicates, so we had to fallback to [Rust code in build.rs](https://github.com/embassy-rs/embassy/blob/f50f3f0a73a41275e6ea21d8661081acad381e05/embassy-stm32/build.rs#L105-L145)
- Can't include the results as a listto another macro, so again [build.rs](https://github.com/embassy-rs/embassy/blob/master/embassy-stm32/build.rs#L100-L101).
They work fine for the 95% of cases, but for the remaining 5% we need Rust code in build.rs. So we might as well do everything with Rust code, so everything is consistent.
The new approach generates a `const METADATA: Metadata = Metadata { ... }` with [these structs](https://github.com/embassy-rs/embassy/blob/unmacrotablize/stm32-metapac-gen/src/assets/metadata.rs) in `stm32-metapac`. `build.rs` can then read that and generate whatever code.
Co-authored-by: Dario Nieuwenhuis <[email protected]>
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 284 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dmamux.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/gpio.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/interrupt.rs | 9 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 64 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/assets/metadata.rs | 97 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/lib.rs | 104 | ||||
| -rw-r--r-- | stm32-metapac/Cargo.toml | 8 |
12 files changed, 363 insertions, 239 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ebd62cbf7..386722d47 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -36,7 +36,9 @@ seq-macro = "0.2.2" | |||
| 36 | cfg-if = "1.0.0" | 36 | cfg-if = "1.0.0" |
| 37 | 37 | ||
| 38 | [build-dependencies] | 38 | [build-dependencies] |
| 39 | stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false } | 39 | proc-macro2 = "1.0.36" |
| 40 | quote = "1.0.15" | ||
| 41 | stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]} | ||
| 40 | 42 | ||
| 41 | [features] | 43 | [features] |
| 42 | sdmmc-rs = ["embedded-sdmmc"] | 44 | sdmmc-rs = ["embedded-sdmmc"] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index aee596445..6bef745f1 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -1,8 +1,10 @@ | |||
| 1 | use std::collections::HashMap; | 1 | use proc_macro2::TokenStream; |
| 2 | use quote::{format_ident, quote}; | ||
| 3 | use std::collections::HashSet; | ||
| 2 | use std::env; | 4 | use std::env; |
| 3 | use std::fmt::Write; | ||
| 4 | use std::fs; | 5 | use std::fs; |
| 5 | use std::path::PathBuf; | 6 | use std::path::PathBuf; |
| 7 | use stm32_metapac::metadata::METADATA; | ||
| 6 | 8 | ||
| 7 | fn main() { | 9 | fn main() { |
| 8 | let chip_name = match env::vars() | 10 | let chip_name = match env::vars() |
| @@ -18,67 +20,50 @@ fn main() { | |||
| 18 | .unwrap() | 20 | .unwrap() |
| 19 | .to_ascii_lowercase(); | 21 | .to_ascii_lowercase(); |
| 20 | 22 | ||
| 21 | struct Peripheral { | 23 | for p in METADATA.peripherals { |
| 22 | kind: String, | 24 | if let Some(r) = &p.registers { |
| 23 | name: String, | 25 | println!("cargo:rustc-cfg={}", r.kind); |
| 24 | version: String, | 26 | println!("cargo:rustc-cfg={}_{}", r.kind, r.version); |
| 27 | } | ||
| 25 | } | 28 | } |
| 26 | 29 | ||
| 27 | let mut peripheral_version_mapping = HashMap::<String, String>::new(); | ||
| 28 | stm32_metapac::peripheral_versions!( | ||
| 29 | ($peri:ident, $version:ident) => { | ||
| 30 | peripheral_version_mapping.insert(stringify!($peri).to_string(), stringify!($version).to_string()); | ||
| 31 | println!("cargo:rustc-cfg={}", stringify!($peri)); | ||
| 32 | println!("cargo:rustc-cfg={}_{}", stringify!($peri), stringify!($version)); | ||
| 33 | }; | ||
| 34 | ); | ||
| 35 | |||
| 36 | let mut peripherals: Vec<Peripheral> = Vec::new(); | ||
| 37 | stm32_metapac::peripherals!( | ||
| 38 | ($kind:ident, $name:ident) => { | ||
| 39 | peripherals.push(Peripheral{ | ||
| 40 | kind: stringify!($kind).to_string(), | ||
| 41 | name: stringify!($name).to_string(), | ||
| 42 | version: peripheral_version_mapping[&stringify!($kind).to_ascii_lowercase()].clone() | ||
| 43 | }); | ||
| 44 | }; | ||
| 45 | ); | ||
| 46 | |||
| 47 | // ======== | 30 | // ======== |
| 48 | // Generate singletons | 31 | // Generate singletons |
| 49 | 32 | ||
| 50 | let mut singletons: Vec<String> = Vec::new(); | 33 | let mut singletons: Vec<String> = Vec::new(); |
| 51 | for p in peripherals { | 34 | for p in METADATA.peripherals { |
| 52 | match p.kind.as_str() { | 35 | if let Some(r) = &p.registers { |
| 53 | // Generate singletons per pin, not per port | 36 | match r.kind { |
| 54 | "gpio" => { | 37 | // Generate singletons per pin, not per port |
| 55 | println!("{}", p.name); | 38 | "gpio" => { |
| 56 | let port_letter = p.name.strip_prefix("GPIO").unwrap(); | 39 | println!("{}", p.name); |
| 57 | for pin_num in 0..16 { | 40 | let port_letter = p.name.strip_prefix("GPIO").unwrap(); |
| 58 | singletons.push(format!("P{}{}", port_letter, pin_num)); | 41 | for pin_num in 0..16 { |
| 42 | singletons.push(format!("P{}{}", port_letter, pin_num)); | ||
| 43 | } | ||
| 59 | } | 44 | } |
| 60 | } | ||
| 61 | |||
| 62 | // No singleton for these, the HAL handles them specially. | ||
| 63 | "exti" => {} | ||
| 64 | 45 | ||
| 65 | // We *shouldn't* have singletons for these, but the HAL currently requires | 46 | // No singleton for these, the HAL handles them specially. |
| 66 | // singletons, for using with RccPeripheral to enable/disable clocks to them. | 47 | "exti" => {} |
| 67 | "rcc" => { | 48 | |
| 68 | if p.version == "h7" { | 49 | // We *shouldn't* have singletons for these, but the HAL currently requires |
| 69 | singletons.push("MCO1".to_string()); | 50 | // singletons, for using with RccPeripheral to enable/disable clocks to them. |
| 70 | singletons.push("MCO2".to_string()); | 51 | "rcc" => { |
| 52 | if r.version == "h7" { | ||
| 53 | singletons.push("MCO1".to_string()); | ||
| 54 | singletons.push("MCO2".to_string()); | ||
| 55 | } | ||
| 56 | singletons.push(p.name.to_string()); | ||
| 71 | } | 57 | } |
| 72 | singletons.push(p.name.clone()); | 58 | //"dbgmcu" => {} |
| 59 | //"syscfg" => {} | ||
| 60 | //"dma" => {} | ||
| 61 | //"bdma" => {} | ||
| 62 | //"dmamux" => {} | ||
| 63 | |||
| 64 | // For other peripherals, one singleton per peri | ||
| 65 | _ => singletons.push(p.name.to_string()), | ||
| 73 | } | 66 | } |
| 74 | //"dbgmcu" => {} | ||
| 75 | //"syscfg" => {} | ||
| 76 | //"dma" => {} | ||
| 77 | //"bdma" => {} | ||
| 78 | //"dmamux" => {} | ||
| 79 | |||
| 80 | // For other peripherals, one singleton per peri | ||
| 81 | _ => singletons.push(p.name.clone()), | ||
| 82 | } | 67 | } |
| 83 | } | 68 | } |
| 84 | 69 | ||
| @@ -88,60 +73,161 @@ fn main() { | |||
| 88 | } | 73 | } |
| 89 | 74 | ||
| 90 | // One singleton per DMA channel | 75 | // One singleton per DMA channel |
| 91 | stm32_metapac::dma_channels! { | 76 | for c in METADATA.dma_channels { |
| 92 | ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $ignore:tt) => { | 77 | singletons.push(c.name.to_string()); |
| 93 | singletons.push(stringify!($channel_peri).to_string()); | 78 | } |
| 94 | }; | 79 | |
| 80 | let mut g = TokenStream::new(); | ||
| 81 | |||
| 82 | let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect(); | ||
| 83 | g.extend(quote! { | ||
| 84 | embassy_hal_common::peripherals!(#(#singleton_tokens),*); | ||
| 85 | }); | ||
| 86 | |||
| 87 | // ======== | ||
| 88 | // Generate interrupt declarations | ||
| 89 | |||
| 90 | let mut irqs = Vec::new(); | ||
| 91 | for irq in METADATA.interrupts { | ||
| 92 | irqs.push(format_ident!("{}", irq.name)); | ||
| 95 | } | 93 | } |
| 96 | 94 | ||
| 97 | let mut generated = String::new(); | 95 | g.extend(quote! { |
| 98 | write!( | 96 | pub mod interrupt { |
| 99 | &mut generated, | 97 | use crate::pac::Interrupt as InterruptEnum; |
| 100 | "embassy_hal_common::peripherals!({});\n", | 98 | #( |
| 101 | singletons.join(",") | 99 | embassy::interrupt::declare!(#irqs); |
| 102 | ) | 100 | )* |
| 103 | .unwrap(); | 101 | } |
| 102 | }); | ||
| 104 | 103 | ||
| 105 | // ======== | 104 | // ======== |
| 106 | // Generate DMA IRQs. | 105 | // Generate DMA IRQs. |
| 107 | // This can't be done with macrotables alone because in many chips, one irq is shared between many | 106 | |
| 108 | // channels, so we have to deduplicate them. | 107 | let mut dma_irqs: HashSet<&str> = HashSet::new(); |
| 109 | 108 | let mut bdma_irqs: HashSet<&str> = HashSet::new(); | |
| 110 | #[allow(unused_mut)] | 109 | |
| 111 | let mut dma_irqs: Vec<String> = Vec::new(); | 110 | for p in METADATA.peripherals { |
| 112 | #[allow(unused_mut)] | 111 | if let Some(r) = &p.registers { |
| 113 | let mut bdma_irqs: Vec<String> = Vec::new(); | 112 | match r.kind { |
| 114 | 113 | "dma" => { | |
| 115 | stm32_metapac::interrupts! { | 114 | for irq in p.interrupts { |
| 116 | ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { | 115 | dma_irqs.insert(irq.interrupt); |
| 117 | dma_irqs.push(stringify!($irq).to_string()); | 116 | } |
| 118 | }; | 117 | } |
| 119 | ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { | 118 | "bdma" => { |
| 120 | bdma_irqs.push(stringify!($irq).to_string()); | 119 | for irq in p.interrupts { |
| 121 | }; | 120 | bdma_irqs.insert(irq.interrupt); |
| 121 | } | ||
| 122 | } | ||
| 123 | _ => {} | ||
| 124 | } | ||
| 125 | } | ||
| 122 | } | 126 | } |
| 123 | 127 | ||
| 124 | dma_irqs.sort(); | 128 | let tokens: Vec<_> = dma_irqs.iter().map(|s| format_ident!("{}", s)).collect(); |
| 125 | dma_irqs.dedup(); | 129 | g.extend(quote! { |
| 126 | bdma_irqs.sort(); | 130 | #( |
| 127 | bdma_irqs.dedup(); | 131 | #[crate::interrupt] |
| 128 | 132 | unsafe fn #tokens () { | |
| 129 | for irq in dma_irqs { | 133 | crate::dma::dma::on_irq(); |
| 130 | write!( | 134 | } |
| 131 | &mut generated, | 135 | )* |
| 132 | "#[crate::interrupt] unsafe fn {} () {{ crate::dma::dma::on_irq(); }}\n", | 136 | }); |
| 133 | irq | 137 | |
| 134 | ) | 138 | let tokens: Vec<_> = bdma_irqs.iter().map(|s| format_ident!("{}", s)).collect(); |
| 135 | .unwrap(); | 139 | g.extend(quote! { |
| 140 | #( | ||
| 141 | #[crate::interrupt] | ||
| 142 | unsafe fn #tokens () { | ||
| 143 | crate::dma::bdma::on_irq(); | ||
| 144 | } | ||
| 145 | )* | ||
| 146 | }); | ||
| 147 | |||
| 148 | // ======== | ||
| 149 | // Generate RccPeripheral impls | ||
| 150 | |||
| 151 | for p in METADATA.peripherals { | ||
| 152 | if !singletons.contains(&p.name.to_string()) { | ||
| 153 | continue; | ||
| 154 | } | ||
| 155 | |||
| 156 | if let Some(rcc) = &p.rcc { | ||
| 157 | let en = rcc.enable.as_ref().unwrap(); | ||
| 158 | |||
| 159 | let rst = match &rcc.reset { | ||
| 160 | Some(rst) => { | ||
| 161 | let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); | ||
| 162 | let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); | ||
| 163 | quote! { | ||
| 164 | critical_section::with(|_| unsafe { | ||
| 165 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); | ||
| 166 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); | ||
| 167 | }); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | None => TokenStream::new(), | ||
| 171 | }; | ||
| 172 | |||
| 173 | let pname = format_ident!("{}", p.name); | ||
| 174 | let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); | ||
| 175 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); | ||
| 176 | let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); | ||
| 177 | |||
| 178 | g.extend(quote! { | ||
| 179 | impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { | ||
| 180 | fn frequency() -> crate::time::Hertz { | ||
| 181 | critical_section::with(|_| unsafe { | ||
| 182 | crate::rcc::get_freqs().#clk | ||
| 183 | }) | ||
| 184 | } | ||
| 185 | fn enable() { | ||
| 186 | critical_section::with(|_| unsafe { | ||
| 187 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)) | ||
| 188 | }) | ||
| 189 | } | ||
| 190 | fn disable() { | ||
| 191 | critical_section::with(|_| unsafe { | ||
| 192 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); | ||
| 193 | }) | ||
| 194 | } | ||
| 195 | fn reset() { | ||
| 196 | #rst | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | impl crate::rcc::RccPeripheral for peripherals::#pname {} | ||
| 201 | }); | ||
| 202 | } | ||
| 136 | } | 203 | } |
| 137 | 204 | ||
| 138 | for irq in bdma_irqs { | 205 | // ======== |
| 139 | write!( | 206 | // Generate fns to enable GPIO, DMA in RCC |
| 140 | &mut generated, | 207 | |
| 141 | "#[crate::interrupt] unsafe fn {} () {{ crate::dma::bdma::on_irq(); }}\n", | 208 | for kind in ["dma", "bdma", "dmamux", "gpio"] { |
| 142 | irq | 209 | let mut gg = TokenStream::new(); |
| 143 | ) | 210 | |
| 144 | .unwrap(); | 211 | for p in METADATA.peripherals { |
| 212 | if p.registers.is_some() && p.registers.as_ref().unwrap().kind == kind { | ||
| 213 | if let Some(rcc) = &p.rcc { | ||
| 214 | let en = rcc.enable.as_ref().unwrap(); | ||
| 215 | let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); | ||
| 216 | let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); | ||
| 217 | |||
| 218 | gg.extend(quote! { | ||
| 219 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); | ||
| 220 | }) | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | let fname = format_ident!("init_{}", kind); | ||
| 226 | g.extend(quote! { | ||
| 227 | pub unsafe fn #fname(){ | ||
| 228 | #gg | ||
| 229 | } | ||
| 230 | }) | ||
| 145 | } | 231 | } |
| 146 | 232 | ||
| 147 | // ======== | 233 | // ======== |
| @@ -149,7 +235,7 @@ fn main() { | |||
| 149 | 235 | ||
| 150 | let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | 236 | let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
| 151 | let out_file = out_dir.join("generated.rs").to_string_lossy().to_string(); | 237 | let out_file = out_dir.join("generated.rs").to_string_lossy().to_string(); |
| 152 | fs::write(out_file, &generated).unwrap(); | 238 | fs::write(out_file, g.to_string()).unwrap(); |
| 153 | 239 | ||
| 154 | // ======== | 240 | // ======== |
| 155 | // Multicore | 241 | // Multicore |
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index ebb0467dc..a37de2d63 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -9,7 +9,6 @@ use embassy::waitqueue::AtomicWaker; | |||
| 9 | use crate::dma::Request; | 9 | use crate::dma::Request; |
| 10 | use crate::pac; | 10 | use crate::pac; |
| 11 | use crate::pac::bdma::vals; | 11 | use crate::pac::bdma::vals; |
| 12 | use crate::rcc::sealed::RccPeripheral; | ||
| 13 | 12 | ||
| 14 | use super::{Word, WordSize}; | 13 | use super::{Word, WordSize}; |
| 15 | 14 | ||
| @@ -77,11 +76,7 @@ pub(crate) unsafe fn init() { | |||
| 77 | crate::interrupt::$irq::steal().enable(); | 76 | crate::interrupt::$irq::steal().enable(); |
| 78 | }; | 77 | }; |
| 79 | } | 78 | } |
| 80 | pac::peripherals! { | 79 | crate::generated::init_bdma(); |
| 81 | (bdma, $peri:ident) => { | ||
| 82 | crate::peripherals::$peri::enable(); | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | } | 80 | } |
| 86 | 81 | ||
| 87 | pac::dma_channels! { | 82 | pac::dma_channels! { |
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 21623b90c..c885452b0 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -7,7 +7,6 @@ use embassy::waitqueue::AtomicWaker; | |||
| 7 | use crate::interrupt; | 7 | use crate::interrupt; |
| 8 | use crate::pac; | 8 | use crate::pac; |
| 9 | use crate::pac::dma::{regs, vals}; | 9 | use crate::pac::dma::{regs, vals}; |
| 10 | use crate::rcc::sealed::RccPeripheral; | ||
| 11 | 10 | ||
| 12 | use super::{Request, Word, WordSize}; | 11 | use super::{Request, Word, WordSize}; |
| 13 | 12 | ||
| @@ -74,11 +73,7 @@ pub(crate) unsafe fn init() { | |||
| 74 | interrupt::$irq::steal().enable(); | 73 | interrupt::$irq::steal().enable(); |
| 75 | }; | 74 | }; |
| 76 | } | 75 | } |
| 77 | pac::peripherals! { | 76 | crate::generated::init_dma(); |
| 78 | (dma, $peri:ident) => { | ||
| 79 | crate::peripherals::$peri::enable(); | ||
| 80 | }; | ||
| 81 | } | ||
| 82 | } | 77 | } |
| 83 | 78 | ||
| 84 | pac::dma_channels! { | 79 | pac::dma_channels! { |
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 83dcff4e8..fd076581b 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -49,11 +49,5 @@ pac::dma_channels! { | |||
| 49 | 49 | ||
| 50 | /// safety: must be called only once | 50 | /// safety: must be called only once |
| 51 | pub(crate) unsafe fn init() { | 51 | pub(crate) unsafe fn init() { |
| 52 | crate::pac::peripheral_rcc! { | 52 | crate::generated::init_dmamux(); |
| 53 | ($name:ident, dmamux, DMAMUX, $clock:ident, ($reg:ident, $field:ident, $set_field:ident), $rst:tt) => { | ||
| 54 | crate::pac::RCC.$reg().modify(|reg| { | ||
| 55 | reg.$set_field(true); | ||
| 56 | }); | ||
| 57 | }; | ||
| 58 | } | ||
| 59 | } | 53 | } |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index d4606716c..f154a66c4 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -608,13 +608,7 @@ crate::pac::pins!( | |||
| 608 | ); | 608 | ); |
| 609 | 609 | ||
| 610 | pub(crate) unsafe fn init() { | 610 | pub(crate) unsafe fn init() { |
| 611 | crate::pac::peripheral_rcc! { | 611 | crate::generated::init_gpio(); |
| 612 | ($name:ident, gpio, GPIO, $clock:ident, ($reg:ident, $field:ident, $set_field:ident), $rst:tt) => { | ||
| 613 | crate::pac::RCC.$reg().modify(|reg| { | ||
| 614 | reg.$set_field(true); | ||
| 615 | }); | ||
| 616 | }; | ||
| 617 | } | ||
| 618 | } | 612 | } |
| 619 | 613 | ||
| 620 | mod eh02 { | 614 | mod eh02 { |
diff --git a/embassy-stm32/src/interrupt.rs b/embassy-stm32/src/interrupt.rs index 27e441644..c757b790c 100644 --- a/embassy-stm32/src/interrupt.rs +++ b/embassy-stm32/src/interrupt.rs | |||
| @@ -3,11 +3,4 @@ pub use critical_section::CriticalSection; | |||
| 3 | pub use embassy::interrupt::{take, Interrupt}; | 3 | pub use embassy::interrupt::{take, Interrupt}; |
| 4 | pub use embassy_hal_common::interrupt::Priority4 as Priority; | 4 | pub use embassy_hal_common::interrupt::Priority4 as Priority; |
| 5 | 5 | ||
| 6 | use crate::pac::Interrupt as InterruptEnum; | 6 | pub use crate::generated::interrupt::*; |
| 7 | use embassy::interrupt::declare; | ||
| 8 | |||
| 9 | crate::pac::interrupts!( | ||
| 10 | ($name:ident) => { | ||
| 11 | declare!($name); | ||
| 12 | }; | ||
| 13 | ); | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 4bc044047..a910f6950 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -65,8 +65,6 @@ mod generated { | |||
| 65 | #![allow(unused_imports)] | 65 | #![allow(unused_imports)] |
| 66 | #![allow(non_snake_case)] | 66 | #![allow(non_snake_case)] |
| 67 | 67 | ||
| 68 | use crate::interrupt; | ||
| 69 | |||
| 70 | include!(concat!(env!("OUT_DIR"), "/generated.rs")); | 68 | include!(concat!(env!("OUT_DIR"), "/generated.rs")); |
| 71 | } | 69 | } |
| 72 | pub use embassy_macros::interrupt; | 70 | pub use embassy_macros::interrupt; |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 541d9c148..3aab01afd 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use crate::peripherals; | ||
| 4 | use crate::time::Hertz; | 3 | use crate::time::Hertz; |
| 5 | use core::mem::MaybeUninit; | 4 | use core::mem::MaybeUninit; |
| 6 | 5 | ||
| @@ -104,66 +103,3 @@ pub(crate) mod sealed { | |||
| 104 | } | 103 | } |
| 105 | 104 | ||
| 106 | pub trait RccPeripheral: sealed::RccPeripheral + 'static {} | 105 | pub trait RccPeripheral: sealed::RccPeripheral + 'static {} |
| 107 | |||
| 108 | crate::pac::peripheral_rcc!( | ||
| 109 | ($inst:ident, gpio, GPIO, $clk:ident, $en:tt, $rst:tt) => {}; | ||
| 110 | ($inst:ident, $module:ident, $block:ident, $clk:ident, ($en_reg:ident, $en_field:ident, $en_set_field:ident), ($rst_reg:ident, $rst_field:ident, $rst_set_field:ident)) => { | ||
| 111 | impl sealed::RccPeripheral for peripherals::$inst { | ||
| 112 | fn frequency() -> crate::time::Hertz { | ||
| 113 | critical_section::with(|_| { | ||
| 114 | unsafe { get_freqs().$clk } | ||
| 115 | }) | ||
| 116 | } | ||
| 117 | fn enable() { | ||
| 118 | critical_section::with(|_| { | ||
| 119 | unsafe { | ||
| 120 | crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(true)); | ||
| 121 | } | ||
| 122 | }) | ||
| 123 | } | ||
| 124 | fn disable() { | ||
| 125 | critical_section::with(|_| { | ||
| 126 | unsafe { | ||
| 127 | crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(false)); | ||
| 128 | } | ||
| 129 | }) | ||
| 130 | } | ||
| 131 | fn reset() { | ||
| 132 | critical_section::with(|_| { | ||
| 133 | unsafe { | ||
| 134 | crate::pac::RCC.$rst_reg().modify(|w| w.$rst_set_field(true)); | ||
| 135 | crate::pac::RCC.$rst_reg().modify(|w| w.$rst_set_field(false)); | ||
| 136 | } | ||
| 137 | }) | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | impl RccPeripheral for peripherals::$inst {} | ||
| 142 | }; | ||
| 143 | ($inst:ident, $module:ident, $block:ident, $clk:ident, ($en_reg:ident, $en_field:ident, $en_set_field:ident), _) => { | ||
| 144 | impl sealed::RccPeripheral for peripherals::$inst { | ||
| 145 | fn frequency() -> crate::time::Hertz { | ||
| 146 | critical_section::with(|_| { | ||
| 147 | unsafe { get_freqs().$clk } | ||
| 148 | }) | ||
| 149 | } | ||
| 150 | fn enable() { | ||
| 151 | critical_section::with(|_| { | ||
| 152 | unsafe { | ||
| 153 | crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(true)); | ||
| 154 | } | ||
| 155 | }) | ||
| 156 | } | ||
| 157 | fn disable() { | ||
| 158 | critical_section::with(|_| { | ||
| 159 | unsafe { | ||
| 160 | crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(false)); | ||
| 161 | } | ||
| 162 | }) | ||
| 163 | } | ||
| 164 | fn reset() {} | ||
| 165 | } | ||
| 166 | |||
| 167 | impl RccPeripheral for peripherals::$inst {} | ||
| 168 | }; | ||
| 169 | ); | ||
diff --git a/stm32-metapac-gen/src/assets/metadata.rs b/stm32-metapac-gen/src/assets/metadata.rs new file mode 100644 index 000000000..7fe49ceba --- /dev/null +++ b/stm32-metapac-gen/src/assets/metadata.rs | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 2 | pub struct Metadata { | ||
| 3 | pub name: &'static str, | ||
| 4 | pub family: &'static str, | ||
| 5 | pub line: &'static str, | ||
| 6 | pub memory: &'static [MemoryRegion], | ||
| 7 | pub peripherals: &'static [Peripheral], | ||
| 8 | pub interrupts: &'static [Interrupt], | ||
| 9 | pub dma_channels: &'static [DmaChannel], | ||
| 10 | } | ||
| 11 | |||
| 12 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 13 | pub struct MemoryRegion { | ||
| 14 | pub name: &'static str, | ||
| 15 | pub kind: MemoryRegionKind, | ||
| 16 | pub address: u32, | ||
| 17 | pub size: u32, | ||
| 18 | } | ||
| 19 | |||
| 20 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 21 | pub enum MemoryRegionKind { | ||
| 22 | Flash, | ||
| 23 | Ram, | ||
| 24 | } | ||
| 25 | |||
| 26 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 27 | pub struct Interrupt { | ||
| 28 | pub name: &'static str, | ||
| 29 | pub number: u32, | ||
| 30 | } | ||
| 31 | |||
| 32 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 33 | pub struct Package { | ||
| 34 | pub name: &'static str, | ||
| 35 | pub package: &'static str, | ||
| 36 | } | ||
| 37 | |||
| 38 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 39 | pub struct Peripheral { | ||
| 40 | pub name: &'static str, | ||
| 41 | pub address: u64, | ||
| 42 | pub registers: Option<PeripheralRegisters>, | ||
| 43 | pub rcc: Option<PeripheralRcc>, | ||
| 44 | pub pins: &'static [PeripheralPin], | ||
| 45 | pub dma_channels: &'static [PeripheralDmaChannel], | ||
| 46 | pub interrupts: &'static [PeripheralInterrupt], | ||
| 47 | } | ||
| 48 | |||
| 49 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 50 | pub struct PeripheralRegisters { | ||
| 51 | pub kind: &'static str, | ||
| 52 | pub version: &'static str, | ||
| 53 | pub block: &'static str, | ||
| 54 | } | ||
| 55 | |||
| 56 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 57 | pub struct PeripheralInterrupt { | ||
| 58 | pub signal: &'static str, | ||
| 59 | pub interrupt: &'static str, | ||
| 60 | } | ||
| 61 | |||
| 62 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 63 | pub struct PeripheralRcc { | ||
| 64 | pub clock: &'static str, | ||
| 65 | pub enable: Option<PeripheralRccRegister>, | ||
| 66 | pub reset: Option<PeripheralRccRegister>, | ||
| 67 | } | ||
| 68 | |||
| 69 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 70 | pub struct PeripheralRccRegister { | ||
| 71 | pub register: &'static str, | ||
| 72 | pub field: &'static str, | ||
| 73 | } | ||
| 74 | |||
| 75 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 76 | pub struct PeripheralPin { | ||
| 77 | pub pin: &'static str, | ||
| 78 | pub signal: &'static str, | ||
| 79 | pub af: Option<&'static str>, | ||
| 80 | } | ||
| 81 | |||
| 82 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 83 | pub struct DmaChannel { | ||
| 84 | pub name: &'static str, | ||
| 85 | pub dma: &'static str, | ||
| 86 | pub channel: u32, | ||
| 87 | pub dmamux: Option<&'static str>, | ||
| 88 | pub dmamux_channel: Option<u32>, | ||
| 89 | } | ||
| 90 | |||
| 91 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 92 | pub struct PeripheralDmaChannel { | ||
| 93 | pub signal: &'static str, | ||
| 94 | pub channel: Option<&'static str>, | ||
| 95 | pub dmamux: Option<&'static str>, | ||
| 96 | pub request: Option<u32>, | ||
| 97 | } | ||
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index fd8da8a6f..10d67869a 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs | |||
| @@ -16,6 +16,17 @@ use chiptool::{generate, ir, transform}; | |||
| 16 | mod data; | 16 | mod data; |
| 17 | use data::*; | 17 | use data::*; |
| 18 | 18 | ||
| 19 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
| 20 | struct Metadata<'a> { | ||
| 21 | name: &'a str, | ||
| 22 | family: &'a str, | ||
| 23 | line: &'a str, | ||
| 24 | memory: &'a [MemoryRegion], | ||
| 25 | peripherals: &'a [Peripheral], | ||
| 26 | interrupts: &'a [Interrupt], | ||
| 27 | dma_channels: &'a [DmaChannel], | ||
| 28 | } | ||
| 29 | |||
| 19 | fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) { | 30 | fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) { |
| 20 | write!( | 31 | write!( |
| 21 | out, | 32 | out, |
| @@ -115,7 +126,6 @@ pub fn gen_chip( | |||
| 115 | let mut interrupt_table: Vec<Vec<String>> = Vec::new(); | 126 | let mut interrupt_table: Vec<Vec<String>> = Vec::new(); |
| 116 | let mut peripherals_table: Vec<Vec<String>> = Vec::new(); | 127 | let mut peripherals_table: Vec<Vec<String>> = Vec::new(); |
| 117 | let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); | 128 | let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new(); |
| 118 | let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); | ||
| 119 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); | 129 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 120 | let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); | 130 | let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); |
| 121 | let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new(); | 131 | let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new(); |
| @@ -253,34 +263,6 @@ pub fn gen_chip( | |||
| 253 | } | 263 | } |
| 254 | _ => {} | 264 | _ => {} |
| 255 | } | 265 | } |
| 256 | |||
| 257 | if let Some(rcc) = &p.rcc { | ||
| 258 | let mut clock = rcc.clock.to_ascii_lowercase(); | ||
| 259 | if p.name.starts_with("TIM") { | ||
| 260 | clock = format!("{}_tim", clock) | ||
| 261 | } | ||
| 262 | |||
| 263 | let mut row = Vec::new(); | ||
| 264 | row.push(p.name.clone()); | ||
| 265 | row.push(bi.kind.clone()); | ||
| 266 | row.push(bi.block.clone()); | ||
| 267 | row.push(clock); | ||
| 268 | |||
| 269 | for reg in [&rcc.enable, &rcc.reset] { | ||
| 270 | if let Some(reg) = reg { | ||
| 271 | row.push(format!( | ||
| 272 | "({}, {}, set_{})", | ||
| 273 | reg.register.to_ascii_lowercase(), | ||
| 274 | reg.field.to_ascii_lowercase(), | ||
| 275 | reg.field.to_ascii_lowercase() | ||
| 276 | )); | ||
| 277 | } else { | ||
| 278 | row.push("_".to_string()) | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | peripheral_rcc_table.push(row); | ||
| 283 | } | ||
| 284 | } | 266 | } |
| 285 | 267 | ||
| 286 | dev.peripherals.push(ir_peri); | 268 | dev.peripherals.push(ir_peri); |
| @@ -384,12 +366,7 @@ pub fn gen_chip( | |||
| 384 | let mut device_x = String::new(); | 366 | let mut device_x = String::new(); |
| 385 | 367 | ||
| 386 | for irq in &core.interrupts { | 368 | for irq in &core.interrupts { |
| 387 | write!( | 369 | write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap(); |
| 388 | &mut device_x, | ||
| 389 | "PROVIDE({} = DefaultHandler);\n", | ||
| 390 | irq.name.to_ascii_uppercase() | ||
| 391 | ) | ||
| 392 | .unwrap(); | ||
| 393 | } | 370 | } |
| 394 | 371 | ||
| 395 | // ============================== | 372 | // ============================== |
| @@ -397,6 +374,7 @@ pub fn gen_chip( | |||
| 397 | 374 | ||
| 398 | let mut data = String::new(); | 375 | let mut data = String::new(); |
| 399 | 376 | ||
| 377 | write!(&mut data, "#[cfg(feature=\"metadata\")] pub mod metadata;").unwrap(); | ||
| 400 | write!(&mut data, "#[cfg(feature=\"pac\")] mod pac;").unwrap(); | 378 | write!(&mut data, "#[cfg(feature=\"pac\")] mod pac;").unwrap(); |
| 401 | write!(&mut data, "#[cfg(feature=\"pac\")] pub use pac::*; ").unwrap(); | 379 | write!(&mut data, "#[cfg(feature=\"pac\")] pub use pac::*; ").unwrap(); |
| 402 | 380 | ||
| @@ -415,7 +393,6 @@ pub fn gen_chip( | |||
| 415 | "peripheral_dma_channels", | 393 | "peripheral_dma_channels", |
| 416 | &peripheral_dma_channels_table, | 394 | &peripheral_dma_channels_table, |
| 417 | ); | 395 | ); |
| 418 | make_table(&mut data, "peripheral_rcc", &peripheral_rcc_table); | ||
| 419 | make_table(&mut data, "dma_channels", &dma_channels_table); | 396 | make_table(&mut data, "dma_channels", &dma_channels_table); |
| 420 | make_table(&mut data, "dbgmcu", &dbgmcu_table); | 397 | make_table(&mut data, "dbgmcu", &dbgmcu_table); |
| 421 | make_peripheral_counts(&mut data, &peripheral_counts); | 398 | make_peripheral_counts(&mut data, &peripheral_counts); |
| @@ -425,6 +402,38 @@ pub fn gen_chip( | |||
| 425 | file.write_all(data.as_bytes()).unwrap(); | 402 | file.write_all(data.as_bytes()).unwrap(); |
| 426 | 403 | ||
| 427 | // ============================== | 404 | // ============================== |
| 405 | // generate metadata.rs | ||
| 406 | |||
| 407 | let metadata = Metadata { | ||
| 408 | name: &chip.name, | ||
| 409 | family: &chip.family, | ||
| 410 | line: &chip.line, | ||
| 411 | memory: &chip.memory, | ||
| 412 | peripherals: &core.peripherals, | ||
| 413 | interrupts: &core.interrupts, | ||
| 414 | dma_channels: &core.dma_channels, | ||
| 415 | }; | ||
| 416 | let metadata = format!("{:#?}", metadata); | ||
| 417 | let metadata = metadata.replace("[\n", "&[\n"); | ||
| 418 | let metadata = metadata.replace("[],\n", "&[],\n"); | ||
| 419 | |||
| 420 | let mut data = String::new(); | ||
| 421 | |||
| 422 | write!( | ||
| 423 | &mut data, | ||
| 424 | " | ||
| 425 | include!(\"../../metadata.rs\"); | ||
| 426 | use MemoryRegionKind::*; | ||
| 427 | pub const METADATA: Metadata = {}; | ||
| 428 | ", | ||
| 429 | metadata | ||
| 430 | ) | ||
| 431 | .unwrap(); | ||
| 432 | |||
| 433 | let mut file = File::create(chip_dir.join("metadata.rs")).unwrap(); | ||
| 434 | file.write_all(data.as_bytes()).unwrap(); | ||
| 435 | |||
| 436 | // ============================== | ||
| 428 | // generate device.x | 437 | // generate device.x |
| 429 | 438 | ||
| 430 | File::create(chip_dir.join("device.x")) | 439 | File::create(chip_dir.join("device.x")) |
| @@ -462,7 +471,21 @@ pub fn gen(options: Options) { | |||
| 462 | for chip_name in &options.chips { | 471 | for chip_name in &options.chips { |
| 463 | println!("Generating {}...", chip_name); | 472 | println!("Generating {}...", chip_name); |
| 464 | 473 | ||
| 465 | let chip = load_chip(&options, chip_name); | 474 | let mut chip = load_chip(&options, chip_name); |
| 475 | |||
| 476 | // Cleanup | ||
| 477 | for core in &mut chip.cores { | ||
| 478 | for irq in &mut core.interrupts { | ||
| 479 | irq.name = irq.name.to_ascii_uppercase(); | ||
| 480 | } | ||
| 481 | for p in &mut core.peripherals { | ||
| 482 | for irq in &mut p.interrupts { | ||
| 483 | irq.interrupt = irq.interrupt.to_ascii_uppercase(); | ||
| 484 | } | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | // Generate | ||
| 466 | for (core_index, core) in chip.cores.iter().enumerate() { | 489 | for (core_index, core) in chip.cores.iter().enumerate() { |
| 467 | let chip_core_name = match chip.cores.len() { | 490 | let chip_core_name = match chip.cores.len() { |
| 468 | 1 => chip_name.clone(), | 491 | 1 => chip_name.clone(), |
| @@ -557,6 +580,13 @@ pub fn gen(options: Options) { | |||
| 557 | ) | 580 | ) |
| 558 | .unwrap(); | 581 | .unwrap(); |
| 559 | 582 | ||
| 583 | // Generate src/metadata.rs | ||
| 584 | fs::write( | ||
| 585 | options.out_dir.join("src").join("metadata.rs"), | ||
| 586 | include_bytes!("assets/metadata.rs"), | ||
| 587 | ) | ||
| 588 | .unwrap(); | ||
| 589 | |||
| 560 | // Generate Cargo.toml | 590 | // Generate Cargo.toml |
| 561 | const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES"; | 591 | const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES"; |
| 562 | const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES"; | 592 | const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES"; |
diff --git a/stm32-metapac/Cargo.toml b/stm32-metapac/Cargo.toml index 4115da349..5642af46e 100644 --- a/stm32-metapac/Cargo.toml +++ b/stm32-metapac/Cargo.toml | |||
| @@ -19,10 +19,14 @@ regex = "1.5.4" | |||
| 19 | default = ["pac"] | 19 | default = ["pac"] |
| 20 | 20 | ||
| 21 | # Build the actual PAC. Set by default. | 21 | # Build the actual PAC. Set by default. |
| 22 | # If not set, only the macrotables will be generated. You may want to not set it | 22 | # If you just want the metadata, unset it with `default-features = false`. |
| 23 | # if you're using stm32-metapac from a build.rs script to use the macros. | ||
| 24 | pac = [] | 23 | pac = [] |
| 25 | 24 | ||
| 25 | # Build the chip metadata. | ||
| 26 | # If set, a const `stm32_metapac::METADATA` will be exported, containing all the | ||
| 27 | # metadata for the currently selected chip. | ||
| 28 | metadata = [] | ||
| 29 | |||
| 26 | rt = ["cortex-m-rt/device"] | 30 | rt = ["cortex-m-rt/device"] |
| 27 | memory-x = [] | 31 | memory-x = [] |
| 28 | 32 | ||
