Ver código fonte

Add a program to draw periphery pin usage diagrams for STM32.

Mathias Gottschlag 4 anos atrás
pai
commit
2d9f9e3b00
6 arquivos alterados com 3978 adições e 0 exclusões
  1. 1
    0
      .gitignore
  2. 240
    0
      Cargo.lock
  3. 10
    0
      Cargo.toml
  4. 297
    0
      src/diagram.rs
  5. 69
    0
      src/main.rs
  6. 3361
    0
      src/mcu.rs

+ 1
- 0
.gitignore Ver arquivo

@@ -0,0 +1 @@
1
+/target

+ 240
- 0
Cargo.lock Ver arquivo

@@ -0,0 +1,240 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+[[package]]
4
+name = "ansi_term"
5
+version = "0.11.0"
6
+source = "registry+https://github.com/rust-lang/crates.io-index"
7
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
8
+dependencies = [
9
+ "winapi",
10
+]
11
+
12
+[[package]]
13
+name = "atty"
14
+version = "0.2.14"
15
+source = "registry+https://github.com/rust-lang/crates.io-index"
16
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
17
+dependencies = [
18
+ "hermit-abi",
19
+ "libc",
20
+ "winapi",
21
+]
22
+
23
+[[package]]
24
+name = "bitflags"
25
+version = "1.2.1"
26
+source = "registry+https://github.com/rust-lang/crates.io-index"
27
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
28
+
29
+[[package]]
30
+name = "clap"
31
+version = "2.33.3"
32
+source = "registry+https://github.com/rust-lang/crates.io-index"
33
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
34
+dependencies = [
35
+ "ansi_term",
36
+ "atty",
37
+ "bitflags",
38
+ "strsim",
39
+ "textwrap",
40
+ "unicode-width",
41
+ "vec_map",
42
+]
43
+
44
+[[package]]
45
+name = "heck"
46
+version = "0.3.1"
47
+source = "registry+https://github.com/rust-lang/crates.io-index"
48
+checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
49
+dependencies = [
50
+ "unicode-segmentation",
51
+]
52
+
53
+[[package]]
54
+name = "hermit-abi"
55
+version = "0.1.17"
56
+source = "registry+https://github.com/rust-lang/crates.io-index"
57
+checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
58
+dependencies = [
59
+ "libc",
60
+]
61
+
62
+[[package]]
63
+name = "lazy_static"
64
+version = "1.4.0"
65
+source = "registry+https://github.com/rust-lang/crates.io-index"
66
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
67
+
68
+[[package]]
69
+name = "libc"
70
+version = "0.2.81"
71
+source = "registry+https://github.com/rust-lang/crates.io-index"
72
+checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
73
+
74
+[[package]]
75
+name = "memchr"
76
+version = "2.3.4"
77
+source = "registry+https://github.com/rust-lang/crates.io-index"
78
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
79
+
80
+[[package]]
81
+name = "proc-macro-error"
82
+version = "1.0.4"
83
+source = "registry+https://github.com/rust-lang/crates.io-index"
84
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
85
+dependencies = [
86
+ "proc-macro-error-attr",
87
+ "proc-macro2",
88
+ "quote",
89
+ "syn",
90
+ "version_check",
91
+]
92
+
93
+[[package]]
94
+name = "proc-macro-error-attr"
95
+version = "1.0.4"
96
+source = "registry+https://github.com/rust-lang/crates.io-index"
97
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
98
+dependencies = [
99
+ "proc-macro2",
100
+ "quote",
101
+ "version_check",
102
+]
103
+
104
+[[package]]
105
+name = "proc-macro2"
106
+version = "1.0.24"
107
+source = "registry+https://github.com/rust-lang/crates.io-index"
108
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
109
+dependencies = [
110
+ "unicode-xid",
111
+]
112
+
113
+[[package]]
114
+name = "quick-xml"
115
+version = "0.20.0"
116
+source = "registry+https://github.com/rust-lang/crates.io-index"
117
+checksum = "26aab6b48e2590e4a64d1ed808749ba06257882b461d01ca71baeb747074a6dd"
118
+dependencies = [
119
+ "memchr",
120
+]
121
+
122
+[[package]]
123
+name = "quote"
124
+version = "1.0.7"
125
+source = "registry+https://github.com/rust-lang/crates.io-index"
126
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
127
+dependencies = [
128
+ "proc-macro2",
129
+]
130
+
131
+[[package]]
132
+name = "stm32-pin-diagram"
133
+version = "0.1.0"
134
+dependencies = [
135
+ "lazy_static",
136
+ "quick-xml",
137
+ "structopt",
138
+]
139
+
140
+[[package]]
141
+name = "strsim"
142
+version = "0.8.0"
143
+source = "registry+https://github.com/rust-lang/crates.io-index"
144
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
145
+
146
+[[package]]
147
+name = "structopt"
148
+version = "0.3.21"
149
+source = "registry+https://github.com/rust-lang/crates.io-index"
150
+checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c"
151
+dependencies = [
152
+ "clap",
153
+ "lazy_static",
154
+ "structopt-derive",
155
+]
156
+
157
+[[package]]
158
+name = "structopt-derive"
159
+version = "0.4.14"
160
+source = "registry+https://github.com/rust-lang/crates.io-index"
161
+checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90"
162
+dependencies = [
163
+ "heck",
164
+ "proc-macro-error",
165
+ "proc-macro2",
166
+ "quote",
167
+ "syn",
168
+]
169
+
170
+[[package]]
171
+name = "syn"
172
+version = "1.0.54"
173
+source = "registry+https://github.com/rust-lang/crates.io-index"
174
+checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
175
+dependencies = [
176
+ "proc-macro2",
177
+ "quote",
178
+ "unicode-xid",
179
+]
180
+
181
+[[package]]
182
+name = "textwrap"
183
+version = "0.11.0"
184
+source = "registry+https://github.com/rust-lang/crates.io-index"
185
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
186
+dependencies = [
187
+ "unicode-width",
188
+]
189
+
190
+[[package]]
191
+name = "unicode-segmentation"
192
+version = "1.7.1"
193
+source = "registry+https://github.com/rust-lang/crates.io-index"
194
+checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
195
+
196
+[[package]]
197
+name = "unicode-width"
198
+version = "0.1.8"
199
+source = "registry+https://github.com/rust-lang/crates.io-index"
200
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
201
+
202
+[[package]]
203
+name = "unicode-xid"
204
+version = "0.2.1"
205
+source = "registry+https://github.com/rust-lang/crates.io-index"
206
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
207
+
208
+[[package]]
209
+name = "vec_map"
210
+version = "0.8.2"
211
+source = "registry+https://github.com/rust-lang/crates.io-index"
212
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
213
+
214
+[[package]]
215
+name = "version_check"
216
+version = "0.9.2"
217
+source = "registry+https://github.com/rust-lang/crates.io-index"
218
+checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
219
+
220
+[[package]]
221
+name = "winapi"
222
+version = "0.3.9"
223
+source = "registry+https://github.com/rust-lang/crates.io-index"
224
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
225
+dependencies = [
226
+ "winapi-i686-pc-windows-gnu",
227
+ "winapi-x86_64-pc-windows-gnu",
228
+]
229
+
230
+[[package]]
231
+name = "winapi-i686-pc-windows-gnu"
232
+version = "0.4.0"
233
+source = "registry+https://github.com/rust-lang/crates.io-index"
234
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
235
+
236
+[[package]]
237
+name = "winapi-x86_64-pc-windows-gnu"
238
+version = "0.4.0"
239
+source = "registry+https://github.com/rust-lang/crates.io-index"
240
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 10
- 0
Cargo.toml Ver arquivo

@@ -0,0 +1,10 @@
1
+[package]
2
+name = "stm32-pin-diagram"
3
+version = "0.1.0"
4
+authors = ["Mathias Gottschlag <mathias.gottschlag@kit.edu>"]
5
+edition = "2018"
6
+
7
+[dependencies]
8
+lazy_static = "1.4"
9
+quick-xml = "0.20"
10
+structopt = "0.3"

+ 297
- 0
src/diagram.rs Ver arquivo

@@ -0,0 +1,297 @@
1
+use std::collections::BTreeSet;
2
+use std::io::{BufWriter, Write};
3
+
4
+use super::mcu::{Mcu, Pin};
5
+
6
+pub fn draw(mcu: &Mcu, shown_peripherals: &BTreeSet<String>) -> Vec<u8> {
7
+    let mut output = Vec::new();
8
+    let mut writer = BufWriter::new(&mut output);
9
+    let package = match Package::from_str(&mcu.package) {
10
+        Some(package) => package,
11
+        None => panic!("Package {} not yet supported.", mcu.package),
12
+    };
13
+
14
+    let mut peripherals = BTreeSet::new();
15
+    for pin in mcu.pins.iter() {
16
+        for function in pin.functions.iter() {
17
+            let peripheral = Pin::split_function(function).0;
18
+            if shown_peripherals.len() != 0 && !shown_peripherals.contains(peripheral) {
19
+                continue;
20
+            }
21
+            if !peripherals.contains(peripheral) {
22
+                peripherals.insert(peripheral.to_owned());
23
+            }
24
+        }
25
+    }
26
+    println!("{} peripherals:", peripherals.len());
27
+    for peripheral in peripherals.iter() {
28
+        println!("{}", peripheral);
29
+    }
30
+
31
+    begin_document(&mut writer, &peripherals);
32
+    draw_package_body(&mut writer, package);
33
+    draw_legend(&mut writer, package, &peripherals);
34
+    for pin in mcu.pins.iter() {
35
+        draw_pin_label(&mut writer, package, pin, &peripherals);
36
+    }
37
+    end_document(&mut writer);
38
+
39
+    drop(writer);
40
+    output
41
+}
42
+
43
+fn begin_document(writer: &mut BufWriter<&mut Vec<u8>>, peripherals: &BTreeSet<String>) {
44
+    write!(
45
+        writer,
46
+        "{}",
47
+        r#"\documentclass[crop,tikz]{standalone}
48
+\usepackage{pgf}
49
+\fontsize{10}{12}\selectfont
50
+\usetikzlibrary{calc, positioning}
51
+\pgfmathsetseed{12345}
52
+"#
53
+    )
54
+    .unwrap();
55
+    // Randomly generate colors for all peripherals.
56
+    for peripheral in peripherals {
57
+        write!(
58
+            writer,
59
+            "\\pgfmathsetmacro{{\\R}}{{random(0,10000)/10000}}
60
+\\pgfmathsetmacro{{\\G}}{{random(0,10000)/10000}}
61
+\\pgfmathsetmacro{{\\B}}{{random(0,10000)/10000}}
62
+\\definecolor{{color{name}}}{{rgb}}{{\\R,\\G,\\B}}
63
+",
64
+            name = peripheral
65
+        )
66
+        .unwrap()
67
+    }
68
+    write!(
69
+        writer,
70
+        "{}",
71
+        r#"\begin{document}
72
+\begin{tikzpicture}[x=12pt,y=12pt]
73
+"#
74
+    )
75
+    .unwrap();
76
+}
77
+
78
+fn end_document(writer: &mut BufWriter<&mut Vec<u8>>) {
79
+    write!(
80
+        writer,
81
+        "{}",
82
+        r#"\end{tikzpicture}
83
+\end{document}
84
+"#
85
+    )
86
+    .unwrap();
87
+}
88
+
89
+fn draw_package_body(writer: &mut BufWriter<&mut Vec<u8>>, package: Package) {
90
+    if let Package::Qfp(pins) = package {
91
+        let pins_per_side = package.pins_per_side();
92
+        let edge = pins_per_side + 3;
93
+        write!(writer, "\\draw[thick] (0, 0) --\n").unwrap();
94
+        for i in 0..pins_per_side {
95
+            write!(
96
+                writer,
97
+                "  coordinate[pos={pos}] (P{pin})\n",
98
+                pos = (i + 2) as f64 / edge as f64,
99
+                pin = i + 1,
100
+            )
101
+            .unwrap();
102
+        }
103
+        write!(writer, " ({size}, 0);\n", size = edge).unwrap();
104
+        write!(writer, "\\draw[thick] ({size}, 0) --\n", size = edge).unwrap();
105
+        for i in 0..pins_per_side {
106
+            write!(
107
+                writer,
108
+                "  coordinate[pos={pos}] (P{pin})\n",
109
+                pos = (i + 2) as f64 / edge as f64,
110
+                pin = i + pins_per_side + 1,
111
+            )
112
+            .unwrap();
113
+        }
114
+        write!(writer, " ({size}, {size});\n", size = edge).unwrap();
115
+        write!(writer, "\\draw[thick] ({size}, {size}) --\n", size = edge).unwrap();
116
+        for i in 0..pins_per_side {
117
+            write!(
118
+                writer,
119
+                "  coordinate[pos={pos}] (P{pin})\n",
120
+                pos = (i + 2) as f64 / edge as f64,
121
+                pin = i + pins_per_side * 2 + 1,
122
+            )
123
+            .unwrap();
124
+        }
125
+        write!(writer, " (0, {size});\n", size = edge).unwrap();
126
+        write!(writer, "\\draw[thick] (0, {size}) --\n", size = edge).unwrap();
127
+        for i in 0..pins_per_side {
128
+            write!(
129
+                writer,
130
+                "  coordinate[pos={pos}] (P{pin})\n",
131
+                pos = (i + 2) as f64 / edge as f64,
132
+                pin = i + pins_per_side * 3 + 1,
133
+            )
134
+            .unwrap();
135
+        }
136
+        write!(writer, " (0, 0);\n").unwrap();
137
+
138
+        // Draw pin numbers.
139
+        for i in 0..pins {
140
+            let side = Side(i / (pins / 4));
141
+            write!(
142
+                writer,
143
+                "\\node[{side} = 0.1 of P{pin}, rotate={rotate}] {{{pin}}};\n",
144
+                side = side.inside_position(),
145
+                rotate = side.rotate(),
146
+                pin = i + 1,
147
+            )
148
+            .unwrap();
149
+        }
150
+    } else {
151
+        panic!("Not yet implemented.");
152
+    }
153
+}
154
+
155
+fn draw_legend(
156
+    writer: &mut BufWriter<&mut Vec<u8>>,
157
+    package: Package,
158
+    peripherals: &BTreeSet<String>,
159
+) {
160
+    let rows = (package.pins_per_side() as usize - 4) * 2 / 3;
161
+    let pos_x = 3;
162
+    let pos_y = package.pins_per_side() as f64 - 2.0;
163
+    for (i, peripheral) in peripherals.iter().enumerate() {
164
+        let column = i / rows;
165
+        let row = i % rows;
166
+        write!(
167
+            writer,
168
+            "\\node[draw, fill=color{rawname}!30, anchor=west] at ({x}, {y}) {{{name}}};\n",
169
+            x = pos_x + column * 5,
170
+            y = pos_y - row as f64 * 1.5,
171
+            rawname = peripheral,
172
+            name = latex_escape(peripheral),
173
+        )
174
+        .unwrap();
175
+    }
176
+}
177
+
178
+fn draw_pin_label(
179
+    writer: &mut BufWriter<&mut Vec<u8>>,
180
+    package: Package,
181
+    pin: &Pin,
182
+    peripherals: &BTreeSet<String>,
183
+) {
184
+    if let Package::Qfp(pins) = package {
185
+        let position = pin.position.parse::<u32>().expect("invalid pin position");
186
+        let side = Side((position - 1) / (pins / 4));
187
+        write!(
188
+            writer,
189
+            "\\node[{side} = 0.1 of P{pin}, rotate={rotate}] (p{pin}label0) {{{name}}};\n",
190
+            side = side.outside_position(),
191
+            rotate = side.rotate(),
192
+            //anchor = side.outside_anchor(),
193
+            pin = position,
194
+            name = latex_escape(&pin.name),
195
+        )
196
+        .unwrap();
197
+
198
+        // Draw the functions as well.
199
+        // TODO: Ideally, the functions would be grouped together.
200
+        let mut label_count = 0;
201
+        for function in pin.functions.iter() {
202
+            let (peripheral, signal) = Pin::split_function(function);
203
+            if !peripherals.contains(peripheral) {
204
+                continue;
205
+            }
206
+            write!(
207
+                writer,
208
+                "\\node[draw, fill=color{peripheral}!30, {side} = 0.1 of p{pin}label{label_count}, rotate={rotate}] (p{pin}label{label_count_p_1}) {{{name}}};\n",
209
+                side = side.outside_position(),
210
+                label_count = label_count,
211
+                label_count_p_1 = label_count + 1,
212
+                rotate = side.rotate(),
213
+                //anchor = side.outside_anchor(),
214
+                pin = position,
215
+                peripheral = peripheral,
216
+                name = latex_escape(signal),
217
+            )
218
+            .unwrap();
219
+            label_count += 1;
220
+        }
221
+    } else {
222
+        panic!("Not yet implemented.");
223
+    }
224
+}
225
+
226
+#[derive(Copy, Clone)]
227
+struct Side(u32);
228
+
229
+impl Side {
230
+    fn inside_anchor(self) -> &'static str {
231
+        match self.0 {
232
+            0 => "west",
233
+            1 => "east",
234
+            2 => "east",
235
+            3 => "west",
236
+            _ => panic!("invalid side"),
237
+        }
238
+    }
239
+    fn outside_anchor(self) -> &'static str {
240
+        Side((self.0 + 2) % 4).inside_anchor()
241
+    }
242
+    fn rotate(self) -> u32 {
243
+        match self.0 {
244
+            0 => 90,
245
+            1 => 0,
246
+            2 => 90,
247
+            3 => 0,
248
+            _ => panic!("invalid side"),
249
+        }
250
+    }
251
+    fn inside_position(self) -> &'static str {
252
+        match self.0 {
253
+            0 => "right",
254
+            1 => "left",
255
+            2 => "left",
256
+            3 => "right",
257
+            _ => panic!("invalid side"),
258
+        }
259
+    }
260
+    fn outside_position(self) -> &'static str {
261
+        Side((self.0 + 2) % 4).inside_position()
262
+    }
263
+}
264
+
265
+fn latex_escape(s: &str) -> String {
266
+    s.replace("_", "\\_")
267
+}
268
+
269
+#[derive(Clone, Copy)]
270
+enum Package {
271
+    Qfp(u32),
272
+    Bga(u32),
273
+}
274
+
275
+impl Package {
276
+    fn from_str(s: &str) -> Option<Package> {
277
+        if s.starts_with("LQFP") {
278
+            let pins = s[4..].parse().ok()?;
279
+            Some(Package::Qfp(pins))
280
+        } else {
281
+            None
282
+        }
283
+    }
284
+
285
+    fn pins_per_side(&self) -> u32 {
286
+        match self {
287
+            Package::Qfp(pins) => pins / 4,
288
+            _ => panic!("Not yet implemented."),
289
+        }
290
+    }
291
+    fn pins(&self) -> u32 {
292
+        match self {
293
+            Package::Qfp(pins) => *pins,
294
+            _ => panic!("Not yet implemented."),
295
+        }
296
+    }
297
+}

+ 69
- 0
src/main.rs Ver arquivo

@@ -0,0 +1,69 @@
1
+use std::collections::BTreeSet;
2
+use std::fs;
3
+use std::io::{self, Write};
4
+use std::iter::FromIterator;
5
+use std::path::PathBuf;
6
+
7
+use structopt::StructOpt;
8
+
9
+use mcu::Mcu;
10
+
11
+mod diagram;
12
+mod mcu;
13
+
14
+#[derive(Debug, StructOpt)]
15
+#[structopt(
16
+    name = "stm32-pin-diagram",
17
+    about = "A program which generates LaTeX pinout diagrams for STM32 microcontrollers"
18
+)]
19
+struct Options {
20
+    /// Model of the MCU (for example "STM32F429ZI").
21
+    model: String,
22
+
23
+    /// Output path - if not specified, the TeX code is written to stdout.
24
+    #[structopt(short, long, parse(from_os_str))]
25
+    output: Option<PathBuf>,
26
+
27
+    /// List of peripherals to show in the diagram. If none is specified, all peripherals are
28
+    /// shown.
29
+    #[structopt(short, long)]
30
+    peripheral: Vec<String>,
31
+}
32
+
33
+fn main() {
34
+    let options = Options::from_args();
35
+
36
+    println!("Loading MCU info...");
37
+    let mcu = match Mcu::load(&options.model) {
38
+        Some(mcu) => mcu,
39
+        None => {
40
+            println!("Could not find the specified MCU. The following MCUs are supported:");
41
+            for mcu in Mcu::list().into_iter() {
42
+                println!("  {}", mcu);
43
+            }
44
+            return;
45
+        }
46
+    };
47
+
48
+    println!("Package: {}", mcu.package);
49
+    /*println!("Pins:");
50
+    for pin in mcu.pins.iter() {
51
+        println!(
52
+            "  {}: {} ({}) ({:?}) ({:?})",
53
+            pin.position, pin.name, pin.type_, pin.gpio_modes, pin.functions
54
+        );
55
+    }*/
56
+
57
+    // TODO: We could just give draw() an io::Write.
58
+
59
+    let diagram = diagram::draw(&mcu, &BTreeSet::from_iter(options.peripheral.into_iter()));
60
+
61
+    match options.output {
62
+        Some(output_file) => {
63
+            fs::write(&output_file, &diagram).expect("could not write output file");
64
+        }
65
+        None => {
66
+            io::stdout().write_all(&diagram).unwrap();
67
+        }
68
+    }
69
+}

+ 3361
- 0
src/mcu.rs
Diferenças do arquivo suprimidas por serem muito extensas
Ver arquivo


Carregando…
Cancelar
Salvar