aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-09 15:27:35 +0000
committerGitHub <[email protected]>2022-02-09 15:27:35 +0000
commit1d265b73b2f46baf60a481c8b8036e50c2b6583f (patch)
tree862f3b9d41b38048d555e40e6e6425da29b0cf1d
parent3d6b8bd9832d5a29cab4aa21434663e6ea6f4488 (diff)
parent8160af6af99573d3ef66aede8c4b0aac033b0ff3 (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.toml4
-rw-r--r--embassy-stm32/build.rs284
-rw-r--r--embassy-stm32/src/dma/bdma.rs7
-rw-r--r--embassy-stm32/src/dma/dma.rs7
-rw-r--r--embassy-stm32/src/dma/dmamux.rs8
-rw-r--r--embassy-stm32/src/gpio.rs8
-rw-r--r--embassy-stm32/src/interrupt.rs9
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/rcc/mod.rs64
-rw-r--r--stm32-metapac-gen/src/assets/metadata.rs97
-rw-r--r--stm32-metapac-gen/src/lib.rs104
-rw-r--r--stm32-metapac/Cargo.toml8
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"
36cfg-if = "1.0.0" 36cfg-if = "1.0.0"
37 37
38[build-dependencies] 38[build-dependencies]
39stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false } 39proc-macro2 = "1.0.36"
40quote = "1.0.15"
41stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
40 42
41[features] 43[features]
42sdmmc-rs = ["embedded-sdmmc"] 44sdmmc-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 @@
1use std::collections::HashMap; 1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3use std::collections::HashSet;
2use std::env; 4use std::env;
3use std::fmt::Write;
4use std::fs; 5use std::fs;
5use std::path::PathBuf; 6use std::path::PathBuf;
7use stm32_metapac::metadata::METADATA;
6 8
7fn main() { 9fn 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;
9use crate::dma::Request; 9use crate::dma::Request;
10use crate::pac; 10use crate::pac;
11use crate::pac::bdma::vals; 11use crate::pac::bdma::vals;
12use crate::rcc::sealed::RccPeripheral;
13 12
14use super::{Word, WordSize}; 13use 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
87pac::dma_channels! { 82pac::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;
7use crate::interrupt; 7use crate::interrupt;
8use crate::pac; 8use crate::pac;
9use crate::pac::dma::{regs, vals}; 9use crate::pac::dma::{regs, vals};
10use crate::rcc::sealed::RccPeripheral;
11 10
12use super::{Request, Word, WordSize}; 11use 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
84pac::dma_channels! { 79pac::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
51pub(crate) unsafe fn init() { 51pub(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
610pub(crate) unsafe fn init() { 610pub(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
620mod eh02 { 614mod 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;
3pub use embassy::interrupt::{take, Interrupt}; 3pub use embassy::interrupt::{take, Interrupt};
4pub use embassy_hal_common::interrupt::Priority4 as Priority; 4pub use embassy_hal_common::interrupt::Priority4 as Priority;
5 5
6use crate::pac::Interrupt as InterruptEnum; 6pub use crate::generated::interrupt::*;
7use embassy::interrupt::declare;
8
9crate::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}
72pub use embassy_macros::interrupt; 70pub 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
3use crate::peripherals;
4use crate::time::Hertz; 3use crate::time::Hertz;
5use core::mem::MaybeUninit; 4use core::mem::MaybeUninit;
6 5
@@ -104,66 +103,3 @@ pub(crate) mod sealed {
104} 103}
105 104
106pub trait RccPeripheral: sealed::RccPeripheral + 'static {} 105pub trait RccPeripheral: sealed::RccPeripheral + 'static {}
107
108crate::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)]
2pub 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)]
13pub 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)]
21pub enum MemoryRegionKind {
22 Flash,
23 Ram,
24}
25
26#[derive(Debug, Eq, PartialEq, Clone)]
27pub struct Interrupt {
28 pub name: &'static str,
29 pub number: u32,
30}
31
32#[derive(Debug, Eq, PartialEq, Clone)]
33pub struct Package {
34 pub name: &'static str,
35 pub package: &'static str,
36}
37
38#[derive(Debug, Eq, PartialEq, Clone)]
39pub 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)]
50pub 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)]
57pub struct PeripheralInterrupt {
58 pub signal: &'static str,
59 pub interrupt: &'static str,
60}
61
62#[derive(Debug, Eq, PartialEq, Clone)]
63pub 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)]
70pub struct PeripheralRccRegister {
71 pub register: &'static str,
72 pub field: &'static str,
73}
74
75#[derive(Debug, Eq, PartialEq, Clone)]
76pub 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)]
83pub 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)]
92pub 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};
16mod data; 16mod data;
17use data::*; 17use data::*;
18 18
19#[derive(Debug, Eq, PartialEq, Clone)]
20struct 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
19fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) { 30fn 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"
19default = ["pac"] 19default = ["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.
24pac = [] 23pac = []
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.
28metadata = []
29
26rt = ["cortex-m-rt/device"] 30rt = ["cortex-m-rt/device"]
27memory-x = [] 31memory-x = []
28 32