aboutsummaryrefslogtreecommitdiff
path: root/embassy-nxp/build.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-nxp/build.rs')
-rw-r--r--embassy-nxp/build.rs353
1 files changed, 326 insertions, 27 deletions
diff --git a/embassy-nxp/build.rs b/embassy-nxp/build.rs
index f3c062c87..f53c29161 100644
--- a/embassy-nxp/build.rs
+++ b/embassy-nxp/build.rs
@@ -4,10 +4,12 @@ use std::process::Command;
4use std::{env, fs}; 4use std::{env, fs};
5 5
6use cfg_aliases::cfg_aliases; 6use cfg_aliases::cfg_aliases;
7#[cfg(feature = "_rt1xxx")]
8use nxp_pac::metadata; 7use nxp_pac::metadata;
8use nxp_pac::metadata::{METADATA, Peripheral};
9#[allow(unused)] 9#[allow(unused)]
10use proc_macro2::TokenStream; 10use proc_macro2::TokenStream;
11use proc_macro2::{Ident, Literal, Span};
12use quote::format_ident;
11#[allow(unused)] 13#[allow(unused)]
12use quote::quote; 14use quote::quote;
13 15
@@ -31,56 +33,188 @@ fn main() {
31 .unwrap() 33 .unwrap()
32 .to_ascii_lowercase(); 34 .to_ascii_lowercase();
33 35
36 let singletons = singletons(&mut cfgs);
37
34 cfg_aliases! { 38 cfg_aliases! {
35 rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") }, 39 rt1xxx: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
36 gpio1: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
37 gpio2: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
38 gpio3: { feature = "mimxrt1062" },
39 gpio4: { feature = "mimxrt1062" },
40 gpio5: { any(feature = "mimxrt1011", feature = "mimxrt1062") },
41 } 40 }
42 41
43 eprintln!("chip: {chip_name}"); 42 eprintln!("chip: {chip_name}");
44 43
45 generate_code(); 44 generate_code(&mut cfgs, &singletons);
46} 45}
47 46
48#[cfg(feature = "_rt1xxx")] 47/// A peripheral singleton returned by `embassy_nxp::init`.
49fn generate_iomuxc() -> TokenStream { 48struct Singleton {
50 use proc_macro2::{Ident, Span}; 49 name: String,
51 50
52 let pads = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| { 51 /// A cfg guard which indicates whether the `Peripherals` struct will give the user this singleton.
53 let name = Ident::new(&registers.name, Span::call_site()); 52 cfg: Option<TokenStream>,
54 let address = registers.pad_ctl; 53}
55 54
56 quote! { 55fn singletons(cfgs: &mut common::CfgSet) -> Vec<Singleton> {
57 pub const #name: u32 = #address; 56 let mut singletons = Vec::new();
57
58 for peripheral in METADATA.peripherals {
59 // GPIO and DMA are generated in a 2nd pass.
60 let skip_singleton = if peripheral.name.starts_with("GPIO") || peripheral.name.starts_with("DMA") {
61 true
62 } else {
63 false
64 };
65
66 if !skip_singleton {
67 singletons.push(Singleton {
68 name: peripheral.name.into(),
69 cfg: None,
70 });
58 } 71 }
59 }); 72 }
60 73
61 let muxes = metadata::iomuxc::IOMUXC_REGISTERS.iter().map(|registers| { 74 cfgs.declare_all(&[
62 let name = Ident::new(&registers.name, Span::call_site()); 75 "gpio1",
63 let address = registers.mux_ctl; 76 "gpio1_hi",
77 "gpio2",
78 "gpio2_hi",
79 "gpio3",
80 "gpio3_hi",
81 "gpio4",
82 "gpio4_hi",
83 "gpio5",
84 "gpio5_hi",
85 "gpio10",
86 "gpio10_hi",
87 ]);
64 88
65 quote! { 89 for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("GPIO")) {
66 pub const #name: u32 = #address; 90 let number = peripheral.name.strip_prefix("GPIO").unwrap();
91 assert!(number.parse::<u8>().is_ok());
92 cfgs.enable(format!("gpio{}", number));
93
94 for signal in peripheral.signals.iter() {
95 let pin_number = signal.name.parse::<u8>().unwrap();
96
97 if pin_number > 15 {
98 cfgs.enable(format!("gpio{}_hi", number));
99 }
100
101 // GPIO signals only defined a single signal, on a single pin.
102 assert_eq!(signal.pins.len(), 1);
103
104 singletons.push(Singleton {
105 name: signal.pins[0].pin.into(),
106 cfg: None,
107 });
108 }
109 }
110
111 for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("DMA")) {
112 let instance = peripheral.name.strip_prefix("DMA").unwrap();
113 assert!(instance.parse::<u8>().is_ok());
114
115 for signal in peripheral.signals.iter() {
116 let channel_number = signal.name.parse::<u8>().unwrap();
117 let name = format!("DMA{instance}_CH{channel_number}");
118
119 // DMA has no pins.
120 assert!(signal.pins.is_empty());
121
122 singletons.push(Singleton { name, cfg: None });
123 }
124 }
125
126 for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("SCT")) {
127 let instance = peripheral.name.strip_prefix("SCT").unwrap();
128 assert!(instance.parse::<u8>().is_ok());
129
130 for signal in peripheral.signals.iter() {
131 if !signal.name.starts_with("OUT") {
132 continue;
133 }
134
135 let channel_number = signal.name.strip_prefix("OUT").unwrap().parse::<u8>().unwrap();
136 let name = format!("SCT{instance}_OUT{channel_number}");
137
138 singletons.push(Singleton { name, cfg: None });
67 } 139 }
140 }
141
142 singletons
143}
144
145#[cfg(feature = "_rt1xxx")]
146fn generate_iomuxc() -> TokenStream {
147 let iomuxc_pad_impls = metadata::METADATA
148 .pins
149 .iter()
150 .filter(|p| p.iomuxc.as_ref().filter(|i| i.mux.is_some()).is_some())
151 .map(|pin| {
152 let Some(ref iomuxc) = pin.iomuxc else {
153 panic!("Pin {} has no IOMUXC definitions", pin.name);
154 };
155
156 let name = Ident::new(pin.name, Span::call_site());
157 let mux = iomuxc.mux.unwrap();
158 let pad = iomuxc.pad;
159
160 quote! {
161 impl_iomuxc_pad!(#name, #pad, #mux);
162 }
163 });
164
165 let base_match_arms = metadata::METADATA
166 .peripherals
167 .iter()
168 .filter(|p| p.name.starts_with("GPIO"))
169 .map(|peripheral| {
170 peripheral.signals.iter().map(|signal| {
171 // All GPIO signals have a single pin.
172 let pin = &signal.pins[0];
173 let instance = peripheral.name.strip_prefix("GPIO").unwrap();
174 let bank_match = format_ident!("Gpio{}", instance);
175 let pin_number = signal.name.parse::<u8>().unwrap();
176 let pin_ident = Ident::new(pin.pin, Span::call_site());
177
178 quote! {
179 (Bank::#bank_match, #pin_number) => <crate::peripherals::#pin_ident as crate::iomuxc::SealedPad>
180 }
181 })
182 })
183 .flatten()
184 .collect::<Vec<_>>();
185
186 let pad_match_arms = base_match_arms.iter().map(|arm| {
187 quote! { #arm::PAD }
188 });
189
190 let mux_match_arms = base_match_arms.iter().map(|arm| {
191 quote! { #arm::MUX }
68 }); 192 });
69 193
70 quote! { 194 quote! {
71 pub mod iomuxc { 195 #(#iomuxc_pad_impls)*
72 pub mod pads { 196
73 #(#pads)* 197 pub(crate) fn iomuxc_pad(bank: crate::gpio::Bank, pin: u8) -> *mut () {
198 use crate::gpio::Bank;
199
200 match (bank, pin) {
201 #(#pad_match_arms),*,
202 _ => unreachable!()
74 } 203 }
204 }
205
206 pub(crate) fn iomuxc_mux(bank: crate::gpio::Bank, pin: u8) -> Option<*mut ()> {
207 use crate::gpio::Bank;
75 208
76 pub mod muxes { 209 match (bank, pin) {
77 #(#muxes)* 210 #(#mux_match_arms),*,
211 _ => unreachable!()
78 } 212 }
79 } 213 }
80 } 214 }
81} 215}
82 216
83fn generate_code() { 217fn generate_code(cfgs: &mut common::CfgSet, singletons: &[Singleton]) {
84 #[allow(unused)] 218 #[allow(unused)]
85 use std::fmt::Write; 219 use std::fmt::Write;
86 220
@@ -88,14 +222,179 @@ fn generate_code() {
88 #[allow(unused_mut)] 222 #[allow(unused_mut)]
89 let mut output = String::new(); 223 let mut output = String::new();
90 224
225 writeln!(&mut output, "{}", peripherals(singletons)).unwrap();
226
91 #[cfg(feature = "_rt1xxx")] 227 #[cfg(feature = "_rt1xxx")]
92 writeln!(&mut output, "{}", generate_iomuxc()).unwrap(); 228 writeln!(&mut output, "{}", generate_iomuxc()).unwrap();
93 229
230 writeln!(&mut output, "{}", interrupts()).unwrap();
231 writeln!(&mut output, "{}", impl_peripherals(cfgs, singletons)).unwrap();
232
94 let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); 233 let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string();
95 fs::write(&out_file, output).unwrap(); 234 fs::write(&out_file, output).unwrap();
96 rustfmt(&out_file); 235 rustfmt(&out_file);
97} 236}
98 237
238fn interrupts() -> TokenStream {
239 let interrupts = METADATA.interrupts.iter().map(|interrupt| format_ident!("{interrupt}"));
240
241 quote! {
242 embassy_hal_internal::interrupt_mod!(#(#interrupts),*);
243 }
244}
245
246fn peripherals(singletons: &[Singleton]) -> TokenStream {
247 let defs = singletons.iter().map(|s| {
248 let ident = Ident::new(&s.name, Span::call_site());
249 quote! { #ident }
250 });
251
252 let peripherals = singletons.iter().map(|s| {
253 let ident = Ident::new(&s.name, Span::call_site());
254 let cfg = s.cfg.clone().unwrap_or_else(|| quote! {});
255 quote! {
256 #cfg
257 #ident
258 }
259 });
260
261 quote! {
262 embassy_hal_internal::peripherals_definition!(#(#defs),*);
263 embassy_hal_internal::peripherals_struct!(#(#peripherals),*);
264 }
265}
266
267fn impl_gpio_pin(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) {
268 let instance = peripheral.name.strip_prefix("GPIO").unwrap();
269 let bank = format_ident!("Gpio{}", instance);
270 // let pin =
271
272 for signal in peripheral.signals.iter() {
273 let pin_number = signal.name.parse::<u8>().unwrap();
274 let pin = Ident::new(signal.pins[0].pin, Span::call_site());
275
276 impls.push(quote! {
277 impl_pin!(#pin, #bank, #pin_number);
278 });
279 }
280}
281
282fn impl_dma_channel(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) {
283 let instance = Ident::new(peripheral.name, Span::call_site());
284
285 for signal in peripheral.signals.iter() {
286 let channel_number = signal.name.parse::<u8>().unwrap();
287 let channel_name = format_ident!("{instance}_CH{channel_number}");
288
289 impls.push(quote! {
290 impl_dma_channel!(#instance, #channel_name, #channel_number);
291 });
292 }
293}
294
295fn impl_usart(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) {
296 let instance = Ident::new(peripheral.name, Span::call_site());
297 let flexcomm = Ident::new(
298 peripheral.flexcomm.expect("LPC55 must specify FLEXCOMM instance"),
299 Span::call_site(),
300 );
301 let number = Literal::u8_unsuffixed(peripheral.name.strip_prefix("USART").unwrap().parse::<u8>().unwrap());
302
303 impls.push(quote! {
304 impl_usart_instance!(#instance, #flexcomm, #number);
305 });
306
307 for signal in peripheral.signals {
308 let r#macro = match signal.name {
309 "TXD" => format_ident!("impl_usart_txd_pin"),
310 "RXD" => format_ident!("impl_usart_rxd_pin"),
311 _ => unreachable!(),
312 };
313
314 for pin in signal.pins {
315 let alt = format_ident!("ALT{}", pin.alt);
316 let pin = format_ident!("{}", pin.pin);
317
318 impls.push(quote! {
319 #r#macro!(#pin, #instance, #alt);
320 });
321 }
322 }
323
324 for dma_mux in peripheral.dma_muxing {
325 assert_eq!(dma_mux.mux, "DMA0", "TODO: USART for more than LPC55");
326
327 let r#macro = match dma_mux.signal {
328 "TX" => format_ident!("impl_usart_tx_channel"),
329 "RX" => format_ident!("impl_usart_rx_channel"),
330 _ => unreachable!(),
331 };
332
333 let channel = format_ident!("DMA0_CH{}", dma_mux.request);
334
335 impls.push(quote! {
336 #r#macro!(#instance, #channel);
337 });
338 }
339}
340
341fn impl_sct(impls: &mut Vec<TokenStream>, peripheral: &Peripheral) {
342 let instance = Ident::new(peripheral.name, Span::call_site());
343
344 impls.push(quote! {
345 impl_sct_instance!(#instance);
346 });
347
348 for signal in peripheral.signals.iter() {
349 if signal.name.starts_with("OUT") {
350 let channel_number = signal.name.strip_prefix("OUT").unwrap().parse::<u8>().unwrap();
351
352 let channel_name = format_ident!("{instance}_OUT{channel_number}");
353
354 impls.push(quote! {
355 impl_sct_output_instance!(#instance, #channel_name, #channel_number);
356 });
357
358 if signal.name.starts_with("OUT") {
359 for pin in signal.pins {
360 let pin_name = format_ident!("{}", pin.pin);
361 let alt = format_ident!("ALT{}", pin.alt);
362
363 impls.push(quote! {
364 impl_sct_output_pin!(#instance, #channel_name, #pin_name, #alt);
365 });
366 }
367 }
368 }
369 }
370}
371
372fn impl_peripherals(_cfgs: &mut common::CfgSet, _singletons: &[Singleton]) -> TokenStream {
373 let mut impls = Vec::new();
374
375 for peripheral in metadata::METADATA.peripherals.iter() {
376 if peripheral.name.starts_with("GPIO") {
377 impl_gpio_pin(&mut impls, peripheral);
378 }
379
380 if peripheral.name.starts_with("DMA") {
381 impl_dma_channel(&mut impls, peripheral);
382 }
383
384 if peripheral.name.starts_with("USART") {
385 impl_usart(&mut impls, peripheral);
386 }
387
388 if peripheral.name.starts_with("SCT") {
389 impl_sct(&mut impls, peripheral);
390 }
391 }
392
393 quote! {
394 #(#impls)*
395 }
396}
397
99/// rustfmt a given path. 398/// rustfmt a given path.
100/// Failures are logged to stderr and ignored. 399/// Failures are logged to stderr and ignored.
101fn rustfmt(path: impl AsRef<Path>) { 400fn rustfmt(path: impl AsRef<Path>) {