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](f50f3f0a73/embassy-stm32/src/dma/bdma.rs (L26)
). - Can't remove duplicates, so we had to fallback to [Rust code in build.rs](f50f3f0a73/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 <dirbaio@dirbaio.net>
This commit is contained in:
commit
1d265b73b2
@ -36,7 +36,9 @@ seq-macro = "0.2.2"
|
|||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false }
|
proc-macro2 = "1.0.36"
|
||||||
|
quote = "1.0.15"
|
||||||
|
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
sdmmc-rs = ["embedded-sdmmc"]
|
sdmmc-rs = ["embedded-sdmmc"]
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Write;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use stm32_metapac::metadata::METADATA;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let chip_name = match env::vars()
|
let chip_name = match env::vars()
|
||||||
@ -18,67 +20,50 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_ascii_lowercase();
|
.to_ascii_lowercase();
|
||||||
|
|
||||||
struct Peripheral {
|
for p in METADATA.peripherals {
|
||||||
kind: String,
|
if let Some(r) = &p.registers {
|
||||||
name: String,
|
println!("cargo:rustc-cfg={}", r.kind);
|
||||||
version: String,
|
println!("cargo:rustc-cfg={}_{}", r.kind, r.version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut peripheral_version_mapping = HashMap::<String, String>::new();
|
|
||||||
stm32_metapac::peripheral_versions!(
|
|
||||||
($peri:ident, $version:ident) => {
|
|
||||||
peripheral_version_mapping.insert(stringify!($peri).to_string(), stringify!($version).to_string());
|
|
||||||
println!("cargo:rustc-cfg={}", stringify!($peri));
|
|
||||||
println!("cargo:rustc-cfg={}_{}", stringify!($peri), stringify!($version));
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut peripherals: Vec<Peripheral> = Vec::new();
|
|
||||||
stm32_metapac::peripherals!(
|
|
||||||
($kind:ident, $name:ident) => {
|
|
||||||
peripherals.push(Peripheral{
|
|
||||||
kind: stringify!($kind).to_string(),
|
|
||||||
name: stringify!($name).to_string(),
|
|
||||||
version: peripheral_version_mapping[&stringify!($kind).to_ascii_lowercase()].clone()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
// Generate singletons
|
// Generate singletons
|
||||||
|
|
||||||
let mut singletons: Vec<String> = Vec::new();
|
let mut singletons: Vec<String> = Vec::new();
|
||||||
for p in peripherals {
|
for p in METADATA.peripherals {
|
||||||
match p.kind.as_str() {
|
if let Some(r) = &p.registers {
|
||||||
// Generate singletons per pin, not per port
|
match r.kind {
|
||||||
"gpio" => {
|
// Generate singletons per pin, not per port
|
||||||
println!("{}", p.name);
|
"gpio" => {
|
||||||
let port_letter = p.name.strip_prefix("GPIO").unwrap();
|
println!("{}", p.name);
|
||||||
for pin_num in 0..16 {
|
let port_letter = p.name.strip_prefix("GPIO").unwrap();
|
||||||
singletons.push(format!("P{}{}", port_letter, pin_num));
|
for pin_num in 0..16 {
|
||||||
|
singletons.push(format!("P{}{}", port_letter, pin_num));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// No singleton for these, the HAL handles them specially.
|
// No singleton for these, the HAL handles them specially.
|
||||||
"exti" => {}
|
"exti" => {}
|
||||||
|
|
||||||
// We *shouldn't* have singletons for these, but the HAL currently requires
|
// We *shouldn't* have singletons for these, but the HAL currently requires
|
||||||
// singletons, for using with RccPeripheral to enable/disable clocks to them.
|
// singletons, for using with RccPeripheral to enable/disable clocks to them.
|
||||||
"rcc" => {
|
"rcc" => {
|
||||||
if p.version == "h7" {
|
if r.version == "h7" {
|
||||||
singletons.push("MCO1".to_string());
|
singletons.push("MCO1".to_string());
|
||||||
singletons.push("MCO2".to_string());
|
singletons.push("MCO2".to_string());
|
||||||
|
}
|
||||||
|
singletons.push(p.name.to_string());
|
||||||
}
|
}
|
||||||
singletons.push(p.name.clone());
|
//"dbgmcu" => {}
|
||||||
}
|
//"syscfg" => {}
|
||||||
//"dbgmcu" => {}
|
//"dma" => {}
|
||||||
//"syscfg" => {}
|
//"bdma" => {}
|
||||||
//"dma" => {}
|
//"dmamux" => {}
|
||||||
//"bdma" => {}
|
|
||||||
//"dmamux" => {}
|
|
||||||
|
|
||||||
// For other peripherals, one singleton per peri
|
// For other peripherals, one singleton per peri
|
||||||
_ => singletons.push(p.name.clone()),
|
_ => singletons.push(p.name.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,60 +73,161 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// One singleton per DMA channel
|
// One singleton per DMA channel
|
||||||
stm32_metapac::dma_channels! {
|
for c in METADATA.dma_channels {
|
||||||
($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $ignore:tt) => {
|
singletons.push(c.name.to_string());
|
||||||
singletons.push(stringify!($channel_peri).to_string());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut generated = String::new();
|
let mut g = TokenStream::new();
|
||||||
write!(
|
|
||||||
&mut generated,
|
let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect();
|
||||||
"embassy_hal_common::peripherals!({});\n",
|
g.extend(quote! {
|
||||||
singletons.join(",")
|
embassy_hal_common::peripherals!(#(#singleton_tokens),*);
|
||||||
)
|
});
|
||||||
.unwrap();
|
|
||||||
|
// ========
|
||||||
|
// Generate interrupt declarations
|
||||||
|
|
||||||
|
let mut irqs = Vec::new();
|
||||||
|
for irq in METADATA.interrupts {
|
||||||
|
irqs.push(format_ident!("{}", irq.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
g.extend(quote! {
|
||||||
|
pub mod interrupt {
|
||||||
|
use crate::pac::Interrupt as InterruptEnum;
|
||||||
|
#(
|
||||||
|
embassy::interrupt::declare!(#irqs);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
// Generate DMA IRQs.
|
// Generate DMA IRQs.
|
||||||
// This can't be done with macrotables alone because in many chips, one irq is shared between many
|
|
||||||
// channels, so we have to deduplicate them.
|
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
let mut dma_irqs: HashSet<&str> = HashSet::new();
|
||||||
let mut dma_irqs: Vec<String> = Vec::new();
|
let mut bdma_irqs: HashSet<&str> = HashSet::new();
|
||||||
#[allow(unused_mut)]
|
|
||||||
let mut bdma_irqs: Vec<String> = Vec::new();
|
|
||||||
|
|
||||||
stm32_metapac::interrupts! {
|
for p in METADATA.peripherals {
|
||||||
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
|
if let Some(r) = &p.registers {
|
||||||
dma_irqs.push(stringify!($irq).to_string());
|
match r.kind {
|
||||||
};
|
"dma" => {
|
||||||
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
for irq in p.interrupts {
|
||||||
bdma_irqs.push(stringify!($irq).to_string());
|
dma_irqs.insert(irq.interrupt);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
"bdma" => {
|
||||||
|
for irq in p.interrupts {
|
||||||
|
bdma_irqs.insert(irq.interrupt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dma_irqs.sort();
|
let tokens: Vec<_> = dma_irqs.iter().map(|s| format_ident!("{}", s)).collect();
|
||||||
dma_irqs.dedup();
|
g.extend(quote! {
|
||||||
bdma_irqs.sort();
|
#(
|
||||||
bdma_irqs.dedup();
|
#[crate::interrupt]
|
||||||
|
unsafe fn #tokens () {
|
||||||
|
crate::dma::dma::on_irq();
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
});
|
||||||
|
|
||||||
for irq in dma_irqs {
|
let tokens: Vec<_> = bdma_irqs.iter().map(|s| format_ident!("{}", s)).collect();
|
||||||
write!(
|
g.extend(quote! {
|
||||||
&mut generated,
|
#(
|
||||||
"#[crate::interrupt] unsafe fn {} () {{ crate::dma::dma::on_irq(); }}\n",
|
#[crate::interrupt]
|
||||||
irq
|
unsafe fn #tokens () {
|
||||||
)
|
crate::dma::bdma::on_irq();
|
||||||
.unwrap();
|
}
|
||||||
|
)*
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========
|
||||||
|
// Generate RccPeripheral impls
|
||||||
|
|
||||||
|
for p in METADATA.peripherals {
|
||||||
|
if !singletons.contains(&p.name.to_string()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rcc) = &p.rcc {
|
||||||
|
let en = rcc.enable.as_ref().unwrap();
|
||||||
|
|
||||||
|
let rst = match &rcc.reset {
|
||||||
|
Some(rst) => {
|
||||||
|
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
|
||||||
|
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
|
||||||
|
quote! {
|
||||||
|
critical_section::with(|_| unsafe {
|
||||||
|
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
|
||||||
|
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => TokenStream::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pname = format_ident!("{}", p.name);
|
||||||
|
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
|
||||||
|
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||||
|
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
||||||
|
|
||||||
|
g.extend(quote! {
|
||||||
|
impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
|
||||||
|
fn frequency() -> crate::time::Hertz {
|
||||||
|
critical_section::with(|_| unsafe {
|
||||||
|
crate::rcc::get_freqs().#clk
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn enable() {
|
||||||
|
critical_section::with(|_| unsafe {
|
||||||
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn disable() {
|
||||||
|
critical_section::with(|_| unsafe {
|
||||||
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn reset() {
|
||||||
|
#rst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::rcc::RccPeripheral for peripherals::#pname {}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for irq in bdma_irqs {
|
// ========
|
||||||
write!(
|
// Generate fns to enable GPIO, DMA in RCC
|
||||||
&mut generated,
|
|
||||||
"#[crate::interrupt] unsafe fn {} () {{ crate::dma::bdma::on_irq(); }}\n",
|
for kind in ["dma", "bdma", "dmamux", "gpio"] {
|
||||||
irq
|
let mut gg = TokenStream::new();
|
||||||
)
|
|
||||||
.unwrap();
|
for p in METADATA.peripherals {
|
||||||
|
if p.registers.is_some() && p.registers.as_ref().unwrap().kind == kind {
|
||||||
|
if let Some(rcc) = &p.rcc {
|
||||||
|
let en = rcc.enable.as_ref().unwrap();
|
||||||
|
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||||
|
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
||||||
|
|
||||||
|
gg.extend(quote! {
|
||||||
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fname = format_ident!("init_{}", kind);
|
||||||
|
g.extend(quote! {
|
||||||
|
pub unsafe fn #fname(){
|
||||||
|
#gg
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
@ -149,7 +235,7 @@ fn main() {
|
|||||||
|
|
||||||
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
let out_file = out_dir.join("generated.rs").to_string_lossy().to_string();
|
let out_file = out_dir.join("generated.rs").to_string_lossy().to_string();
|
||||||
fs::write(out_file, &generated).unwrap();
|
fs::write(out_file, g.to_string()).unwrap();
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
// Multicore
|
// Multicore
|
||||||
|
@ -9,7 +9,6 @@ use embassy::waitqueue::AtomicWaker;
|
|||||||
use crate::dma::Request;
|
use crate::dma::Request;
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::pac::bdma::vals;
|
use crate::pac::bdma::vals;
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
|
||||||
|
|
||||||
use super::{Word, WordSize};
|
use super::{Word, WordSize};
|
||||||
|
|
||||||
@ -77,11 +76,7 @@ pub(crate) unsafe fn init() {
|
|||||||
crate::interrupt::$irq::steal().enable();
|
crate::interrupt::$irq::steal().enable();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pac::peripherals! {
|
crate::generated::init_bdma();
|
||||||
(bdma, $peri:ident) => {
|
|
||||||
crate::peripherals::$peri::enable();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pac::dma_channels! {
|
pac::dma_channels! {
|
||||||
|
@ -7,7 +7,6 @@ use embassy::waitqueue::AtomicWaker;
|
|||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::pac::dma::{regs, vals};
|
use crate::pac::dma::{regs, vals};
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
|
||||||
|
|
||||||
use super::{Request, Word, WordSize};
|
use super::{Request, Word, WordSize};
|
||||||
|
|
||||||
@ -74,11 +73,7 @@ pub(crate) unsafe fn init() {
|
|||||||
interrupt::$irq::steal().enable();
|
interrupt::$irq::steal().enable();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pac::peripherals! {
|
crate::generated::init_dma();
|
||||||
(dma, $peri:ident) => {
|
|
||||||
crate::peripherals::$peri::enable();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pac::dma_channels! {
|
pac::dma_channels! {
|
||||||
|
@ -49,11 +49,5 @@ pac::dma_channels! {
|
|||||||
|
|
||||||
/// safety: must be called only once
|
/// safety: must be called only once
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
crate::pac::peripheral_rcc! {
|
crate::generated::init_dmamux();
|
||||||
($name:ident, dmamux, DMAMUX, $clock:ident, ($reg:ident, $field:ident, $set_field:ident), $rst:tt) => {
|
|
||||||
crate::pac::RCC.$reg().modify(|reg| {
|
|
||||||
reg.$set_field(true);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -608,13 +608,7 @@ crate::pac::pins!(
|
|||||||
);
|
);
|
||||||
|
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
crate::pac::peripheral_rcc! {
|
crate::generated::init_gpio();
|
||||||
($name:ident, gpio, GPIO, $clock:ident, ($reg:ident, $field:ident, $set_field:ident), $rst:tt) => {
|
|
||||||
crate::pac::RCC.$reg().modify(|reg| {
|
|
||||||
reg.$set_field(true);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod eh02 {
|
mod eh02 {
|
||||||
|
@ -3,11 +3,4 @@ pub use critical_section::CriticalSection;
|
|||||||
pub use embassy::interrupt::{take, Interrupt};
|
pub use embassy::interrupt::{take, Interrupt};
|
||||||
pub use embassy_hal_common::interrupt::Priority4 as Priority;
|
pub use embassy_hal_common::interrupt::Priority4 as Priority;
|
||||||
|
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
pub use crate::generated::interrupt::*;
|
||||||
use embassy::interrupt::declare;
|
|
||||||
|
|
||||||
crate::pac::interrupts!(
|
|
||||||
($name:ident) => {
|
|
||||||
declare!($name);
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
@ -65,8 +65,6 @@ mod generated {
|
|||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::interrupt;
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||||
}
|
}
|
||||||
pub use embassy_macros::interrupt;
|
pub use embassy_macros::interrupt;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use crate::peripherals;
|
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
@ -104,66 +103,3 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait RccPeripheral: sealed::RccPeripheral + 'static {}
|
pub trait RccPeripheral: sealed::RccPeripheral + 'static {}
|
||||||
|
|
||||||
crate::pac::peripheral_rcc!(
|
|
||||||
($inst:ident, gpio, GPIO, $clk:ident, $en:tt, $rst:tt) => {};
|
|
||||||
($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)) => {
|
|
||||||
impl sealed::RccPeripheral for peripherals::$inst {
|
|
||||||
fn frequency() -> crate::time::Hertz {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe { get_freqs().$clk }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn enable() {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe {
|
|
||||||
crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(true));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn disable() {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe {
|
|
||||||
crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(false));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn reset() {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe {
|
|
||||||
crate::pac::RCC.$rst_reg().modify(|w| w.$rst_set_field(true));
|
|
||||||
crate::pac::RCC.$rst_reg().modify(|w| w.$rst_set_field(false));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RccPeripheral for peripherals::$inst {}
|
|
||||||
};
|
|
||||||
($inst:ident, $module:ident, $block:ident, $clk:ident, ($en_reg:ident, $en_field:ident, $en_set_field:ident), _) => {
|
|
||||||
impl sealed::RccPeripheral for peripherals::$inst {
|
|
||||||
fn frequency() -> crate::time::Hertz {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe { get_freqs().$clk }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn enable() {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe {
|
|
||||||
crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(true));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn disable() {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
unsafe {
|
|
||||||
crate::pac::RCC.$en_reg().modify(|w| w.$en_set_field(false));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn reset() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RccPeripheral for peripherals::$inst {}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
97
stm32-metapac-gen/src/assets/metadata.rs
Normal file
97
stm32-metapac-gen/src/assets/metadata.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct Metadata {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub family: &'static str,
|
||||||
|
pub line: &'static str,
|
||||||
|
pub memory: &'static [MemoryRegion],
|
||||||
|
pub peripherals: &'static [Peripheral],
|
||||||
|
pub interrupts: &'static [Interrupt],
|
||||||
|
pub dma_channels: &'static [DmaChannel],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct MemoryRegion {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub kind: MemoryRegionKind,
|
||||||
|
pub address: u32,
|
||||||
|
pub size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub enum MemoryRegionKind {
|
||||||
|
Flash,
|
||||||
|
Ram,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct Interrupt {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub number: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct Package {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub package: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct Peripheral {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub address: u64,
|
||||||
|
pub registers: Option<PeripheralRegisters>,
|
||||||
|
pub rcc: Option<PeripheralRcc>,
|
||||||
|
pub pins: &'static [PeripheralPin],
|
||||||
|
pub dma_channels: &'static [PeripheralDmaChannel],
|
||||||
|
pub interrupts: &'static [PeripheralInterrupt],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct PeripheralRegisters {
|
||||||
|
pub kind: &'static str,
|
||||||
|
pub version: &'static str,
|
||||||
|
pub block: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct PeripheralInterrupt {
|
||||||
|
pub signal: &'static str,
|
||||||
|
pub interrupt: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct PeripheralRcc {
|
||||||
|
pub clock: &'static str,
|
||||||
|
pub enable: Option<PeripheralRccRegister>,
|
||||||
|
pub reset: Option<PeripheralRccRegister>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct PeripheralRccRegister {
|
||||||
|
pub register: &'static str,
|
||||||
|
pub field: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct PeripheralPin {
|
||||||
|
pub pin: &'static str,
|
||||||
|
pub signal: &'static str,
|
||||||
|
pub af: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct DmaChannel {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub dma: &'static str,
|
||||||
|
pub channel: u32,
|
||||||
|
pub dmamux: Option<&'static str>,
|
||||||
|
pub dmamux_channel: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct PeripheralDmaChannel {
|
||||||
|
pub signal: &'static str,
|
||||||
|
pub channel: Option<&'static str>,
|
||||||
|
pub dmamux: Option<&'static str>,
|
||||||
|
pub request: Option<u32>,
|
||||||
|
}
|
@ -16,6 +16,17 @@ use chiptool::{generate, ir, transform};
|
|||||||
mod data;
|
mod data;
|
||||||
use data::*;
|
use data::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
struct Metadata<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
family: &'a str,
|
||||||
|
line: &'a str,
|
||||||
|
memory: &'a [MemoryRegion],
|
||||||
|
peripherals: &'a [Peripheral],
|
||||||
|
interrupts: &'a [Interrupt],
|
||||||
|
dma_channels: &'a [DmaChannel],
|
||||||
|
}
|
||||||
|
|
||||||
fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) {
|
fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) {
|
||||||
write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
@ -115,7 +126,6 @@ pub fn gen_chip(
|
|||||||
let mut interrupt_table: Vec<Vec<String>> = Vec::new();
|
let mut interrupt_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripherals_table: Vec<Vec<String>> = Vec::new();
|
let mut peripherals_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new();
|
let mut peripheral_pins_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new();
|
|
||||||
let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
|
let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
|
let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new();
|
let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new();
|
||||||
@ -253,34 +263,6 @@ pub fn gen_chip(
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rcc) = &p.rcc {
|
|
||||||
let mut clock = rcc.clock.to_ascii_lowercase();
|
|
||||||
if p.name.starts_with("TIM") {
|
|
||||||
clock = format!("{}_tim", clock)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut row = Vec::new();
|
|
||||||
row.push(p.name.clone());
|
|
||||||
row.push(bi.kind.clone());
|
|
||||||
row.push(bi.block.clone());
|
|
||||||
row.push(clock);
|
|
||||||
|
|
||||||
for reg in [&rcc.enable, &rcc.reset] {
|
|
||||||
if let Some(reg) = reg {
|
|
||||||
row.push(format!(
|
|
||||||
"({}, {}, set_{})",
|
|
||||||
reg.register.to_ascii_lowercase(),
|
|
||||||
reg.field.to_ascii_lowercase(),
|
|
||||||
reg.field.to_ascii_lowercase()
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
row.push("_".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
peripheral_rcc_table.push(row);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev.peripherals.push(ir_peri);
|
dev.peripherals.push(ir_peri);
|
||||||
@ -384,12 +366,7 @@ pub fn gen_chip(
|
|||||||
let mut device_x = String::new();
|
let mut device_x = String::new();
|
||||||
|
|
||||||
for irq in &core.interrupts {
|
for irq in &core.interrupts {
|
||||||
write!(
|
write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap();
|
||||||
&mut device_x,
|
|
||||||
"PROVIDE({} = DefaultHandler);\n",
|
|
||||||
irq.name.to_ascii_uppercase()
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
@ -397,6 +374,7 @@ pub fn gen_chip(
|
|||||||
|
|
||||||
let mut data = String::new();
|
let mut data = String::new();
|
||||||
|
|
||||||
|
write!(&mut data, "#[cfg(feature=\"metadata\")] pub mod metadata;").unwrap();
|
||||||
write!(&mut data, "#[cfg(feature=\"pac\")] mod pac;").unwrap();
|
write!(&mut data, "#[cfg(feature=\"pac\")] mod pac;").unwrap();
|
||||||
write!(&mut data, "#[cfg(feature=\"pac\")] pub use pac::*; ").unwrap();
|
write!(&mut data, "#[cfg(feature=\"pac\")] pub use pac::*; ").unwrap();
|
||||||
|
|
||||||
@ -415,7 +393,6 @@ pub fn gen_chip(
|
|||||||
"peripheral_dma_channels",
|
"peripheral_dma_channels",
|
||||||
&peripheral_dma_channels_table,
|
&peripheral_dma_channels_table,
|
||||||
);
|
);
|
||||||
make_table(&mut data, "peripheral_rcc", &peripheral_rcc_table);
|
|
||||||
make_table(&mut data, "dma_channels", &dma_channels_table);
|
make_table(&mut data, "dma_channels", &dma_channels_table);
|
||||||
make_table(&mut data, "dbgmcu", &dbgmcu_table);
|
make_table(&mut data, "dbgmcu", &dbgmcu_table);
|
||||||
make_peripheral_counts(&mut data, &peripheral_counts);
|
make_peripheral_counts(&mut data, &peripheral_counts);
|
||||||
@ -424,6 +401,38 @@ pub fn gen_chip(
|
|||||||
let mut file = File::create(chip_dir.join("mod.rs")).unwrap();
|
let mut file = File::create(chip_dir.join("mod.rs")).unwrap();
|
||||||
file.write_all(data.as_bytes()).unwrap();
|
file.write_all(data.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// generate metadata.rs
|
||||||
|
|
||||||
|
let metadata = Metadata {
|
||||||
|
name: &chip.name,
|
||||||
|
family: &chip.family,
|
||||||
|
line: &chip.line,
|
||||||
|
memory: &chip.memory,
|
||||||
|
peripherals: &core.peripherals,
|
||||||
|
interrupts: &core.interrupts,
|
||||||
|
dma_channels: &core.dma_channels,
|
||||||
|
};
|
||||||
|
let metadata = format!("{:#?}", metadata);
|
||||||
|
let metadata = metadata.replace("[\n", "&[\n");
|
||||||
|
let metadata = metadata.replace("[],\n", "&[],\n");
|
||||||
|
|
||||||
|
let mut data = String::new();
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut data,
|
||||||
|
"
|
||||||
|
include!(\"../../metadata.rs\");
|
||||||
|
use MemoryRegionKind::*;
|
||||||
|
pub const METADATA: Metadata = {};
|
||||||
|
",
|
||||||
|
metadata
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut file = File::create(chip_dir.join("metadata.rs")).unwrap();
|
||||||
|
file.write_all(data.as_bytes()).unwrap();
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
// generate device.x
|
// generate device.x
|
||||||
|
|
||||||
@ -462,7 +471,21 @@ pub fn gen(options: Options) {
|
|||||||
for chip_name in &options.chips {
|
for chip_name in &options.chips {
|
||||||
println!("Generating {}...", chip_name);
|
println!("Generating {}...", chip_name);
|
||||||
|
|
||||||
let chip = load_chip(&options, chip_name);
|
let mut chip = load_chip(&options, chip_name);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
for core in &mut chip.cores {
|
||||||
|
for irq in &mut core.interrupts {
|
||||||
|
irq.name = irq.name.to_ascii_uppercase();
|
||||||
|
}
|
||||||
|
for p in &mut core.peripherals {
|
||||||
|
for irq in &mut p.interrupts {
|
||||||
|
irq.interrupt = irq.interrupt.to_ascii_uppercase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate
|
||||||
for (core_index, core) in chip.cores.iter().enumerate() {
|
for (core_index, core) in chip.cores.iter().enumerate() {
|
||||||
let chip_core_name = match chip.cores.len() {
|
let chip_core_name = match chip.cores.len() {
|
||||||
1 => chip_name.clone(),
|
1 => chip_name.clone(),
|
||||||
@ -557,6 +580,13 @@ pub fn gen(options: Options) {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// Generate src/metadata.rs
|
||||||
|
fs::write(
|
||||||
|
options.out_dir.join("src").join("metadata.rs"),
|
||||||
|
include_bytes!("assets/metadata.rs"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Generate Cargo.toml
|
// Generate Cargo.toml
|
||||||
const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES";
|
const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES";
|
||||||
const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES";
|
const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES";
|
||||||
|
@ -19,10 +19,14 @@ regex = "1.5.4"
|
|||||||
default = ["pac"]
|
default = ["pac"]
|
||||||
|
|
||||||
# Build the actual PAC. Set by default.
|
# Build the actual PAC. Set by default.
|
||||||
# If not set, only the macrotables will be generated. You may want to not set it
|
# If you just want the metadata, unset it with `default-features = false`.
|
||||||
# if you're using stm32-metapac from a build.rs script to use the macros.
|
|
||||||
pac = []
|
pac = []
|
||||||
|
|
||||||
|
# Build the chip metadata.
|
||||||
|
# If set, a const `stm32_metapac::METADATA` will be exported, containing all the
|
||||||
|
# metadata for the currently selected chip.
|
||||||
|
metadata = []
|
||||||
|
|
||||||
rt = ["cortex-m-rt/device"]
|
rt = ["cortex-m-rt/device"]
|
||||||
memory-x = []
|
memory-x = []
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user