aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs148
-rw-r--r--embassy-stm32/src/adc/mod.rs6
-rw-r--r--embassy-stm32/src/can/bxcan.rs4
-rw-r--r--embassy-stm32/src/dac/mod.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs2
-rw-r--r--embassy-stm32/src/dma/bdma.rs69
-rw-r--r--embassy-stm32/src/dma/dma.rs42
-rw-r--r--embassy-stm32/src/dma/dmamux.rs4
-rw-r--r--embassy-stm32/src/exti.rs2
-rw-r--r--embassy-stm32/src/fmc/mod.rs2
-rw-r--r--embassy-stm32/src/gpio.rs2
-rw-r--r--embassy-stm32/src/i2c/mod.rs28
-rw-r--r--embassy-stm32/src/i2c/v1.rs8
-rw-r--r--embassy-stm32/src/i2c/v2.rs40
-rw-r--r--embassy-stm32/src/lib.rs28
-rw-r--r--embassy-stm32/src/pwm/mod.rs2
-rw-r--r--embassy-stm32/src/rng.rs4
-rw-r--r--embassy-stm32/src/sdmmc/v2.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs2
-rw-r--r--embassy-stm32/src/time_driver.rs2
-rw-r--r--embassy-stm32/src/timer/mod.rs2
-rw-r--r--embassy-stm32/src/usart/mod.rs2
-rw-r--r--embassy-stm32/src/usb_otg.rs4
-rw-r--r--stm32-metapac-gen/src/assets/lib_inner.rs6
-rw-r--r--stm32-metapac-gen/src/lib.rs723
-rw-r--r--stm32-metapac-gen/src/main.rs5
-rw-r--r--stm32-metapac/Cargo.toml15
-rw-r--r--stm32-metapac/build.rs27
-rw-r--r--stm32-metapac/build_pregenerated.rs (renamed from stm32-metapac-gen/src/assets/build.rs)10
-rw-r--r--stm32-metapac/src/common.rs80
-rw-r--r--stm32-metapac/src/lib.rs12
-rw-r--r--stm32-metapac/src/metadata.rs (renamed from stm32-metapac-gen/src/assets/metadata.rs)0
32 files changed, 661 insertions, 624 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 1257e0152..e67c4b983 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -2,6 +2,7 @@ use proc_macro2::TokenStream;
2use quote::{format_ident, quote}; 2use quote::{format_ident, quote};
3use std::collections::{HashMap, HashSet}; 3use std::collections::{HashMap, HashSet};
4use std::env; 4use std::env;
5use std::fmt::Write as _;
5use std::fs; 6use std::fs;
6use std::path::PathBuf; 7use std::path::PathBuf;
7use stm32_metapac::metadata::METADATA; 8use stm32_metapac::metadata::METADATA;
@@ -530,9 +531,127 @@ fn main() {
530 } 531 }
531 532
532 // ======== 533 // ========
533 // Write generated.rs 534 // Write foreach_foo! macrotables
535
536 let mut interrupts_table: Vec<Vec<String>> = Vec::new();
537 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
538 let mut pins_table: Vec<Vec<String>> = Vec::new();
539 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
540
541 let gpio_base = METADATA
542 .peripherals
543 .iter()
544 .find(|p| p.name == "GPIOA")
545 .unwrap()
546 .address as u32;
547 let gpio_stride = 0x400;
548
549 for p in METADATA.peripherals {
550 if let Some(regs) = &p.registers {
551 if regs.kind == "gpio" {
552 let port_letter = p.name.chars().skip(4).next().unwrap();
553 assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride);
554 let port_num = (p.address as u32 - gpio_base) / gpio_stride;
555
556 for pin_num in 0u32..16 {
557 let pin_name = format!("P{}{}", port_letter, pin_num);
558 pins_table.push(vec![
559 pin_name,
560 p.name.to_string(),
561 port_num.to_string(),
562 pin_num.to_string(),
563 format!("EXTI{}", pin_num),
564 ]);
565 }
566 }
567
568 for irq in p.interrupts {
569 let mut row = Vec::new();
570 row.push(p.name.to_string());
571 row.push(regs.kind.to_string());
572 row.push(regs.block.to_string());
573 row.push(irq.signal.to_string());
574 row.push(irq.interrupt.to_ascii_uppercase());
575 interrupts_table.push(row)
576 }
577
578 let mut row = Vec::new();
579 row.push(regs.kind.to_string());
580 row.push(p.name.to_string());
581 peripherals_table.push(row);
582 }
583 }
584
585 let mut dma_channel_count: usize = 0;
586 let mut bdma_channel_count: usize = 0;
587
588 for ch in METADATA.dma_channels {
589 let mut row = Vec::new();
590 let dma_peri = METADATA
591 .peripherals
592 .iter()
593 .find(|p| p.name == ch.dma)
594 .unwrap();
595 let bi = dma_peri.registers.as_ref().unwrap();
596
597 let num;
598 match bi.kind {
599 "dma" => {
600 num = dma_channel_count;
601 dma_channel_count += 1;
602 }
603 "bdma" => {
604 num = bdma_channel_count;
605 bdma_channel_count += 1;
606 }
607 _ => panic!("bad dma channel kind {}", bi.kind),
608 }
609
610 row.push(ch.name.to_string());
611 row.push(ch.dma.to_string());
612 row.push(bi.kind.to_string());
613 row.push(ch.channel.to_string());
614 row.push(num.to_string());
615 if let Some(dmamux) = &ch.dmamux {
616 let dmamux_channel = ch.dmamux_channel.unwrap();
617 row.push(format!(
618 "{{dmamux: {}, dmamux_channel: {}}}",
619 dmamux, dmamux_channel
620 ));
621 } else {
622 row.push("{}".to_string());
623 }
624
625 dma_channels_table.push(row);
626 }
627
628 g.extend(quote! {
629 pub(crate) const DMA_CHANNEL_COUNT: usize = #dma_channel_count;
630 pub(crate) const BDMA_CHANNEL_COUNT: usize = #bdma_channel_count;
631 });
632
633 for irq in METADATA.interrupts {
634 let name = irq.name.to_ascii_uppercase();
635 interrupts_table.push(vec![name.clone()]);
636 if name.contains("EXTI") {
637 interrupts_table.push(vec!["EXTI".to_string(), name.clone()]);
638 }
639 }
640
641 let mut m = String::new();
642
643 make_table(&mut m, "foreach_interrupt", &interrupts_table);
644 make_table(&mut m, "foreach_peripheral", &peripherals_table);
645 make_table(&mut m, "foreach_pin", &pins_table);
646 make_table(&mut m, "foreach_dma_channel", &dma_channels_table);
534 647
535 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 648 let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
649 let out_file = out_dir.join("macros.rs").to_string_lossy().to_string();
650 fs::write(out_file, m).unwrap();
651
652 // ========
653 // Write generated.rs
654
536 let out_file = out_dir.join("generated.rs").to_string_lossy().to_string(); 655 let out_file = out_dir.join("generated.rs").to_string_lossy().to_string();
537 fs::write(out_file, g.to_string()).unwrap(); 656 fs::write(out_file, g.to_string()).unwrap();
538 657
@@ -644,3 +763,30 @@ impl<T: Iterator> IteratorExt for T {
644 } 763 }
645 } 764 }
646} 765}
766
767fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) {
768 write!(
769 out,
770 "#[macro_export]
771macro_rules! {} {{
772 ($($pat:tt => $code:tt;)*) => {{
773 macro_rules! __{}_inner {{
774 $(($pat) => $code;)*
775 ($_:tt) => {{}}
776 }}
777",
778 name, name
779 )
780 .unwrap();
781
782 for row in data {
783 write!(out, " __{}_inner!(({}));\n", name, row.join(",")).unwrap();
784 }
785
786 write!(
787 out,
788 " }};
789}}"
790 )
791 .unwrap();
792}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 86f33ca19..7b3233a1d 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -36,7 +36,7 @@ pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral + 'static {}
36pub trait Common: sealed::Common + 'static {} 36pub trait Common: sealed::Common + 'static {}
37pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 37pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
38 38
39crate::pac::peripherals!( 39foreach_peripheral!(
40 (adc, $inst:ident) => { 40 (adc, $inst:ident) => {
41 impl crate::adc::sealed::Instance for peripherals::$inst { 41 impl crate::adc::sealed::Instance for peripherals::$inst {
42 fn regs() -> &'static crate::pac::adc::Adc { 42 fn regs() -> &'static crate::pac::adc::Adc {
@@ -44,7 +44,7 @@ crate::pac::peripherals!(
44 } 44 }
45 #[cfg(not(adc_f1))] 45 #[cfg(not(adc_f1))]
46 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon { 46 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
47 crate::pac::peripherals!{ 47 foreach_peripheral!{
48 (adccommon, $common_inst:ident) => { 48 (adccommon, $common_inst:ident) => {
49 return &crate::pac::$common_inst 49 return &crate::pac::$common_inst
50 }; 50 };
@@ -57,7 +57,7 @@ crate::pac::peripherals!(
57); 57);
58 58
59#[cfg(not(adc_f1))] 59#[cfg(not(adc_f1))]
60crate::pac::peripherals!( 60foreach_peripheral!(
61 (adccommon, $inst:ident) => { 61 (adccommon, $inst:ident) => {
62 impl sealed::Common for peripherals::$inst { 62 impl sealed::Common for peripherals::$inst {
63 fn regs() -> &'static crate::pac::adccommon::AdcCommon { 63 fn regs() -> &'static crate::pac::adccommon::AdcCommon {
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 856f3151a..c52d737bc 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -70,7 +70,7 @@ pub(crate) mod sealed {
70 70
71pub trait Instance: sealed::Instance + RccPeripheral {} 71pub trait Instance: sealed::Instance + RccPeripheral {}
72 72
73crate::pac::peripherals!( 73foreach_peripheral!(
74 (can, $inst:ident) => { 74 (can, $inst:ident) => {
75 impl sealed::Instance for peripherals::$inst { 75 impl sealed::Instance for peripherals::$inst {
76 fn regs() -> &'static crate::pac::can::Can { 76 fn regs() -> &'static crate::pac::can::Can {
@@ -86,7 +86,7 @@ crate::pac::peripherals!(
86 }; 86 };
87); 87);
88 88
89crate::pac::peripherals!( 89foreach_peripheral!(
90 (can, CAN) => { 90 (can, CAN) => {
91 unsafe impl bxcan::FilterOwner for peripherals::CAN { 91 unsafe impl bxcan::FilterOwner for peripherals::CAN {
92 const NUM_FILTER_BANKS: u8 = 14; 92 const NUM_FILTER_BANKS: u8 = 14;
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 7432c34a0..1f6ba63df 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -16,7 +16,7 @@ pub trait Instance: sealed::Instance + 'static {}
16 16
17pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} 17pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
18 18
19crate::pac::peripherals!( 19foreach_peripheral!(
20 (dac, $inst:ident) => { 20 (dac, $inst:ident) => {
21 impl crate::dac::sealed::Instance for peripherals::$inst { 21 impl crate::dac::sealed::Instance for peripherals::$inst {
22 fn regs() -> &'static crate::pac::dac::Dac { 22 fn regs() -> &'static crate::pac::dac::Dac {
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 9ac96c69a..bf78b631f 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -474,7 +474,7 @@ macro_rules! impl_peripheral {
474 }; 474 };
475} 475}
476 476
477crate::pac::interrupts! { 477foreach_interrupt! {
478 ($inst:ident, dcmi, $block:ident, GLOBAL, $irq:ident) => { 478 ($inst:ident, dcmi, $block:ident, GLOBAL, $irq:ident) => {
479 impl_peripheral!($inst, $irq); 479 impl_peripheral!($inst, $irq);
480 }; 480 };
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 2f0715cf6..4fafe7dfa 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -7,6 +7,7 @@ use embassy::interrupt::{Interrupt, InterruptExt};
7use embassy::waitqueue::AtomicWaker; 7use embassy::waitqueue::AtomicWaker;
8 8
9use crate::dma::Request; 9use crate::dma::Request;
10use crate::generated::BDMA_CHANNEL_COUNT;
10use crate::pac; 11use crate::pac;
11use crate::pac::bdma::vals; 12use crate::pac::bdma::vals;
12 13
@@ -22,62 +23,44 @@ impl From<WordSize> for vals::Size {
22 } 23 }
23} 24}
24 25
25const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8;
26
27struct State { 26struct State {
28 ch_wakers: [AtomicWaker; CH_COUNT], 27 ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT],
29} 28}
30 29
31impl State { 30impl State {
32 const fn new() -> Self { 31 const fn new() -> Self {
33 const AW: AtomicWaker = AtomicWaker::new(); 32 const AW: AtomicWaker = AtomicWaker::new();
34 Self { 33 Self {
35 ch_wakers: [AW; CH_COUNT], 34 ch_wakers: [AW; BDMA_CHANNEL_COUNT],
36 } 35 }
37 } 36 }
38} 37}
39 38
40static STATE: State = State::new(); 39static STATE: State = State::new();
41 40
42macro_rules! dma_num {
43 (DMA1) => {
44 0
45 };
46 (DMA2) => {
47 1
48 };
49 (BDMA) => {
50 0
51 };
52 (BDMA1) => {
53 0
54 };
55 (BDMA2) => {
56 1
57 };
58}
59
60pub(crate) unsafe fn on_irq() { 41pub(crate) unsafe fn on_irq() {
61 pac::peripherals! { 42 foreach_peripheral! {
43 (bdma, BDMA1) => {
44 // BDMA1 in H7 doesn't use DMAMUX, which breaks
45 };
62 (bdma, $dma:ident) => { 46 (bdma, $dma:ident) => {
63 let isr = pac::$dma.isr().read(); 47 let isr = pac::$dma.isr().read();
64 let dman = dma_num!($dma); 48 foreach_dma_channel! {
65 49 ($channel_peri:ident, $dma, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
66 for chn in 0..pac::dma_channels_count!($dma) { 50 let cr = pac::$dma.ch($channel_num).cr();
67 let cr = pac::$dma.ch(chn).cr(); 51 if isr.tcif($channel_num) && cr.read().tcie() {
68 if isr.tcif(chn) && cr.read().tcie() {
69 cr.write(|_| ()); // Disable channel interrupts with the default value. 52 cr.write(|_| ()); // Disable channel interrupts with the default value.
70 let n = dma_num!($dma) * 8 + chn; 53 STATE.ch_wakers[$index].wake();
71 STATE.ch_wakers[n].wake();
72 } 54 }
73 } 55 };
56 }
74 }; 57 };
75 } 58 }
76} 59}
77 60
78/// safety: must be called only once 61/// safety: must be called only once
79pub(crate) unsafe fn init() { 62pub(crate) unsafe fn init() {
80 pac::interrupts! { 63 foreach_interrupt! {
81 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { 64 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
82 crate::interrupt::$irq::steal().enable(); 65 crate::interrupt::$irq::steal().enable();
83 }; 66 };
@@ -85,20 +68,20 @@ pub(crate) unsafe fn init() {
85 crate::generated::init_bdma(); 68 crate::generated::init_bdma();
86} 69}
87 70
88pac::dma_channels! { 71foreach_dma_channel! {
89 ($channel_peri:ident, BDMA1, bdma, $channel_num:expr, $dmamux:tt) => { 72 ($channel_peri:ident, BDMA1, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
90 // BDMA1 in H7 doesn't use DMAMUX, which breaks 73 // BDMA1 in H7 doesn't use DMAMUX, which breaks
91 }; 74 };
92 ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => { 75 ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
93 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { 76 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
94 77
95 unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const[W], reg_addr: *mut W) { 78 unsafe fn start_write<W: Word>(&mut self, _request: Request, buf: *const[W], reg_addr: *mut W) {
96 let (ptr, len) = super::slice_ptr_parts(buf); 79 let (ptr, len) = super::slice_ptr_parts(buf);
97 low_level_api::start_transfer( 80 low_level_api::start_transfer(
98 pac::$dma_peri, 81 pac::$dma_peri,
99 $channel_num, 82 $channel_num,
100 #[cfg(any(bdma_v2, dmamux))] 83 #[cfg(any(bdma_v2, dmamux))]
101 request, 84 _request,
102 vals::Dir::FROMMEMORY, 85 vals::Dir::FROMMEMORY,
103 reg_addr as *const u32, 86 reg_addr as *const u32,
104 ptr as *mut u32, 87 ptr as *mut u32,
@@ -113,13 +96,13 @@ pac::dma_channels! {
113 } 96 }
114 97
115 98
116 unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { 99 unsafe fn start_write_repeated<W: Word>(&mut self, _request: Request, repeated: W, count: usize, reg_addr: *mut W) {
117 let buf = [repeated]; 100 let buf = [repeated];
118 low_level_api::start_transfer( 101 low_level_api::start_transfer(
119 pac::$dma_peri, 102 pac::$dma_peri,
120 $channel_num, 103 $channel_num,
121 #[cfg(any(bdma_v2, dmamux))] 104 #[cfg(any(bdma_v2, dmamux))]
122 request, 105 _request,
123 vals::Dir::FROMMEMORY, 106 vals::Dir::FROMMEMORY,
124 reg_addr as *const u32, 107 reg_addr as *const u32,
125 buf.as_ptr() as *mut u32, 108 buf.as_ptr() as *mut u32,
@@ -133,13 +116,13 @@ pac::dma_channels! {
133 ) 116 )
134 } 117 }
135 118
136 unsafe fn start_read<W: Word>(&mut self, request: Request, reg_addr: *const W, buf: *mut [W]) { 119 unsafe fn start_read<W: Word>(&mut self, _request: Request, reg_addr: *const W, buf: *mut [W]) {
137 let (ptr, len) = super::slice_ptr_parts_mut(buf); 120 let (ptr, len) = super::slice_ptr_parts_mut(buf);
138 low_level_api::start_transfer( 121 low_level_api::start_transfer(
139 pac::$dma_peri, 122 pac::$dma_peri,
140 $channel_num, 123 $channel_num,
141 #[cfg(any(bdma_v2, dmamux))] 124 #[cfg(any(bdma_v2, dmamux))]
142 request, 125 _request,
143 vals::Dir::FROMPERIPHERAL, 126 vals::Dir::FROMPERIPHERAL,
144 reg_addr as *const u32, 127 reg_addr as *const u32,
145 ptr as *mut u32, 128 ptr as *mut u32,
@@ -165,7 +148,7 @@ pac::dma_channels! {
165 } 148 }
166 149
167 fn set_waker(&mut self, waker: &Waker) { 150 fn set_waker(&mut self, waker: &Waker) {
168 unsafe {low_level_api::set_waker(dma_num!($dma_peri) * 8 + $channel_num, waker )} 151 unsafe { low_level_api::set_waker($index, waker) }
169 } 152 }
170 } 153 }
171 154
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index c885452b0..fd1732fbb 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -4,14 +4,13 @@ use core::task::Waker;
4use embassy::interrupt::{Interrupt, InterruptExt}; 4use embassy::interrupt::{Interrupt, InterruptExt};
5use embassy::waitqueue::AtomicWaker; 5use embassy::waitqueue::AtomicWaker;
6 6
7use crate::generated::DMA_CHANNEL_COUNT;
7use crate::interrupt; 8use crate::interrupt;
8use crate::pac; 9use crate::pac;
9use crate::pac::dma::{regs, vals}; 10use crate::pac::dma::{regs, vals};
10 11
11use super::{Request, Word, WordSize}; 12use super::{Request, Word, WordSize};
12 13
13const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8;
14
15impl From<WordSize> for vals::Size { 14impl From<WordSize> for vals::Size {
16 fn from(raw: WordSize) -> Self { 15 fn from(raw: WordSize) -> Self {
17 match raw { 16 match raw {
@@ -23,44 +22,31 @@ impl From<WordSize> for vals::Size {
23} 22}
24 23
25struct State { 24struct State {
26 ch_wakers: [AtomicWaker; CH_COUNT], 25 ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT],
27} 26}
28 27
29impl State { 28impl State {
30 const fn new() -> Self { 29 const fn new() -> Self {
31 const AW: AtomicWaker = AtomicWaker::new(); 30 const AW: AtomicWaker = AtomicWaker::new();
32 Self { 31 Self {
33 ch_wakers: [AW; CH_COUNT], 32 ch_wakers: [AW; DMA_CHANNEL_COUNT],
34 } 33 }
35 } 34 }
36} 35}
37 36
38static STATE: State = State::new(); 37static STATE: State = State::new();
39 38
40macro_rules! dma_num {
41 (DMA1) => {
42 0
43 };
44 (DMA2) => {
45 1
46 };
47}
48
49pub(crate) unsafe fn on_irq() { 39pub(crate) unsafe fn on_irq() {
50 pac::peripherals! { 40 foreach_peripheral! {
51 (dma, $dma:ident) => { 41 (dma, $dma:ident) => {
52 for isrn in 0..2 { 42 foreach_dma_channel! {
53 let isr = pac::$dma.isr(isrn).read(); 43 ($channel_peri:ident, $dma, dma, $channel_num:expr, $index:expr, $dmamux:tt) => {
54 44 let cr = pac::$dma.st($channel_num).cr();
55 for chn in 0..4 { 45 if pac::$dma.isr($channel_num/4).read().tcif($channel_num%4) && cr.read().tcie() {
56 let cr = pac::$dma.st(isrn * 4 + chn).cr();
57
58 if isr.tcif(chn) && cr.read().tcie() {
59 cr.write(|_| ()); // Disable channel interrupts with the default value. 46 cr.write(|_| ()); // Disable channel interrupts with the default value.
60 let n = dma_num!($dma) * 8 + isrn * 4 + chn; 47 STATE.ch_wakers[$index].wake();
61 STATE.ch_wakers[n].wake();
62 } 48 }
63 } 49 };
64 } 50 }
65 }; 51 };
66 } 52 }
@@ -68,7 +54,7 @@ pub(crate) unsafe fn on_irq() {
68 54
69/// safety: must be called only once 55/// safety: must be called only once
70pub(crate) unsafe fn init() { 56pub(crate) unsafe fn init() {
71 pac::interrupts! { 57 foreach_interrupt! {
72 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 58 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
73 interrupt::$irq::steal().enable(); 59 interrupt::$irq::steal().enable();
74 }; 60 };
@@ -76,8 +62,8 @@ pub(crate) unsafe fn init() {
76 crate::generated::init_dma(); 62 crate::generated::init_dma();
77} 63}
78 64
79pac::dma_channels! { 65foreach_dma_channel! {
80 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => { 66 ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => {
81 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { 67 impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
82 unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W) { 68 unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W) {
83 let (ptr, len) = super::slice_ptr_parts(buf); 69 let (ptr, len) = super::slice_ptr_parts(buf);
@@ -149,7 +135,7 @@ pac::dma_channels! {
149 } 135 }
150 136
151 fn set_waker(&mut self, waker: &Waker) { 137 fn set_waker(&mut self, waker: &Waker) {
152 unsafe {low_level_api::set_waker(dma_num!($dma_peri) * 8 + $channel_num, waker )} 138 unsafe {low_level_api::set_waker($index, waker )}
153 } 139 }
154 } 140 }
155 141
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index 971695a06..628f496be 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -35,8 +35,8 @@ pub trait MuxChannel: sealed::MuxChannel + super::Channel {
35 type Mux; 35 type Mux;
36} 36}
37 37
38pac::dma_channels! { 38foreach_dma_channel! {
39 ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { 39 ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $index:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => {
40 impl sealed::MuxChannel for peripherals::$channel_peri { 40 impl sealed::MuxChannel for peripherals::$channel_peri {
41 const DMAMUX_CH_NUM: u8 = $dmamux_channel; 41 const DMAMUX_CH_NUM: u8 = $dmamux_channel;
42 const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux; 42 const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux;
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 909d0ee88..47307530b 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -278,7 +278,7 @@ impl<'a> Future for ExtiInputFuture<'a> {
278 278
279macro_rules! foreach_exti_irq { 279macro_rules! foreach_exti_irq {
280 ($action:ident) => { 280 ($action:ident) => {
281 crate::pac::interrupts!( 281 foreach_interrupt!(
282 (EXTI0) => { $action!(EXTI0); }; 282 (EXTI0) => { $action!(EXTI0); };
283 (EXTI1) => { $action!(EXTI1); }; 283 (EXTI1) => { $action!(EXTI1); };
284 (EXTI2) => { $action!(EXTI2); }; 284 (EXTI2) => { $action!(EXTI2); };
diff --git a/embassy-stm32/src/fmc/mod.rs b/embassy-stm32/src/fmc/mod.rs
index a17b88ea9..2a730f5f8 100644
--- a/embassy-stm32/src/fmc/mod.rs
+++ b/embassy-stm32/src/fmc/mod.rs
@@ -127,7 +127,7 @@ impl<'d, T: Instance> Fmc<'d, T> {
127 )); 127 ));
128} 128}
129 129
130crate::pac::peripherals!( 130foreach_peripheral!(
131 (fmc, $inst:ident) => { 131 (fmc, $inst:ident) => {
132 impl crate::fmc::sealed::Instance for crate::peripherals::$inst { 132 impl crate::fmc::sealed::Instance for crate::peripherals::$inst {
133 fn regs() -> stm32_metapac::fmc::Fmc { 133 fn regs() -> stm32_metapac::fmc::Fmc {
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index aef8ee552..4837c4120 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -558,7 +558,7 @@ impl sealed::Pin for AnyPin {
558 558
559// ==================== 559// ====================
560 560
561crate::pac::pins!( 561foreach_pin!(
562 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { 562 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => {
563 impl Pin for peripherals::$pin_name { 563 impl Pin for peripherals::$pin_name {
564 #[cfg(feature = "exti")] 564 #[cfg(feature = "exti")]
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index aad1c1375..c2a4c2546 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -21,9 +21,10 @@ pub enum Error {
21} 21}
22 22
23pub(crate) mod sealed { 23pub(crate) mod sealed {
24 use super::*;
24 pub trait Instance: crate::rcc::RccPeripheral { 25 pub trait Instance: crate::rcc::RccPeripheral {
25 fn regs() -> crate::pac::i2c::I2c; 26 fn regs() -> crate::pac::i2c::I2c;
26 fn state_number() -> usize; 27 fn state() -> &'static State;
27 } 28 }
28} 29}
29 30
@@ -36,33 +37,16 @@ pin_trait!(SdaPin, Instance);
36dma_trait!(RxDma, Instance); 37dma_trait!(RxDma, Instance);
37dma_trait!(TxDma, Instance); 38dma_trait!(TxDma, Instance);
38 39
39macro_rules! i2c_state { 40foreach_interrupt!(
40 (I2C1) => {
41 0
42 };
43 (I2C2) => {
44 1
45 };
46 (I2C3) => {
47 2
48 };
49 (I2C4) => {
50 3
51 };
52 (I2C5) => {
53 4
54 };
55}
56
57crate::pac::interrupts!(
58 ($inst:ident, i2c, $block:ident, EV, $irq:ident) => { 41 ($inst:ident, i2c, $block:ident, EV, $irq:ident) => {
59 impl sealed::Instance for peripherals::$inst { 42 impl sealed::Instance for peripherals::$inst {
60 fn regs() -> crate::pac::i2c::I2c { 43 fn regs() -> crate::pac::i2c::I2c {
61 crate::pac::$inst 44 crate::pac::$inst
62 } 45 }
63 46
64 fn state_number() -> usize { 47 fn state() -> &'static State {
65 i2c_state!($inst) 48 static STATE: State = State::new();
49 &STATE
66 } 50 }
67 } 51 }
68 52
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 2bd0dcdf7..f280187e5 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -7,6 +7,14 @@ use crate::i2c::{Error, Instance, SclPin, SdaPin};
7use crate::pac::i2c; 7use crate::pac::i2c;
8use crate::time::Hertz; 8use crate::time::Hertz;
9 9
10pub struct State {}
11
12impl State {
13 pub(crate) const fn new() -> Self {
14 Self {}
15 }
16}
17
10pub struct I2c<'d, T: Instance> { 18pub struct I2c<'d, T: Instance> {
11 phantom: PhantomData<&'d mut T>, 19 phantom: PhantomData<&'d mut T>,
12} 20}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index a1ba5bc7d..2c46237d6 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -13,31 +13,23 @@ use futures::future::poll_fn;
13use crate::dma::NoDma; 13use crate::dma::NoDma;
14use crate::gpio::sealed::AFType; 14use crate::gpio::sealed::AFType;
15use crate::i2c::{Error, Instance, SclPin, SdaPin}; 15use crate::i2c::{Error, Instance, SclPin, SdaPin};
16use crate::pac;
17use crate::pac::i2c; 16use crate::pac::i2c;
18use crate::time::Hertz; 17use crate::time::Hertz;
19 18
20const I2C_COUNT: usize = pac::peripheral_count!(i2c);
21
22pub struct State { 19pub struct State {
23 waker: [AtomicWaker; I2C_COUNT], 20 waker: AtomicWaker,
24 chunks_transferred: [AtomicUsize; I2C_COUNT], 21 chunks_transferred: AtomicUsize,
25} 22}
26 23
27impl State { 24impl State {
28 const fn new() -> Self { 25 pub(crate) const fn new() -> Self {
29 const AW: AtomicWaker = AtomicWaker::new();
30 const CT: AtomicUsize = AtomicUsize::new(0);
31
32 Self { 26 Self {
33 waker: [AW; I2C_COUNT], 27 waker: AtomicWaker::new(),
34 chunks_transferred: [CT; I2C_COUNT], 28 chunks_transferred: AtomicUsize::new(0),
35 } 29 }
36 } 30 }
37} 31}
38 32
39static STATE: State = State::new();
40
41pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { 33pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
42 phantom: PhantomData<&'d mut T>, 34 phantom: PhantomData<&'d mut T>,
43 tx_dma: TXDMA, 35 tx_dma: TXDMA,
@@ -108,9 +100,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
108 let isr = regs.isr().read(); 100 let isr = regs.isr().read();
109 101
110 if isr.tcr() || isr.tc() { 102 if isr.tcr() || isr.tc() {
111 let n = T::state_number(); 103 let state = T::state();
112 STATE.chunks_transferred[n].fetch_add(1, Ordering::Relaxed); 104 state.chunks_transferred.fetch_add(1, Ordering::Relaxed);
113 STATE.waker[n].wake(); 105 state.waker.wake();
114 } 106 }
115 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable 107 // The flag can only be cleared by writting to nbytes, we won't do that here, so disable
116 // the interrupt 108 // the interrupt
@@ -411,8 +403,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
411 crate::dma::write(ch, request, bytes, dst) 403 crate::dma::write(ch, request, bytes, dst)
412 }; 404 };
413 405
414 let state_number = T::state_number(); 406 let state = T::state();
415 STATE.chunks_transferred[state_number].store(0, Ordering::Relaxed); 407 state.chunks_transferred.store(0, Ordering::Relaxed);
416 let mut remaining_len = total_len; 408 let mut remaining_len = total_len;
417 409
418 let _on_drop = OnDrop::new(|| { 410 let _on_drop = OnDrop::new(|| {
@@ -445,8 +437,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
445 } 437 }
446 438
447 poll_fn(|cx| { 439 poll_fn(|cx| {
448 STATE.waker[state_number].register(cx.waker()); 440 state.waker.register(cx.waker());
449 let chunks_transferred = STATE.chunks_transferred[state_number].load(Ordering::Relaxed); 441 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
450 442
451 if chunks_transferred == total_chunks { 443 if chunks_transferred == total_chunks {
452 return Poll::Ready(()); 444 return Poll::Ready(());
@@ -504,8 +496,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
504 crate::dma::read(ch, request, src, buffer) 496 crate::dma::read(ch, request, src, buffer)
505 }; 497 };
506 498
507 let state_number = T::state_number(); 499 let state = T::state();
508 STATE.chunks_transferred[state_number].store(0, Ordering::Relaxed); 500 state.chunks_transferred.store(0, Ordering::Relaxed);
509 let mut remaining_len = total_len; 501 let mut remaining_len = total_len;
510 502
511 let _on_drop = OnDrop::new(|| { 503 let _on_drop = OnDrop::new(|| {
@@ -530,8 +522,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
530 } 522 }
531 523
532 poll_fn(|cx| { 524 poll_fn(|cx| {
533 STATE.waker[state_number].register(cx.waker()); 525 state.waker.register(cx.waker());
534 let chunks_transferred = STATE.chunks_transferred[state_number].load(Ordering::Relaxed); 526 let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
535 527
536 if chunks_transferred == total_chunks { 528 if chunks_transferred == total_chunks {
537 return Poll::Ready(()); 529 return Poll::Ready(());
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 79221e600..5e8d6dd86 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -11,6 +11,7 @@ pub(crate) use stm32_metapac as pac;
11 11
12// This must go FIRST so that all the other modules see its macros. 12// This must go FIRST so that all the other modules see its macros.
13pub mod fmt; 13pub mod fmt;
14include!(concat!(env!("OUT_DIR"), "/macros.rs"));
14 15
15// Utilities 16// Utilities
16pub mod interrupt; 17pub mod interrupt;
@@ -62,7 +63,7 @@ pub mod usb_otg;
62pub mod subghz; 63pub mod subghz;
63 64
64// This must go last, so that it sees all the impl_foo! macros defined earlier. 65// This must go last, so that it sees all the impl_foo! macros defined earlier.
65mod generated { 66pub(crate) mod generated {
66 67
67 #![allow(dead_code)] 68 #![allow(dead_code)]
68 #![allow(unused_imports)] 69 #![allow(unused_imports)]
@@ -98,10 +99,27 @@ pub fn init(config: Config) -> Peripherals {
98 #[cfg(dbgmcu)] 99 #[cfg(dbgmcu)]
99 if config.enable_debug_during_sleep { 100 if config.enable_debug_during_sleep {
100 crate::pac::DBGMCU.cr().modify(|cr| { 101 crate::pac::DBGMCU.cr().modify(|cr| {
101 crate::pac::dbgmcu! { 102 #[cfg(any(dbgmcu_f0, dbgmcu_g0, dbgmcu_u5))]
102 (cr, $fn_name:ident) => { 103 {
103 cr.$fn_name(true); 104 cr.set_dbg_stop(true);
104 }; 105 cr.set_dbg_standby(true);
106 }
107 #[cfg(any(
108 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7,
109 dbgmcu_l0, dbgmcu_l1, dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
110 ))]
111 {
112 cr.set_dbg_sleep(true);
113 cr.set_dbg_stop(true);
114 cr.set_dbg_standby(true);
115 }
116 #[cfg(dbgmcu_h7)]
117 {
118 cr.set_d1dbgcken(true);
119 cr.set_d3dbgcken(true);
120 cr.set_dbgsleep_d1(true);
121 cr.set_dbgstby_d1(true);
122 cr.set_dbgstop_d1(true);
105 } 123 }
106 }); 124 });
107 } 125 }
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
index edc34fa5c..e8938ffae 100644
--- a/embassy-stm32/src/pwm/mod.rs
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -127,7 +127,7 @@ macro_rules! impl_compare_capable_16bit {
127 }; 127 };
128} 128}
129 129
130crate::pac::interrupts! { 130foreach_interrupt! {
131 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 131 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
132 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { 132 impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
133 unsafe fn set_output_compare_mode( 133 unsafe fn set_output_compare_mode(
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 032fee011..0a93951bf 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -136,7 +136,7 @@ pub(crate) mod sealed {
136 136
137pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral {} 137pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral {}
138 138
139crate::pac::peripherals!( 139foreach_peripheral!(
140 (rng, $inst:ident) => { 140 (rng, $inst:ident) => {
141 impl Instance for peripherals::$inst {} 141 impl Instance for peripherals::$inst {}
142 142
@@ -165,7 +165,7 @@ macro_rules! irq {
165 }; 165 };
166} 166}
167 167
168crate::pac::interrupts!( 168foreach_interrupt!(
169 (RNG) => { 169 (RNG) => {
170 irq!(RNG); 170 irq!(RNG);
171 }; 171 };
diff --git a/embassy-stm32/src/sdmmc/v2.rs b/embassy-stm32/src/sdmmc/v2.rs
index 1f4c9db70..cb8fa5544 100644
--- a/embassy-stm32/src/sdmmc/v2.rs
+++ b/embassy-stm32/src/sdmmc/v2.rs
@@ -1271,7 +1271,7 @@ where
1271 } 1271 }
1272} 1272}
1273 1273
1274crate::pac::peripherals!( 1274foreach_peripheral!(
1275 (sdmmc, $inst:ident) => { 1275 (sdmmc, $inst:ident) => {
1276 impl sealed::Instance for peripherals::$inst { 1276 impl sealed::Instance for peripherals::$inst {
1277 type Interrupt = crate::interrupt::$inst; 1277 type Interrupt = crate::interrupt::$inst;
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index fe2014147..e3b647280 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -874,7 +874,7 @@ pin_trait!(MisoPin, Instance);
874dma_trait!(RxDma, Instance); 874dma_trait!(RxDma, Instance);
875dma_trait!(TxDma, Instance); 875dma_trait!(TxDma, Instance);
876 876
877crate::pac::peripherals!( 877foreach_peripheral!(
878 (spi, $inst:ident) => { 878 (spi, $inst:ident) => {
879 impl sealed::Instance for peripherals::$inst { 879 impl sealed::Instance for peripherals::$inst {
880 fn regs() -> &'static crate::pac::spi::Spi { 880 fn regs() -> &'static crate::pac::spi::Spi {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 98054e051..009c62030 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -29,7 +29,7 @@ type T = peripherals::TIM4;
29#[cfg(time_driver_tim5)] 29#[cfg(time_driver_tim5)]
30type T = peripherals::TIM5; 30type T = peripherals::TIM5;
31 31
32crate::pac::interrupts! { 32foreach_interrupt! {
33 (TIM2, timer, $block:ident, UP, $irq:ident) => { 33 (TIM2, timer, $block:ident, UP, $irq:ident) => {
34 #[cfg(time_driver_tim2)] 34 #[cfg(time_driver_tim2)]
35 #[interrupt] 35 #[interrupt]
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index e3389fbad..4c1eb946b 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -155,7 +155,7 @@ macro_rules! impl_32bit_timer {
155 }; 155 };
156} 156}
157 157
158crate::pac::interrupts! { 158foreach_interrupt! {
159 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 159 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
160 impl_basic_16bit_timer!($inst, $irq); 160 impl_basic_16bit_timer!($inst, $irq);
161 161
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 12e5d503d..60e607126 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -601,7 +601,7 @@ pin_trait!(CkPin, Instance);
601dma_trait!(TxDma, Instance); 601dma_trait!(TxDma, Instance);
602dma_trait!(RxDma, Instance); 602dma_trait!(RxDma, Instance);
603 603
604crate::pac::interrupts!( 604foreach_interrupt!(
605 ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { 605 ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
606 impl sealed::Instance for peripherals::$inst { 606 impl sealed::Instance for peripherals::$inst {
607 fn regs(&self) -> crate::pac::usart::Usart { 607 fn regs(&self) -> crate::pac::usart::Usart {
diff --git a/embassy-stm32/src/usb_otg.rs b/embassy-stm32/src/usb_otg.rs
index 6e08815d0..8c2c1e99c 100644
--- a/embassy-stm32/src/usb_otg.rs
+++ b/embassy-stm32/src/usb_otg.rs
@@ -135,7 +135,7 @@ pin_trait!(UlpiD5Pin, Instance);
135pin_trait!(UlpiD6Pin, Instance); 135pin_trait!(UlpiD6Pin, Instance);
136pin_trait!(UlpiD7Pin, Instance); 136pin_trait!(UlpiD7Pin, Instance);
137 137
138crate::pac::peripherals!( 138foreach_peripheral!(
139 (otgfs, $inst:ident) => { 139 (otgfs, $inst:ident) => {
140 impl sealed::Instance for peripherals::$inst { 140 impl sealed::Instance for peripherals::$inst {
141 const REGISTERS: *const () = crate::pac::$inst.0 as *const (); 141 const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
@@ -223,7 +223,7 @@ crate::pac::peripherals!(
223 }; 223 };
224); 224);
225 225
226crate::pac::interrupts!( 226foreach_interrupt!(
227 ($inst:ident, otgfs, $block:ident, GLOBAL, $irq:ident) => { 227 ($inst:ident, otgfs, $block:ident, GLOBAL, $irq:ident) => {
228 unsafe impl USBInterrupt for crate::interrupt::$irq {} 228 unsafe impl USBInterrupt for crate::interrupt::$irq {}
229 }; 229 };
diff --git a/stm32-metapac-gen/src/assets/lib_inner.rs b/stm32-metapac-gen/src/assets/lib_inner.rs
deleted file mode 100644
index b7729cb3a..000000000
--- a/stm32-metapac-gen/src/assets/lib_inner.rs
+++ /dev/null
@@ -1,6 +0,0 @@
1// GEN PATHS HERE
2mod inner;
3
4pub mod common;
5
6pub use inner::*;
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs
index 575be9e4b..14625097e 100644
--- a/stm32-metapac-gen/src/lib.rs
+++ b/stm32-metapac-gen/src/lib.rs
@@ -1,8 +1,9 @@
1use chiptool::generate::CommonModule; 1use chiptool::generate::CommonModule;
2use chiptool::{generate, ir, transform};
2use proc_macro2::TokenStream; 3use proc_macro2::TokenStream;
3use regex::Regex; 4use regex::Regex;
4use std::collections::{BTreeMap, HashMap, HashSet}; 5use std::collections::{BTreeMap, HashMap, HashSet};
5use std::fmt::Write as _; 6use std::fmt::{Debug, Write as _};
6use std::fs; 7use std::fs;
7use std::fs::File; 8use std::fs::File;
8use std::io::Write; 9use std::io::Write;
@@ -10,9 +11,6 @@ use std::path::Path;
10use std::path::PathBuf; 11use std::path::PathBuf;
11use std::str::FromStr; 12use std::str::FromStr;
12 13
13use chiptool::util::ToSanitizedSnakeCase;
14use chiptool::{generate, ir, transform};
15
16mod data; 14mod data;
17use data::*; 15use data::*;
18 16
@@ -27,532 +25,322 @@ struct Metadata<'a> {
27 dma_channels: &'a [DmaChannel], 25 dma_channels: &'a [DmaChannel],
28} 26}
29 27
30fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) {
31 write!(
32 out,
33 "#[macro_export]
34macro_rules! peripheral_count {{
35 "
36 )
37 .unwrap();
38 for (name, count) in data {
39 write!(out, "({}) => ({});\n", name, count,).unwrap();
40 }
41 write!(out, " }}\n").unwrap();
42}
43
44fn make_dma_channel_counts(out: &mut String, data: &BTreeMap<String, u8>) {
45 if data.len() == 0 {
46 return;
47 }
48 write!(
49 out,
50 "#[macro_export]
51macro_rules! dma_channels_count {{
52 "
53 )
54 .unwrap();
55 for (name, count) in data {
56 write!(out, "({}) => ({});\n", name, count,).unwrap();
57 }
58 write!(out, " }}\n").unwrap();
59}
60
61fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) {
62 write!(
63 out,
64 "#[macro_export]
65macro_rules! {} {{
66 ($($pat:tt => $code:tt;)*) => {{
67 macro_rules! __{}_inner {{
68 $(($pat) => $code;)*
69 ($_:tt) => {{}}
70 }}
71",
72 name, name
73 )
74 .unwrap();
75
76 for row in data {
77 write!(out, " __{}_inner!(({}));\n", name, row.join(",")).unwrap();
78 }
79
80 write!(
81 out,
82 " }};
83}}"
84 )
85 .unwrap();
86}
87
88pub struct Options { 28pub struct Options {
89 pub chips: Vec<String>, 29 pub chips: Vec<String>,
90 pub out_dir: PathBuf, 30 pub out_dir: PathBuf,
91 pub data_dir: PathBuf, 31 pub data_dir: PathBuf,
92} 32}
93 33
94pub fn gen_chip( 34pub struct Gen {
95 options: &Options, 35 opts: Options,
96 chip_core_name: &str, 36 all_peripheral_versions: HashSet<(String, String)>,
97 chip: &Chip, 37 metadata_dedup: HashMap<String, String>,
98 core: &Core, 38}
99 core_index: usize, 39
100 all_peripheral_versions: &mut HashSet<(String, String)>, 40impl Gen {
101) { 41 pub fn new(opts: Options) -> Self {
102 let mut ir = ir::IR::new(); 42 Self {
103 43 opts,
104 let mut dev = ir::Device { 44 all_peripheral_versions: HashSet::new(),
105 interrupts: Vec::new(), 45 metadata_dedup: HashMap::new(),
106 peripherals: Vec::new(),
107 };
108
109 // Load DBGMCU register for chip
110 let mut dbgmcu: Option<ir::IR> = core.peripherals.iter().find_map(|p| {
111 if p.name == "DBGMCU" {
112 p.registers.as_ref().map(|bi| {
113 let dbgmcu_reg_path = options
114 .data_dir
115 .join("registers")
116 .join(&format!("{}_{}.yaml", bi.kind, bi.version));
117 serde_yaml::from_reader(File::open(dbgmcu_reg_path).unwrap()).unwrap()
118 })
119 } else {
120 None
121 }
122 });
123
124 let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new();
125 let mut pin_table: Vec<Vec<String>> = Vec::new();
126 let mut interrupt_table: Vec<Vec<String>> = Vec::new();
127 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
128 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
129 let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new();
130 let mut dma_channel_counts: BTreeMap<String, u8> = BTreeMap::new();
131 let mut dbgmcu_table: Vec<Vec<String>> = Vec::new();
132
133 let gpio_base = core
134 .peripherals
135 .iter()
136 .find(|p| p.name == "GPIOA")
137 .unwrap()
138 .address as u32;
139 let gpio_stride = 0x400;
140
141 let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap();
142
143 if let Some(ref mut reg) = dbgmcu {
144 if let Some(ref cr) = reg.fieldsets.get("CR") {
145 for field in cr.fields.iter().filter(|e| e.name.contains("DBG")) {
146 let mut fn_name = String::new();
147 fn_name.push_str("set_");
148 fn_name.push_str(&field.name.to_sanitized_snake_case());
149 dbgmcu_table.push(vec!["cr".into(), fn_name]);
150 }
151 } 46 }
152 } 47 }
153 48
154 for p in &core.peripherals { 49 fn gen_chip(&mut self, chip_core_name: &str, chip: &Chip, core: &Core, core_index: usize) {
155 let captures = number_suffix_re.captures(&p.name).unwrap(); 50 let mut ir = ir::IR::new();
156 let root_peri_name = captures.get(1).unwrap().as_str().to_string(); 51
157 peripheral_counts.insert( 52 let mut dev = ir::Device {
158 root_peri_name.clone(), 53 interrupts: Vec::new(),
159 peripheral_counts.get(&root_peri_name).map_or(1, |v| v + 1), 54 peripherals: Vec::new(),
160 );
161 let mut ir_peri = ir::Peripheral {
162 name: p.name.clone(),
163 array: None,
164 base_address: p.address,
165 block: None,
166 description: None,
167 interrupts: HashMap::new(),
168 }; 55 };
169 56
170 if let Some(bi) = &p.registers { 57 let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new();
171 peripheral_counts.insert( 58
172 bi.kind.clone(), 59 let gpio_base = core
173 peripheral_counts.get(&bi.kind).map_or(1, |v| v + 1), 60 .peripherals
174 ); 61 .iter()
175 62 .find(|p| p.name == "GPIOA")
176 for irq in &p.interrupts { 63 .unwrap()
177 let mut row = Vec::new(); 64 .address as u32;
178 row.push(p.name.clone()); 65 let gpio_stride = 0x400;
179 row.push(bi.kind.clone()); 66
180 row.push(bi.block.clone()); 67 for p in &core.peripherals {
181 row.push(irq.signal.clone()); 68 let mut ir_peri = ir::Peripheral {
182 row.push(irq.interrupt.to_ascii_uppercase()); 69 name: p.name.clone(),
183 interrupt_table.push(row) 70 array: None,
184 } 71 base_address: p.address,
72 block: None,
73 description: None,
74 interrupts: HashMap::new(),
75 };
185 76
186 let mut peripheral_row = Vec::new(); 77 if let Some(bi) = &p.registers {
187 peripheral_row.push(bi.kind.clone()); 78 if let Some(old_version) =
188 peripheral_row.push(p.name.clone()); 79 peripheral_versions.insert(bi.kind.clone(), bi.version.clone())
189 peripherals_table.push(peripheral_row); 80 {
190 81 if old_version != bi.version {
191 if let Some(old_version) = 82 panic!(
192 peripheral_versions.insert(bi.kind.clone(), bi.version.clone()) 83 "Peripheral {} has multiple versions: {} and {}",
193 { 84 bi.kind, old_version, bi.version
194 if old_version != bi.version { 85 );
195 panic!( 86 }
196 "Peripheral {} has multiple versions: {} and {}",
197 bi.kind, old_version, bi.version
198 );
199 } 87 }
200 } 88 ir_peri.block = Some(format!("{}::{}", bi.kind, bi.block));
201 ir_peri.block = Some(format!("{}::{}", bi.kind, bi.block));
202 89
203 match bi.kind.as_str() { 90 if bi.kind == "gpio" {
204 "gpio" => {
205 let port_letter = p.name.chars().skip(4).next().unwrap();
206 assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride); 91 assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride);
207 let port_num = (p.address as u32 - gpio_base) / gpio_stride;
208
209 for pin_num in 0u32..16 {
210 let pin_name = format!("P{}{}", port_letter, pin_num);
211 pin_table.push(vec![
212 pin_name.clone(),
213 p.name.clone(),
214 port_num.to_string(),
215 pin_num.to_string(),
216 format!("EXTI{}", pin_num),
217 ]);
218 }
219 } 92 }
220 _ => {}
221 } 93 }
222 }
223
224 dev.peripherals.push(ir_peri);
225 }
226 94
227 for ch in &core.dma_channels { 95 dev.peripherals.push(ir_peri);
228 let mut row = Vec::new();
229 let dma_peri = core.peripherals.iter().find(|p| p.name == ch.dma).unwrap();
230 let bi = dma_peri.registers.as_ref().unwrap();
231
232 row.push(ch.name.clone());
233 row.push(ch.dma.clone());
234 row.push(bi.kind.clone());
235 row.push(ch.channel.to_string());
236 if let Some(dmamux) = &ch.dmamux {
237 let dmamux_channel = ch.dmamux_channel.unwrap();
238 row.push(format!(
239 "{{dmamux: {}, dmamux_channel: {}}}",
240 dmamux, dmamux_channel
241 ));
242 } else {
243 row.push("{}".to_string());
244 } 96 }
245 97
246 dma_channels_table.push(row); 98 for irq in &core.interrupts {
247 99 dev.interrupts.push(ir::Interrupt {
248 let dma_peri_name = ch.dma.clone(); 100 name: irq.name.clone(),
249 dma_channel_counts.insert( 101 description: None,
250 dma_peri_name.clone(), 102 value: irq.number,
251 dma_channel_counts.get(&dma_peri_name).map_or(1, |v| v + 1), 103 });
252 );
253 }
254
255 for irq in &core.interrupts {
256 dev.interrupts.push(ir::Interrupt {
257 name: irq.name.clone(),
258 description: None,
259 value: irq.number,
260 });
261
262 let name = irq.name.to_ascii_uppercase();
263
264 interrupt_table.push(vec![name.clone()]);
265
266 if name.contains("EXTI") {
267 interrupt_table.push(vec!["EXTI".to_string(), name.clone()]);
268 } 104 }
269 }
270 105
271 ir.devices.insert("".to_string(), dev); 106 ir.devices.insert("".to_string(), dev);
272 107
273 let mut extra = format!( 108 let mut extra = format!(
274 "pub fn GPIO(n: usize) -> gpio::Gpio {{ 109 "pub fn GPIO(n: usize) -> gpio::Gpio {{
275 gpio::Gpio(({} + {}*n) as _) 110 gpio::Gpio(({} + {}*n) as _)
276 }}", 111 }}",
277 gpio_base, gpio_stride, 112 gpio_base, gpio_stride,
278 ); 113 );
279 114
280 for (module, version) in &peripheral_versions { 115 for (module, version) in &peripheral_versions {
281 all_peripheral_versions.insert((module.clone(), version.clone())); 116 self.all_peripheral_versions
117 .insert((module.clone(), version.clone()));
118 write!(
119 &mut extra,
120 "#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n",
121 module, version, module
122 )
123 .unwrap();
124 }
282 write!( 125 write!(
283 &mut extra, 126 &mut extra,
284 "#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n", 127 "pub const CORE_INDEX: usize = {};\n",
285 module, version, module 128 core_index
286 ) 129 )
287 .unwrap(); 130 .unwrap();
288 }
289 write!(
290 &mut extra,
291 "pub const CORE_INDEX: usize = {};\n",
292 core_index
293 )
294 .unwrap();
295 131
296 // Cleanups! 132 // Cleanups!
297 transform::sort::Sort {}.run(&mut ir).unwrap(); 133 transform::sort::Sort {}.run(&mut ir).unwrap();
298 transform::Sanitize {}.run(&mut ir).unwrap(); 134 transform::Sanitize {}.run(&mut ir).unwrap();
299 135
300 // ============================== 136 // ==============================
301 // Setup chip dir 137 // Setup chip dir
302 138
303 let chip_dir = options 139 let chip_dir = self
304 .out_dir 140 .opts
305 .join("src/chips") 141 .out_dir
306 .join(chip_core_name.to_ascii_lowercase()); 142 .join("src/chips")
307 fs::create_dir_all(&chip_dir).unwrap(); 143 .join(chip_core_name.to_ascii_lowercase());
144 fs::create_dir_all(&chip_dir).unwrap();
308 145
309 // ============================== 146 // ==============================
310 // generate pac.rs 147 // generate pac.rs
311 148
312 let data = generate::render(&ir, &gen_opts()).unwrap().to_string(); 149 let data = generate::render(&ir, &gen_opts()).unwrap().to_string();
313 let data = data.replace("] ", "]\n"); 150 let data = data.replace("] ", "]\n");
314 151
315 // Remove inner attributes like #![no_std] 152 // Remove inner attributes like #![no_std]
316 let data = Regex::new("# *! *\\[.*\\]").unwrap().replace_all(&data, ""); 153 let data = Regex::new("# *! *\\[.*\\]").unwrap().replace_all(&data, "");
317 154
318 let mut file = File::create(chip_dir.join("pac.rs")).unwrap(); 155 let mut file = File::create(chip_dir.join("pac.rs")).unwrap();
319 file.write_all(data.as_bytes()).unwrap(); 156 file.write_all(data.as_bytes()).unwrap();
320 file.write_all(extra.as_bytes()).unwrap(); 157 file.write_all(extra.as_bytes()).unwrap();
321 158
322 let mut device_x = String::new(); 159 let mut device_x = String::new();
323 160
324 for irq in &core.interrupts { 161 for irq in &core.interrupts {
325 write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap(); 162 write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap();
326 } 163 }
327 164
328 // ============================== 165 // ==============================
329 // generate mod.rs 166 // generate metadata.rs
330
331 let mut data = String::new();
332
333 write!(&mut data, "#[cfg(feature=\"metadata\")] pub mod metadata;").unwrap();
334 write!(&mut data, "#[cfg(feature=\"pac\")] mod pac;").unwrap();
335 write!(&mut data, "#[cfg(feature=\"pac\")] pub use pac::*; ").unwrap();
336
337 let peripheral_version_table = peripheral_versions
338 .iter()
339 .map(|(kind, version)| vec![kind.clone(), version.clone()])
340 .collect();
341
342 make_table(&mut data, "pins", &pin_table);
343 make_table(&mut data, "interrupts", &interrupt_table);
344 make_table(&mut data, "peripherals", &peripherals_table);
345 make_table(&mut data, "peripheral_versions", &peripheral_version_table);
346 make_table(&mut data, "dma_channels", &dma_channels_table);
347 make_table(&mut data, "dbgmcu", &dbgmcu_table);
348 make_peripheral_counts(&mut data, &peripheral_counts);
349 make_dma_channel_counts(&mut data, &dma_channel_counts);
350
351 let mut file = File::create(chip_dir.join("mod.rs")).unwrap();
352 file.write_all(data.as_bytes()).unwrap();
353
354 // ==============================
355 // generate metadata.rs
356
357 let metadata = Metadata {
358 name: &chip.name,
359 family: &chip.family,
360 line: &chip.line,
361 memory: &chip.memory,
362 peripherals: &core.peripherals,
363 interrupts: &core.interrupts,
364 dma_channels: &core.dma_channels,
365 };
366 let metadata = format!("{:#?}", metadata);
367 let metadata = metadata.replace("[\n", "&[\n");
368 let metadata = metadata.replace("[],\n", "&[],\n");
369
370 let mut data = String::new();
371 167
372 write!( 168 // (peripherals, interrupts, dma_channels) are often equal across multiple chips.
373 &mut data, 169 // To reduce bloat, deduplicate them.
374 " 170 let mut data = String::new();
375 include!(\"../../metadata.rs\"); 171 write!(
376 use MemoryRegionKind::*; 172 &mut data,
377 pub const METADATA: Metadata = {}; 173 "
378 ", 174 const PERIPHERALS: &'static [Peripheral] = {};
379 metadata 175 const INTERRUPTS: &'static [Interrupt] = {};
380 ) 176 const DMA_CHANNELS: &'static [DmaChannel] = {};
381 .unwrap(); 177 ",
178 stringify(&core.peripherals),
179 stringify(&core.interrupts),
180 stringify(&core.dma_channels),
181 )
182 .unwrap();
382 183
383 let mut file = File::create(chip_dir.join("metadata.rs")).unwrap(); 184 let out_dir = self.opts.out_dir.clone();
384 file.write_all(data.as_bytes()).unwrap(); 185 let n = self.metadata_dedup.len();
186 let deduped_file = self.metadata_dedup.entry(data.clone()).or_insert_with(|| {
187 let file = format!("metadata_{:04}.rs", n);
188 let path = out_dir.join("src/chips").join(&file);
189 fs::write(path, data).unwrap();
385 190
386 // ============================== 191 file
387 // generate device.x 192 });
388 193
389 File::create(chip_dir.join("device.x")) 194 let data = format!(
390 .unwrap() 195 "include!(\"../{}\");
391 .write_all(device_x.as_bytes()) 196 pub const METADATA: Metadata = Metadata {{
392 .unwrap(); 197 name: {:?},
198 family: {:?},
199 line: {:?},
200 memory: {},
201 peripherals: PERIPHERALS,
202 interrupts: INTERRUPTS,
203 dma_channels: DMA_CHANNELS,
204 }};",
205 deduped_file,
206 &chip.name,
207 &chip.family,
208 &chip.line,
209 stringify(&chip.memory),
210 );
393 211
394 // ============================== 212 let mut file = File::create(chip_dir.join("metadata.rs")).unwrap();
395 // generate default memory.x 213 file.write_all(data.as_bytes()).unwrap();
396 gen_memory_x(&chip_dir, &chip);
397}
398 214
399fn load_chip(options: &Options, name: &str) -> Chip { 215 // ==============================
400 let chip_path = options 216 // generate device.x
401 .data_dir
402 .join("chips")
403 .join(&format!("{}.json", name));
404 let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name));
405 serde_yaml::from_slice(&chip).unwrap()
406}
407 217
408fn gen_opts() -> generate::Options { 218 File::create(chip_dir.join("device.x"))
409 generate::Options { 219 .unwrap()
410 common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()), 220 .write_all(device_x.as_bytes())
221 .unwrap();
222
223 // ==============================
224 // generate default memory.x
225 gen_memory_x(&chip_dir, &chip);
411 } 226 }
412}
413 227
414pub fn gen(options: Options) { 228 fn load_chip(&mut self, name: &str) -> Chip {
415 fs::create_dir_all(options.out_dir.join("src/peripherals")).unwrap(); 229 let chip_path = self
416 fs::create_dir_all(options.out_dir.join("src/chips")).unwrap(); 230 .opts
231 .data_dir
232 .join("chips")
233 .join(&format!("{}.json", name));
234 let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name));
235 serde_yaml::from_slice(&chip).unwrap()
236 }
417 237
418 let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new(); 238 pub fn gen(&mut self) {
419 let mut chip_core_names: Vec<String> = Vec::new(); 239 fs::create_dir_all(self.opts.out_dir.join("src/peripherals")).unwrap();
240 fs::create_dir_all(self.opts.out_dir.join("src/chips")).unwrap();
420 241
421 for chip_name in &options.chips { 242 let mut chip_core_names: Vec<String> = Vec::new();
422 println!("Generating {}...", chip_name);
423 243
424 let mut chip = load_chip(&options, chip_name); 244 for chip_name in &self.opts.chips.clone() {
245 println!("Generating {}...", chip_name);
425 246
426 // Cleanup 247 let mut chip = self.load_chip(chip_name);
427 for core in &mut chip.cores { 248
428 for irq in &mut core.interrupts { 249 // Cleanup
429 irq.name = irq.name.to_ascii_uppercase(); 250 for core in &mut chip.cores {
430 } 251 for irq in &mut core.interrupts {
431 for p in &mut core.peripherals { 252 irq.name = irq.name.to_ascii_uppercase();
432 for irq in &mut p.interrupts { 253 }
433 irq.interrupt = irq.interrupt.to_ascii_uppercase(); 254 for p in &mut core.peripherals {
255 for irq in &mut p.interrupts {
256 irq.interrupt = irq.interrupt.to_ascii_uppercase();
257 }
434 } 258 }
435 } 259 }
436 }
437 260
438 // Generate 261 // Generate
439 for (core_index, core) in chip.cores.iter().enumerate() { 262 for (core_index, core) in chip.cores.iter().enumerate() {
440 let chip_core_name = match chip.cores.len() { 263 let chip_core_name = match chip.cores.len() {
441 1 => chip_name.clone(), 264 1 => chip_name.clone(),
442 _ => format!("{}-{}", chip_name, core.name), 265 _ => format!("{}-{}", chip_name, core.name),
443 }; 266 };
444 267
445 chip_core_names.push(chip_core_name.clone()); 268 chip_core_names.push(chip_core_name.clone());
446 gen_chip( 269 self.gen_chip(&chip_core_name, &chip, core, core_index)
447 &options, 270 }
448 &chip_core_name,
449 &chip,
450 core,
451 core_index,
452 &mut all_peripheral_versions,
453 )
454 } 271 }
455 }
456 272
457 for (module, version) in all_peripheral_versions { 273 for (module, version) in &self.all_peripheral_versions {
458 println!("loading {} {}", module, version); 274 println!("loading {} {}", module, version);
459 275
460 let regs_path = Path::new(&options.data_dir) 276 let regs_path = Path::new(&self.opts.data_dir)
461 .join("registers") 277 .join("registers")
462 .join(&format!("{}_{}.yaml", module, version)); 278 .join(&format!("{}_{}.yaml", module, version));
463 279
464 let mut ir: ir::IR = serde_yaml::from_reader(File::open(regs_path).unwrap()).unwrap(); 280 let mut ir: ir::IR = serde_yaml::from_reader(File::open(regs_path).unwrap()).unwrap();
465 281
466 transform::expand_extends::ExpandExtends {} 282 transform::expand_extends::ExpandExtends {}
467 .run(&mut ir) 283 .run(&mut ir)
468 .unwrap(); 284 .unwrap();
469 285
470 transform::map_names(&mut ir, |k, s| match k { 286 transform::map_names(&mut ir, |k, s| match k {
471 transform::NameKind::Block => *s = format!("{}", s), 287 transform::NameKind::Block => *s = format!("{}", s),
472 transform::NameKind::Fieldset => *s = format!("regs::{}", s), 288 transform::NameKind::Fieldset => *s = format!("regs::{}", s),
473 transform::NameKind::Enum => *s = format!("vals::{}", s), 289 transform::NameKind::Enum => *s = format!("vals::{}", s),
474 _ => {} 290 _ => {}
475 }); 291 });
476 292
477 transform::sort::Sort {}.run(&mut ir).unwrap(); 293 transform::sort::Sort {}.run(&mut ir).unwrap();
478 transform::Sanitize {}.run(&mut ir).unwrap(); 294 transform::Sanitize {}.run(&mut ir).unwrap();
479 295
480 let items = generate::render(&ir, &gen_opts()).unwrap(); 296 let items = generate::render(&ir, &gen_opts()).unwrap();
481 let mut file = File::create( 297 let mut file = File::create(
482 options 298 self.opts
483 .out_dir 299 .out_dir
484 .join("src/peripherals") 300 .join("src/peripherals")
485 .join(format!("{}_{}.rs", module, version)), 301 .join(format!("{}_{}.rs", module, version)),
486 ) 302 )
487 .unwrap(); 303 .unwrap();
488 let data = items.to_string().replace("] ", "]\n"); 304 let data = items.to_string().replace("] ", "]\n");
489 305
490 // Remove inner attributes like #![no_std] 306 // Remove inner attributes like #![no_std]
491 let re = Regex::new("# *! *\\[.*\\]").unwrap(); 307 let re = Regex::new("# *! *\\[.*\\]").unwrap();
492 let data = re.replace_all(&data, ""); 308 let data = re.replace_all(&data, "");
493 file.write_all(data.as_bytes()).unwrap(); 309 file.write_all(data.as_bytes()).unwrap();
494 } 310 }
495 311
496 // Generate src/lib_inner.rs 312 // Generate Cargo.toml
497 const PATHS_MARKER: &[u8] = b"// GEN PATHS HERE"; 313 const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES";
498 let librs = include_bytes!("assets/lib_inner.rs"); 314 const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES";
499 let i = bytes_find(librs, PATHS_MARKER).unwrap();
500 let mut paths = String::new();
501 315
502 for name in chip_core_names { 316 let mut contents = include_bytes!("../../stm32-metapac/Cargo.toml").to_vec();
503 let x = name.to_ascii_lowercase(); 317 let begin = bytes_find(&contents, BUILDDEP_BEGIN).unwrap();
504 write!( 318 let end = bytes_find(&contents, BUILDDEP_END).unwrap() + BUILDDEP_END.len();
505 &mut paths, 319 contents.drain(begin..end);
506 "#[cfg_attr(feature=\"{}\", path = \"chips/{}/mod.rs\")]", 320 fs::write(self.opts.out_dir.join("Cargo.toml"), contents).unwrap();
507 x, x 321
322 // copy misc files
323 fs::write(
324 self.opts.out_dir.join("build.rs"),
325 include_bytes!("../../stm32-metapac/build_pregenerated.rs"),
326 )
327 .unwrap();
328 fs::write(
329 self.opts.out_dir.join("src/lib.rs"),
330 include_bytes!("../../stm32-metapac/src/lib.rs"),
331 )
332 .unwrap();
333 fs::write(
334 self.opts.out_dir.join("src/common.rs"),
335 include_bytes!("../../stm32-metapac/src/common.rs"),
336 )
337 .unwrap();
338 fs::write(
339 self.opts.out_dir.join("src/metadata.rs"),
340 include_bytes!("../../stm32-metapac/src/metadata.rs"),
508 ) 341 )
509 .unwrap(); 342 .unwrap();
510 } 343 }
511 let mut contents: Vec<u8> = Vec::new();
512 contents.extend(&librs[..i]);
513 contents.extend(paths.as_bytes());
514 contents.extend(&librs[i + PATHS_MARKER.len()..]);
515 fs::write(options.out_dir.join("src").join("lib_inner.rs"), &contents).unwrap();
516
517 // Generate src/lib.rs
518 const CUT_MARKER: &[u8] = b"// GEN CUT HERE";
519 let librs = include_bytes!("../../stm32-metapac/src/lib.rs");
520 let i = bytes_find(librs, CUT_MARKER).unwrap();
521 let mut contents: Vec<u8> = Vec::new();
522 contents.extend(&librs[..i]);
523 contents.extend(b"include!(\"lib_inner.rs\");\n");
524 fs::write(options.out_dir.join("src").join("lib.rs"), contents).unwrap();
525
526 // Generate src/common.rs
527 fs::write(
528 options.out_dir.join("src").join("common.rs"),
529 generate::COMMON_MODULE,
530 )
531 .unwrap();
532
533 // Generate src/metadata.rs
534 fs::write(
535 options.out_dir.join("src").join("metadata.rs"),
536 include_bytes!("assets/metadata.rs"),
537 )
538 .unwrap();
539
540 // Generate Cargo.toml
541 const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES";
542 const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES";
543
544 let mut contents = include_bytes!("../../stm32-metapac/Cargo.toml").to_vec();
545 let begin = bytes_find(&contents, BUILDDEP_BEGIN).unwrap();
546 let end = bytes_find(&contents, BUILDDEP_END).unwrap() + BUILDDEP_END.len();
547 contents.drain(begin..end);
548 fs::write(options.out_dir.join("Cargo.toml"), contents).unwrap();
549
550 // Generate build.rs
551 fs::write(
552 options.out_dir.join("build.rs"),
553 include_bytes!("assets/build.rs"),
554 )
555 .unwrap();
556} 344}
557 345
558fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { 346fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
@@ -561,6 +349,23 @@ fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
561 .position(|window| window == needle) 349 .position(|window| window == needle)
562} 350}
563 351
352fn stringify<T: Debug>(metadata: T) -> String {
353 let mut metadata = format!("{:?}", metadata);
354 if metadata.starts_with('[') {
355 metadata = format!("&{}", metadata);
356 }
357 metadata = metadata.replace(": [", ": &[");
358 metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram");
359 metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash");
360 metadata
361}
362
363fn gen_opts() -> generate::Options {
364 generate::Options {
365 common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()),
366 }
367}
368
564fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { 369fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) {
565 let mut memory_x = String::new(); 370 let mut memory_x = String::new();
566 371
diff --git a/stm32-metapac-gen/src/main.rs b/stm32-metapac-gen/src/main.rs
index fd1e2a060..391441302 100644
--- a/stm32-metapac-gen/src/main.rs
+++ b/stm32-metapac-gen/src/main.rs
@@ -26,9 +26,10 @@ fn main() {
26 26
27 chips.sort(); 27 chips.sort();
28 28
29 gen(Options { 29 let opts = Options {
30 out_dir, 30 out_dir,
31 data_dir, 31 data_dir,
32 chips, 32 chips,
33 }) 33 };
34 Gen::new(opts).gen();
34} 35}
diff --git a/stm32-metapac/Cargo.toml b/stm32-metapac/Cargo.toml
index 5642af46e..c994797b7 100644
--- a/stm32-metapac/Cargo.toml
+++ b/stm32-metapac/Cargo.toml
@@ -3,6 +3,21 @@ name = "stm32-metapac"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2018" 4edition = "2018"
5resolver = "2" 5resolver = "2"
6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy"
8description = "Peripheral Access Crate (PAC) for all STM32 chips, including metadata."
9
10# `cargo publish` is unable to figure out which .rs files are needed due to the include! magic.
11include = [
12 "**/*.rs",
13 "**/*.x",
14 "Cargo.toml",
15]
16
17[package.metadata.docs.rs]
18features = ["stm32h755zi-cm7", "pac", "metadata"]
19default-target = "thumbv7em-none-eabihf"
20targets = []
6 21
7[dependencies] 22[dependencies]
8cortex-m = "0.7.3" 23cortex-m = "0.7.3"
diff --git a/stm32-metapac/build.rs b/stm32-metapac/build.rs
index 7fd5a6b1f..44c10eced 100644
--- a/stm32-metapac/build.rs
+++ b/stm32-metapac/build.rs
@@ -6,7 +6,7 @@ fn parse_chip_core(chip_and_core: &str) -> (String, Option<String>) {
6 let mut s = chip_and_core.split('-'); 6 let mut s = chip_and_core.split('-');
7 let chip_name: String = s.next().unwrap().to_string(); 7 let chip_name: String = s.next().unwrap().to_string();
8 if let Some(c) = s.next() { 8 if let Some(c) = s.next() {
9 if c.starts_with("CM") { 9 if c.starts_with("cm") {
10 return (chip_name, Some(c.to_ascii_lowercase())); 10 return (chip_name, Some(c.to_ascii_lowercase()));
11 } 11 }
12 } 12 }
@@ -18,36 +18,45 @@ fn main() {
18 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); 18 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
19 let data_dir = PathBuf::from("../stm32-data/data"); 19 let data_dir = PathBuf::from("../stm32-data/data");
20 20
21 println!("cwd: {:?}", env::current_dir());
22
23 let chip_core_name = env::vars_os() 21 let chip_core_name = env::vars_os()
24 .map(|(a, _)| a.to_string_lossy().to_string()) 22 .map(|(a, _)| a.to_string_lossy().to_string())
25 .find(|x| x.starts_with("CARGO_FEATURE_STM32")) 23 .find(|x| x.starts_with("CARGO_FEATURE_STM32"))
26 .expect("No stm32xx Cargo feature enabled") 24 .expect("No stm32xx Cargo feature enabled")
27 .strip_prefix("CARGO_FEATURE_") 25 .strip_prefix("CARGO_FEATURE_")
28 .unwrap() 26 .unwrap()
29 .to_ascii_uppercase() 27 .to_ascii_lowercase()
30 .replace('_', "-"); 28 .replace('_', "-");
31 29
32 let (chip_name, _) = parse_chip_core(&chip_core_name); 30 let (chip_name, _) = parse_chip_core(&chip_core_name);
33 31
34 gen(Options { 32 let opts = Options {
35 out_dir: out_dir.clone(), 33 out_dir: out_dir.clone(),
36 data_dir: data_dir.clone(), 34 data_dir: data_dir.clone(),
37 chips: vec![chip_name], 35 chips: vec![chip_name.to_ascii_uppercase()],
38 }); 36 };
37 Gen::new(opts).gen();
39 38
40 println!( 39 println!(
41 "cargo:rustc-link-search={}/src/chips/{}", 40 "cargo:rustc-link-search={}/src/chips/{}",
42 out_dir.display(), 41 out_dir.display(),
43 chip_core_name.to_ascii_lowercase() 42 chip_core_name,
44 ); 43 );
45 44
46 #[cfg(feature = "memory-x")] 45 #[cfg(feature = "memory-x")]
47 println!( 46 println!(
48 "cargo:rustc-link-search={}/src/chips/{}/memory_x/", 47 "cargo:rustc-link-search={}/src/chips/{}/memory_x/",
49 out_dir.display(), 48 out_dir.display(),
50 chip_core_name.to_ascii_lowercase() 49 chip_core_name
50 );
51 println!(
52 "cargo:rustc-env=STM32_METAPAC_PAC_PATH={}/src/chips/{}/pac.rs",
53 out_dir.display(),
54 chip_core_name
55 );
56 println!(
57 "cargo:rustc-env=STM32_METAPAC_METADATA_PATH={}/src/chips/{}/metadata.rs",
58 out_dir.display(),
59 chip_core_name
51 ); 60 );
52 61
53 println!("cargo:rerun-if-changed=build.rs"); 62 println!("cargo:rerun-if-changed=build.rs");
diff --git a/stm32-metapac-gen/src/assets/build.rs b/stm32-metapac/build_pregenerated.rs
index 14d041ff6..2219acb55 100644
--- a/stm32-metapac-gen/src/assets/build.rs
+++ b/stm32-metapac/build_pregenerated.rs
@@ -23,7 +23,15 @@ fn main() {
23 println!( 23 println!(
24 "cargo:rustc-link-search={}/src/chips/{}/memory_x/", 24 "cargo:rustc-link-search={}/src/chips/{}/memory_x/",
25 crate_dir.display(), 25 crate_dir.display(),
26 chip_core_name, 26 chip_core_name
27 );
28 println!(
29 "cargo:rustc-env=STM32_METAPAC_PAC_PATH=chips/{}/pac.rs",
30 chip_core_name
31 );
32 println!(
33 "cargo:rustc-env=STM32_METAPAC_METADATA_PATH=chips/{}/metadata.rs",
34 chip_core_name
27 ); 35 );
28 36
29 println!("cargo:rerun-if-changed=build.rs"); 37 println!("cargo:rerun-if-changed=build.rs");
diff --git a/stm32-metapac/src/common.rs b/stm32-metapac/src/common.rs
new file mode 100644
index 000000000..568a98486
--- /dev/null
+++ b/stm32-metapac/src/common.rs
@@ -0,0 +1,80 @@
1use core::marker::PhantomData;
2
3#[derive(Copy, Clone, PartialEq, Eq)]
4pub struct RW;
5#[derive(Copy, Clone, PartialEq, Eq)]
6pub struct R;
7#[derive(Copy, Clone, PartialEq, Eq)]
8pub struct W;
9
10mod sealed {
11 use super::*;
12 pub trait Access {}
13 impl Access for R {}
14 impl Access for W {}
15 impl Access for RW {}
16}
17
18pub trait Access: sealed::Access + Copy {}
19impl Access for R {}
20impl Access for W {}
21impl Access for RW {}
22
23pub trait Read: Access {}
24impl Read for RW {}
25impl Read for R {}
26
27pub trait Write: Access {}
28impl Write for RW {}
29impl Write for W {}
30
31#[derive(Copy, Clone, PartialEq, Eq)]
32pub struct Reg<T: Copy, A: Access> {
33 ptr: *mut u8,
34 phantom: PhantomData<*mut (T, A)>,
35}
36unsafe impl<T: Copy, A: Access> Send for Reg<T, A> {}
37unsafe impl<T: Copy, A: Access> Sync for Reg<T, A> {}
38
39impl<T: Copy, A: Access> Reg<T, A> {
40 pub fn from_ptr(ptr: *mut u8) -> Self {
41 Self {
42 ptr,
43 phantom: PhantomData,
44 }
45 }
46
47 pub fn ptr(&self) -> *mut T {
48 self.ptr as _
49 }
50}
51
52impl<T: Copy, A: Read> Reg<T, A> {
53 pub unsafe fn read(&self) -> T {
54 (self.ptr as *mut T).read_volatile()
55 }
56}
57
58impl<T: Copy, A: Write> Reg<T, A> {
59 pub unsafe fn write_value(&self, val: T) {
60 (self.ptr as *mut T).write_volatile(val)
61 }
62}
63
64impl<T: Default + Copy, A: Write> Reg<T, A> {
65 pub unsafe fn write<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
66 let mut val = Default::default();
67 let res = f(&mut val);
68 self.write_value(val);
69 res
70 }
71}
72
73impl<T: Copy, A: Read + Write> Reg<T, A> {
74 pub unsafe fn modify<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
75 let mut val = self.read();
76 let res = f(&mut val);
77 self.write_value(val);
78 res
79 }
80}
diff --git a/stm32-metapac/src/lib.rs b/stm32-metapac/src/lib.rs
index 5dd2682fb..9cdc5e0b4 100644
--- a/stm32-metapac/src/lib.rs
+++ b/stm32-metapac/src/lib.rs
@@ -3,5 +3,13 @@
3#![allow(unused)] 3#![allow(unused)]
4#![allow(non_camel_case_types)] 4#![allow(non_camel_case_types)]
5 5
6// GEN CUT HERE 6pub mod common;
7include!(concat!(env!("OUT_DIR"), "/src/lib_inner.rs")); 7
8#[cfg(feature = "pac")]
9include!(env!("STM32_METAPAC_PAC_PATH"));
10
11#[cfg(feature = "metadata")]
12pub mod metadata {
13 include!("metadata.rs");
14 include!(env!("STM32_METAPAC_METADATA_PATH"));
15}
diff --git a/stm32-metapac-gen/src/assets/metadata.rs b/stm32-metapac/src/metadata.rs
index 150aa5956..150aa5956 100644
--- a/stm32-metapac-gen/src/assets/metadata.rs
+++ b/stm32-metapac/src/metadata.rs