Skip to content

Commit 0ed9111

Browse files
committed
Add support for extracting EEPROM size
1 parent 73a46ed commit 0ed9111

File tree

3 files changed

+128
-47
lines changed

3 files changed

+128
-47
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
[![Build Status][github-actions-badge]][github-actions]
44

5-
A program to extract AF modes on MCU pins from the database files provided with STM32CubeMX.
5+
A program to extract hardware configuration information from the MCU database
6+
files shipped with STM32CubeMX.
7+
68

79
## Usage
810

@@ -32,10 +34,6 @@ are available:
3234
* STM32MP1
3335
* STM32WB
3436

35-
The program will output one AF mode definition per GPIO variant, with a
36-
corresponding feature gate.
37-
38-
More on the generated feature groups can be found below.
3937

4038
## The STM32CubeMX Database
4139

@@ -160,7 +158,8 @@ As you can see, this element describes the pin `PB6`. Depending on the chosen
160158
Alternative Function (AF), it can become an `I2C1_SCL` pin (AF1), a `USART1_TX`
161159
pin (AF0), or some other variants.
162160

163-
## Feature Groups
161+
162+
## GPIO Feature Groups
164163

165164
When generating pin function mappings, we want to avoid generating a mapping
166165
for every possible MCU, since that would result in dozens or even hundreds of
@@ -212,6 +211,7 @@ In order to simplify the GPIO IP version selection for the user, alias features
212211
are generated. These are purely a convenience for the user and are never used
213212
directly as feature gates in the source code.
214213

214+
215215
<!-- Badges -->
216216
[github-actions]: https://github.com/dbrgn/cube-parse/actions?query=branch%3Amaster
217217
[github-actions-badge]: https://github.com/dbrgn/cube-parse/workflows/CI/badge.svg

src/main.rs

Lines changed: 115 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ mod utils;
1212

1313
#[derive(Debug, PartialEq)]
1414
enum GenerateTarget {
15-
PinMappings,
1615
Features,
16+
PinMappings,
17+
EepromSizes,
1718
}
1819

1920
lazy_static! {
@@ -31,6 +32,11 @@ fn gpio_version_to_feature(version: &str) -> Result<String, String> {
3132
}
3233
}
3334

35+
/// Get the EEPROM size (in KiB) feature for a certain size.
36+
fn eeprom_size_to_feature(size: u32) -> String {
37+
format!("eeprom-{}", size)
38+
}
39+
3440
fn main() -> Result<(), String> {
3541
let args = App::new("cube-parse")
3642
.version(env!("CARGO_PKG_VERSION"))
@@ -47,7 +53,7 @@ fn main() -> Result<(), String> {
4753
Arg::with_name("generate")
4854
.help("What to generate")
4955
.takes_value(true)
50-
.possible_values(&["pin_mappings", "features"])
56+
.possible_values(&["features", "pin_mappings", "eeprom_sizes"])
5157
.required(true),
5258
)
5359
.arg(
@@ -62,8 +68,9 @@ fn main() -> Result<(), String> {
6268
let db_dir = Path::new(args.value_of("db_dir").unwrap());
6369
let mcu_family = args.value_of("mcu_family").unwrap();
6470
let generate = match args.value_of("generate").unwrap() {
65-
"pin_mappings" => GenerateTarget::PinMappings,
6671
"features" => GenerateTarget::Features,
72+
"pin_mappings" => GenerateTarget::PinMappings,
73+
"eeprom_sizes" => GenerateTarget::EepromSizes,
6774
_ => unreachable!(),
6875
};
6976

@@ -79,39 +86,68 @@ fn main() -> Result<(), String> {
7986

8087
// MCU map
8188
//
89+
// This maps a MCU ref name to the corresponding `mcu::Mcu` instance.
90+
let mut mcu_map: HashMap<String, mcu::Mcu> = HashMap::new();
91+
92+
// GPIO map
93+
//
8294
// The keys of this map are GPIO peripheral version strings (e.g.
8395
// "STM32L051_gpio_v1_0"), while the value is a Vec of MCU ref names.
8496
let mut mcu_gpio_map: HashMap<String, Vec<String>> = HashMap::new();
8597

8698
// Package map
8799
//
88-
// The keys of this map are MCU ref names, the values are package names
89-
// (e.g. ).
100+
// The keys of this map are MCU ref names, the values are package names.
90101
let mut mcu_package_map: HashMap<String, String> = HashMap::new();
91102

103+
// EEPROM size map
104+
//
105+
// The keys of this map are EEPROM sizes in KiB, the values are Vecs of MCU ref names.
106+
let mut mcu_eeprom_size_map: HashMap<u32, Vec<String>> = HashMap::new();
107+
108+
// Iterate through subfamilies, then through MCUs. Fill the maps above with
109+
// aggregated data.
92110
for sf in family {
93111
for mcu in sf {
112+
// Load MCU data from the XML files
94113
let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name)
95114
.map_err(|e| format!("Could not load MCU data: {}", e))?;
96115

116+
// Fill GPIO map
97117
let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string();
98118
mcu_gpio_map
99119
.entry(gpio_version)
100120
.or_insert(vec![])
101121
.push(mcu.ref_name.clone());
102122

123+
// Fill package map
103124
if mcu_family == "STM32L0" {
104125
// The stm32l0xx-hal has package based features
105126
mcu_package_map.insert(mcu.ref_name.clone(), mcu.package_name.clone());
106127
}
128+
129+
// Fill EEPROM size map
130+
if let Some(size) = mcu_dat.get_eeprom_size_kib() {
131+
mcu_eeprom_size_map
132+
.entry(size)
133+
.or_insert(vec![])
134+
.push(mcu.ref_name.clone());
135+
}
136+
137+
mcu_map.insert(mcu.ref_name.clone(), mcu_dat);
107138
}
108139
}
109140

110141
match generate {
111-
GenerateTarget::Features => {
112-
generate_features(&mcu_gpio_map, &mcu_package_map, &mcu_family)?
113-
}
142+
GenerateTarget::Features => generate_features(
143+
&mcu_map,
144+
&mcu_gpio_map,
145+
&mcu_package_map,
146+
&mcu_eeprom_size_map,
147+
&mcu_family,
148+
)?,
114149
GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?,
150+
GenerateTarget::EepromSizes => generate_eeprom_sizes(&mcu_eeprom_size_map)?,
115151
};
116152

117153
Ok(())
@@ -132,31 +168,67 @@ lazy_static! {
132168
};
133169
}
134170

135-
/// Print the IO features, followed by MCU features that act purely as aliases
136-
/// for the IO features.
171+
/// Generate all Cargo features
137172
///
138-
/// Both lists are sorted alphanumerically.
173+
/// Feature categories:
174+
///
175+
/// - IO features (`io-*`)
176+
/// - EEPROM features (`eeprom-*`)
177+
///
178+
/// Finally, the MCU features are printed, they act purely as aliases for the
179+
/// other features.
139180
fn generate_features(
181+
mcu_map: &HashMap<String, mcu::Mcu>,
140182
mcu_gpio_map: &HashMap<String, Vec<String>>,
141183
mcu_package_map: &HashMap<String, String>,
184+
mcu_eeprom_size_map: &HashMap<u32, Vec<String>>,
142185
mcu_family: &str,
143186
) -> Result<(), String> {
144-
let mut main_features = mcu_gpio_map
187+
// IO features
188+
let mut io_features = mcu_gpio_map
145189
.keys()
146190
.map(|gpio| gpio_version_to_feature(gpio))
147191
.collect::<Result<Vec<String>, String>>()?;
148-
main_features.sort();
192+
io_features.sort();
193+
println!("# Features based on the GPIO peripheral version");
194+
println!("# This determines the pin function mapping of the MCU");
195+
for feature in io_features {
196+
println!("{} = []", feature);
197+
}
198+
println!();
149199

200+
// EEPROM sizes
201+
let mut eeprom_sizes = mcu_eeprom_size_map.keys().collect::<Vec<_>>();
202+
eeprom_sizes.sort();
203+
println!("# Features based on EEPROM size (in KiB)");
204+
for size in eeprom_sizes {
205+
println!("{} = []", eeprom_size_to_feature(*size));
206+
}
207+
println!();
208+
209+
// Physical packages
210+
if !mcu_package_map.is_empty() {
211+
println!("# Physical packages");
212+
let mut packages = mcu_package_map
213+
.values()
214+
.map(|v| v.to_lowercase())
215+
.collect::<Vec<_>>();
216+
packages.sort_by(|a, b| compare_str(a, b));
217+
packages.dedup();
218+
for pkg in packages {
219+
println!("{} = []", pkg);
220+
}
221+
println!();
222+
}
223+
224+
// MCU features
150225
let mut mcu_aliases = vec![];
151226
for (gpio, mcu_list) in mcu_gpio_map {
152227
let gpio_version_feature = gpio_version_to_feature(gpio).unwrap();
153228
for mcu in mcu_list {
154229
let mut dependencies = vec![];
155230

156-
// GPIO version feature
157-
dependencies.push(gpio_version_feature.clone());
158-
159-
// Additional dependencies
231+
// Static feature dependencies
160232
if let Some(family) = FEATURE_DEPENDENCIES.get(mcu_family) {
161233
for (pattern, feature) in family {
162234
if Regex::new(pattern).unwrap().is_match(&mcu) {
@@ -171,10 +243,17 @@ fn generate_features(
171243
dependencies.push(package.to_lowercase());
172244
}
173245

174-
let mcu_feature = format!("mcu-{}", mcu);
246+
// GPIO version feature
247+
dependencies.push(gpio_version_feature.clone());
248+
249+
// EEPROM size
250+
if let Some(size) = mcu_map.get(mcu).unwrap().get_eeprom_size_kib() {
251+
dependencies.push(eeprom_size_to_feature(size));
252+
}
253+
175254
mcu_aliases.push(format!(
176-
"{} = [{}]",
177-
mcu_feature,
255+
"mcu-{} = [{}]",
256+
mcu,
178257
&dependencies.iter().map(|val| format!("\"{}\"", val)).fold(
179258
String::new(),
180259
|mut acc, x| {
@@ -189,27 +268,12 @@ fn generate_features(
189268
}
190269
}
191270
mcu_aliases.sort();
192-
193-
println!("# Features based on the GPIO peripheral version");
194-
println!("# This determines the pin function mapping of the MCU");
195-
for feature in main_features {
196-
println!("{} = []", feature);
197-
}
198-
println!();
199-
if !mcu_package_map.is_empty() {
200-
println!("# Physical packages");
201-
let mut packages = mcu_package_map
202-
.values()
203-
.map(|v| v.to_lowercase())
204-
.collect::<Vec<_>>();
205-
packages.sort_by(|a, b| compare_str(a, b));
206-
packages.dedup();
207-
for pkg in packages {
208-
println!("{} = []", pkg);
209-
}
210-
println!();
211-
}
212-
println!("# MCUs");
271+
println!("# MCU aliases");
272+
println!("#");
273+
println!("# Note: These are just aliases, they should not be used to directly feature gate");
274+
println!(
275+
"# functionality in the HAL! However, user code should usually depend on a MCU alias."
276+
);
213277
for alias in mcu_aliases {
214278
println!("{}", alias);
215279
}
@@ -235,6 +299,16 @@ fn generate_pin_mappings(
235299
Ok(())
236300
}
237301

302+
/// Generate code containing the EEPROM size.
303+
fn generate_eeprom_sizes(mcu_eeprom_size_map: &HashMap<u32, Vec<String>>) -> Result<(), String> {
304+
println!("// EEPROM sizes in KiB, generated with cube-parse");
305+
for size in mcu_eeprom_size_map.keys() {
306+
println!("#[cfg({})]", eeprom_size_to_feature(*size));
307+
println!("const EEPROM_SIZE_KIB: u32 = {};", size);
308+
}
309+
Ok(())
310+
}
311+
238312
fn render_pin_modes(ip: &internal_peripheral::IpGPIO) {
239313
let mut pin_map: HashMap<String, Vec<String>> = HashMap::new();
240314

src/mcu.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use crate::utils::load_file;
99
pub struct Mcu {
1010
#[serde(rename = "IP", default)]
1111
ip: Vec<IP>,
12+
#[serde(rename = "E2prom")]
13+
eeprom_size_kib: String,
1214
}
1315

1416
impl Mcu {
@@ -19,6 +21,11 @@ impl Mcu {
1921
pub fn get_ip(&self, name: &str) -> Option<&IP> {
2022
self.ip.iter().find(|v| v.name == name)
2123
}
24+
25+
/// Return the EEPROM size in KiB
26+
pub fn get_eeprom_size_kib(&self) -> Option<u32> {
27+
self.eeprom_size_kib.parse().ok()
28+
}
2229
}
2330

2431
#[derive(Debug, Deserialize)]

0 commit comments

Comments
 (0)