Merge pull request #173 from noppej/add_interrupts_to_pac

Add missing interrupt definitions so that `stm32-metapac` can be used in an RTIC application
This commit is contained in:
Dario Nieuwenhuis 2023-03-23 13:06:33 +00:00 committed by GitHub
commit c8a037d235
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 120 additions and 73 deletions

50
Cargo.lock generated
View File

@ -64,6 +64,24 @@ dependencies = [
"svd-parser",
]
[[package]]
name = "chiptool"
version = "0.1.0"
source = "git+https://github.com/embassy-rs/chiptool#150ce4a3442001ef73e0c0f29242f8ffa06aedcc"
dependencies = [
"anyhow",
"clap",
"env_logger",
"inflections",
"log",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_yaml 0.8.26",
"svd-parser",
]
[[package]]
name = "clap"
version = "3.2.23"
@ -398,9 +416,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.52"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
"unicode-ident",
]
@ -454,9 +472,9 @@ checksum = "a0d51660a68078997855ba5602f73ab3a5031bd7ad480a9d4c90fbbf04e1fff0"
[[package]]
name = "regex"
version = "1.7.1"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
dependencies = [
"aho-corasick",
"memchr",
@ -465,9 +483,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.28"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "ryu"
@ -483,22 +501,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.157"
version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca"
checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.157"
version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5"
checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.2",
"syn 2.0.6",
]
[[package]]
@ -542,7 +560,7 @@ name = "stm32-data-gen"
version = "0.1.0"
dependencies = [
"anyhow",
"chiptool",
"chiptool 0.1.0 (git+https://github.com/embassy-rs/chiptool?rev=1d9e0a39a6acc291e50cabc4ed617a87f06d5e89)",
"glob",
"num",
"quick-xml",
@ -569,7 +587,7 @@ dependencies = [
name = "stm32-metapac-gen"
version = "0.1.0"
dependencies = [
"chiptool",
"chiptool 0.1.0 (git+https://github.com/embassy-rs/chiptool)",
"proc-macro2",
"regex",
"serde",
@ -609,9 +627,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.2"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045"
checksum = "ece519cfaf36269ea69d16c363fa1d59ceba8296bbfbfc003c3176d01f2816ee"
dependencies = [
"proc-macro2",
"quote",
@ -650,7 +668,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.2",
"syn 2.0.6",
]
[[package]]

View File

@ -4,8 +4,8 @@
families, including:
- :heavy_check_mark: Base chip information
- RAM, flash
- Packages
- RAM, flash
- Packages
- :heavy_check_mark: Peripheral addresses and interrupts
- :heavy_check_mark: Interrupts
- :heavy_check_mark: GPIO AlternateFunction mappings (for all families except F1)
@ -22,20 +22,20 @@ families, including:
These are the data sources currently used.
- STM32Cube database:
- List of all MCUs
- Peripheral versions
- Flash, RAM size
- GPIO AF mappings
- Interrupt mappings (which signals from which peripherals are OR'd into a NVIC interrupt line)
- DMA channel request mappings
- Packages and package pinouts (TODO)
- List of all MCUs
- Peripheral versions
- Flash, RAM size
- GPIO AF mappings
- Interrupt mappings (which signals from which peripherals are OR'd into a NVIC interrupt line)
- DMA channel request mappings
- Packages and package pinouts (TODO)
- STM32Cubeprog database
- Flash, RAM size
- Flash, RAM size
- STM32 mcufinder:
- Links to documentation PDFs (reference manuals, datasheets...)
- Links to documentation PDFs (reference manuals, datasheets...)
- STM32 HAL headers:
- interrupt number, name
- peripheral addresses
- interrupt number, name
- peripheral addresses
- stm32-rs SVDs: register blocks. YAMLs are intially extracted from SVDs, manually cleaned up and
committed. From this point on, they're manually maintained (we don't maintain "patches" for registers)
@ -43,21 +43,27 @@ These are the data sources currently used.
In order to run the generator, you will need to install the following tools:
* `wget`
* `git`
* `jq`
* `svd` `pip3 install svdtools`
* `xmltodict` - `pip3 install xmltodict`
- `wget`
- `git`
- `jq`
- `svd` `pip3 install svdtools`
- `xmltodict` - `pip3 install xmltodict`
## Generating the YAMLs
## Generate the `stm32-metapac` crate
- Run `./d download-all`
- Run `cargo run --release`
This generates all the YAMLs in `data/` except those in `data/registers/`, which are manually extracted and cleaned up.
> This will download all the required data sources into `sources/`.
> Do not manually edit the files in `data/chips`, contents of these files are autogenerated.
> Assignments of registers to peripherals is done in the file `parse.py` and fixes to registers can be done in the files located in `data/registers`.
- Run `cargo run --release stm32-data-gen`
> This generates all the intermediate JSON's in `build/data/`.
>
> > Assignments of registers to peripherals is done in a [perimap](#peripheral-mapping-perimap) and fixes to registers can be done in the files located in `data/registers`.
- Run `cargo run --release stm32-metapac-gen`
> This generates the `stm32-metapac` crate into `build/stm32-metapac/`.
## Adding support for a new peripheral
@ -68,11 +74,11 @@ are only interested in one. It's easier than it looks, and doing all families at
- Install chiptool with `./d install-chiptool`
- Run `./d extract-all LPUART1`. This'll output a bunch of yamls in `tmp/LPUART1`. NOTE sometimes peripherals have a number sometimes not (`LPUART1` vs `LPUART`). You might want to try both and merge the outputted YAMLs into a single directory.
- Diff them between themselves, to identify differences. The differences can either be:
- 1: Legitimate differences between families, because there are different LPUART versions. For example, added registers/fields.
- 2: SVD inconsistencies, like different register names for the same register
- 3: SVD mistakes (yes, there are some)
- 4: Missing stuff in SVDs, usually enums or doc descriptions.
- Identify how many actually-different (incompatible) versions of the peripheral exist, as we must *not* merge them. Name them v1, v2.. (if possible, by order of chip release date, see [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=1972450814).
- 1: Legitimate differences between families, because there are different LPUART versions. For example, added registers/fields.
- 2: SVD inconsistencies, like different register names for the same register
- 3: SVD mistakes (yes, there are some)
- 4: Missing stuff in SVDs, usually enums or doc descriptions.
- Identify how many actually-different (incompatible) versions of the peripheral exist, as we must _not_ merge them. Name them v1, v2.. (if possible, by order of chip release date, see [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=1972450814).
- For each version, pick the "best" YAML (the one that has less enums/docs missing), place them in `data/registers/lpuart_vX.yaml`
- Cleanup the register yamls (see below).
- Minimize the diff between each pair of versions. For example between `lpuart_v1.yaml` and `lpuart_v2.yaml`. If one is missing enums or descriptions, copy it from another.
@ -88,11 +94,11 @@ SVDs have some widespread annoyances that should be fixed when adding register Y
- Remove "useless prefixes". For example if all regs in the `RNG` peripheral are named `RNG_FOO`, `RNG_BAR`, the `RNG_` peripheral is not conveying any useful information at all, and must go.
- Remove "useless enums". Useless enums is one of the biggest cause of slow compilation times in STM32 PACs.
- 0=disabled, 1=enabled. Common in `xxEN` and `xxIE` fields. If a field says "enable foo" and is one bit, it's obvious "true" means enabled and "false" means disabled.
- "Write 0/1 to clear" enums, common in `xxIF` fields.
- Check out the `DeleteEnums` chiptool transforms.
- 0=disabled, 1=enabled. Common in `xxEN` and `xxIE` fields. If a field says "enable foo" and is one bit, it's obvious "true" means enabled and "false" means disabled.
- "Write 0/1 to clear" enums, common in `xxIF` fields.
- Check out the `DeleteEnums` chiptool transforms.
- Convert repeated registers or fields (like `FOO0 FOO1, FOO2, FOO3`) to arrays `FOO[n]`.
- Check out the `MakeRegisterArray`, `MakeFieldArray` chiptool transforms.
- Check out the `MakeRegisterArray`, `MakeFieldArray` chiptool transforms.
## Adding support for a new family (RCC)
@ -116,27 +122,33 @@ the STM32G081) and compare its YAML against each of the other models' to verify
that they are all mutually consistent.
Finally, we can merge
```
./merge_regs.py tmp/RCC/g0*.yaml
```
This will produce `regs_merged.yaml`, which we can copy into its final resting
place:
```
mv regs_merged.yaml data/registers/rcc_g0.yaml
```
To assign these newly generated registers to peripherals, utilize the mapping done in `parse.py`.
An example mapping can be seen in the following snippet
```
('STM32G0.*:RCC:.*', 'rcc_g0/RCC'),
```
such mapping assignes the `rcc_g0/RCC` register block to the `RCC` peripheral in every device from the `STM32G0` family.
## Peripheral mapping (perimap)
The script has a map to match peripherals to the right version in all chips, the [perimap](https://github.com/embassy-rs/stm32-data/blob/main/src/chips.rs#L109).
The `stm32-data-gen` binary has a map to match peripherals to the right version in all chips, the [perimap](https://github.com/embassy-rs/stm32-data/blob/main/stm32-data-gen/src/chips.rs#L109).
When parsing a chip, for each peripheral a "key" string is constructed using this format: `CHIP:PERIPHERAL_NAME:IP_NAME:IP_VERSION`, where:
- `CHIP`: full chip name, for example `STM32L443CC`
- `PERIPHERAL_NAME`: peripheral name, for example `SPI3`. Corresponds to `IP.InstanceName` in the [MCU XML](https://github.com/embassy-rs/stm32-data-sources/blob/949842b4b8742e6bc70ae29a0ede14b4066db819/cubedb/mcu/STM32L443CCYx.xml#L38).
- `IP_NAME`: IP name, for example `SPI`. Corresponds to `IP.Name` in the [MCU XML](https://github.com/embassy-rs/stm32-data-sources/blob/949842b4b8742e6bc70ae29a0ede14b4066db819/cubedb/mcu/STM32L443CCYx.xml#L38).
@ -174,4 +186,5 @@ Sometimes even the same IP name+version in the same chip family has different re
```
### Peripheral versions
The versions of peripherals can be found in the table [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=0).

3
d
View File

@ -10,6 +10,9 @@ case "$CMD" in
download-all)
rm -rf ./sources/
git clone https://github.com/embassy-rs/stm32-data-sources.git ./sources/
# The following is a temporary workaround until https://github.com/embassy-rs/stm32-data/pull/175 is merged.
cd ./sources/
git checkout 3d60b46
;;
install-chiptool)
cargo install --git https://github.com/embassy-rs/chiptool

View File

@ -691,6 +691,10 @@ fn process_core(
want_nvic_name
};
let chip_nvic = group.ips.values().find(|x| x.name == want_nvic_name).unwrap();
// With the current data sources, this value is always either 2 or 4, and never resolves to None
let nvic_priority_bits = defines.0.get("__NVIC_PRIO_BITS").map(|bits| *bits as u8);
let mut header_irqs = h.interrupts.get(core_name).unwrap().clone();
let chip_irqs = chip_interrupts
.0
@ -963,6 +967,7 @@ fn process_core(
stm32_data_serde::chip::Core {
name: real_core_name.clone(),
peripherals,
nvic_priority_bits,
interrupts,
dma_channels: core_dma_channels,
}

View File

@ -62,6 +62,8 @@ pub mod chip {
pub struct Core {
pub name: String,
pub peripherals: Vec<core::Peripheral>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nvic_priority_bits: Option<u8>,
pub interrupts: Vec<core::Interrupt>,
pub dma_channels: Vec<core::DmaChannels>,
}

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
regex = "1.7.1"
chiptool = { git = "https://github.com/embassy-rs/chiptool", rev = "1d9e0a39a6acc291e50cabc4ed617a87f06d5e89" }
chiptool = { git = "https://github.com/embassy-rs/chiptool" }
serde = { version = "1.0.157", features = [ "derive" ] }
serde_json = "1.0.94"
proc-macro2 = "1.0.52"

View File

@ -1,6 +1,6 @@
[package]
name = "stm32-metapac"
version = "0.1.0"
version = "1.0.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/stm32-data"

View File

@ -5,6 +5,7 @@ pub struct Metadata {
pub line: &'static str,
pub memory: &'static [MemoryRegion],
pub peripherals: &'static [Peripheral],
pub nvic_priority_bits: Option<u8>,
pub interrupts: &'static [Interrupt],
pub dma_channels: &'static [DmaChannel],
}

View File

@ -38,6 +38,8 @@ pub enum MemoryRegionKind {
pub struct Core {
pub name: String,
pub peripherals: Vec<Peripheral>,
#[serde(default)]
pub nvic_priority_bits: Option<u8>,
pub interrupts: Vec<Interrupt>,
pub dma_channels: Vec<DmaChannel>,
}

View File

@ -50,6 +50,7 @@ impl Gen {
let mut ir = ir::IR::new();
let mut dev = ir::Device {
nvic_priority_bits: core.nvic_priority_bits,
interrupts: Vec::new(),
peripherals: Vec::new(),
};
@ -107,22 +108,22 @@ impl Gen {
for (module, version) in &peripheral_versions {
self.all_peripheral_versions.insert((module.clone(), version.clone()));
write!(
writeln!(
&mut extra,
"#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n",
"#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};",
module, version, module
)
.unwrap();
}
write!(&mut extra, "pub const CORE_INDEX: usize = {};\n", core_index).unwrap();
writeln!(&mut extra, "pub const CORE_INDEX: usize = {};", core_index).unwrap();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
let settings = flash.settings.as_ref().unwrap();
write!(&mut extra, "pub const FLASH_BASE: usize = {};\n", flash.address).unwrap();
write!(&mut extra, "pub const FLASH_SIZE: usize = {};\n", flash.size).unwrap();
write!(&mut extra, "pub const ERASE_SIZE: usize = {};\n", settings.erase_size).unwrap();
write!(&mut extra, "pub const WRITE_SIZE: usize = {};\n", settings.write_size).unwrap();
write!(&mut extra, "pub const ERASE_VALUE: u8 = {};\n", settings.erase_value).unwrap();
writeln!(&mut extra, "pub const FLASH_BASE: usize = {};", flash.address).unwrap();
writeln!(&mut extra, "pub const FLASH_SIZE: usize = {};", flash.size).unwrap();
writeln!(&mut extra, "pub const ERASE_SIZE: usize = {};", settings.erase_size).unwrap();
writeln!(&mut extra, "pub const WRITE_SIZE: usize = {};", settings.write_size).unwrap();
writeln!(&mut extra, "pub const ERASE_VALUE: u8 = {};", settings.erase_value).unwrap();
// Cleanups!
transform::sort::Sort {}.run(&mut ir).unwrap();
@ -154,7 +155,7 @@ impl Gen {
let mut device_x = String::new();
for irq in &core.interrupts {
write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap();
writeln!(&mut device_x, "PROVIDE({} = DefaultHandler);", irq.name).unwrap();
}
// ==============================
@ -194,6 +195,7 @@ impl Gen {
line: {:?},
memory: {},
peripherals: PERIPHERALS,
nvic_priority_bits: {:?},
interrupts: INTERRUPTS,
dma_channels: DMA_CHANNELS,
}};",
@ -202,6 +204,7 @@ impl Gen {
&chip.family,
&chip.line,
stringify(&chip.memory),
&core.nvic_priority_bits,
);
let mut file = File::create(chip_dir.join("metadata.rs")).unwrap();
@ -217,12 +220,12 @@ impl Gen {
// ==============================
// generate default memory.x
gen_memory_x(&chip_dir, &chip);
gen_memory_x(&chip_dir, chip);
}
fn load_chip(&mut self, name: &str) -> Chip {
let chip_path = self.opts.data_dir.join("chips").join(&format!("{}.json", name));
let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name));
let chip_path = self.opts.data_dir.join("chips").join(format!("{}.json", name));
let chip = fs::read(chip_path).unwrap_or_else(|_| panic!("Could not load chip {}", name));
serde_json::from_slice(&chip).unwrap()
}
@ -273,7 +276,7 @@ impl Gen {
transform::expand_extends::ExpandExtends {}.run(&mut ir).unwrap();
transform::map_names(&mut ir, |k, s| match k {
transform::NameKind::Block => *s = format!("{}", s),
transform::NameKind::Block => *s = s.to_string(),
transform::NameKind::Fieldset => *s = format!("regs::{}", s),
transform::NameKind::Enum => *s = format!("vals::{}", s),
_ => {}
@ -301,7 +304,7 @@ impl Gen {
// Generate Cargo.toml
let mut contents = include_bytes!("../res/Cargo.toml").to_vec();
for name in &chip_core_names {
write!(&mut contents, "{} = []\n", name.to_ascii_lowercase()).unwrap();
writeln!(&mut contents, "{} = []", name.to_ascii_lowercase()).unwrap();
}
fs::write(self.opts.out_dir.join("Cargo.toml"), contents).unwrap();
@ -342,22 +345,22 @@ fn gen_opts() -> generate::Options {
}
}
fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) {
fn gen_memory_x(out_dir: &Path, chip: &Chip) {
let mut memory_x = String::new();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
let ram = chip.memory.iter().find(|r| r.name == "SRAM").unwrap();
write!(memory_x, "MEMORY\n{{\n").unwrap();
write!(
writeln!(
memory_x,
" FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n",
" FLASH : ORIGIN = 0x{:x}, LENGTH = {}",
flash.address, flash.size,
)
.unwrap();
write!(
writeln!(
memory_x,
" RAM : ORIGIN = 0x{:x}, LENGTH = {}\n",
" RAM : ORIGIN = 0x{:x}, LENGTH = {}",
ram.address, ram.size,
)
.unwrap();