diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-02-26 02:42:26 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-02-26 02:42:26 +0000 |
| commit | 141e007acf5f3c91a9cbd13196c32867bfddd78d (patch) | |
| tree | 52c3c3ca05e2960ffb21e6e02ae969f58e003027 | |
| parent | d381b8e2b613dac5a8b6c80033e81fabc4a8632d (diff) | |
| parent | 451bb48464fe685d26606d4f050a7972dc093c64 (diff) | |
Merge #646
646: Debloat stm32-metapac r=Dirbaio a=Dirbaio
- Remove usage of `peripheral_counts!` macrotables.
- Remove `dbgmcu!` macrotable.
- Move the remaining macrotables to embassy-stm32 build.rs. This brings metapac decompressed size from ~250mb to ~100mb
- Deduplicate files with identical metadata. This brings decompressed size from ~100mb to ~70mb, compressed from ~10mb to ~4mb, which is finally small enough to publish on crates.io!
Co-authored-by: Dario Nieuwenhuis <[email protected]>
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; | |||
| 2 | use quote::{format_ident, quote}; | 2 | use quote::{format_ident, quote}; |
| 3 | use std::collections::{HashMap, HashSet}; | 3 | use std::collections::{HashMap, HashSet}; |
| 4 | use std::env; | 4 | use std::env; |
| 5 | use std::fmt::Write as _; | ||
| 5 | use std::fs; | 6 | use std::fs; |
| 6 | use std::path::PathBuf; | 7 | use std::path::PathBuf; |
| 7 | use stm32_metapac::metadata::METADATA; | 8 | use 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 | |||
| 767 | fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { | ||
| 768 | write!( | ||
| 769 | out, | ||
| 770 | "#[macro_export] | ||
| 771 | macro_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 {} | |||
| 36 | pub trait Common: sealed::Common + 'static {} | 36 | pub trait Common: sealed::Common + 'static {} |
| 37 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 37 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} |
| 38 | 38 | ||
| 39 | crate::pac::peripherals!( | 39 | foreach_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))] |
| 60 | crate::pac::peripherals!( | 60 | foreach_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 | ||
| 71 | pub trait Instance: sealed::Instance + RccPeripheral {} | 71 | pub trait Instance: sealed::Instance + RccPeripheral {} |
| 72 | 72 | ||
| 73 | crate::pac::peripherals!( | 73 | foreach_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 | ||
| 89 | crate::pac::peripherals!( | 89 | foreach_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 | ||
| 17 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} | 17 | pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {} |
| 18 | 18 | ||
| 19 | crate::pac::peripherals!( | 19 | foreach_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 | ||
| 477 | crate::pac::interrupts! { | 477 | foreach_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}; | |||
| 7 | use embassy::waitqueue::AtomicWaker; | 7 | use embassy::waitqueue::AtomicWaker; |
| 8 | 8 | ||
| 9 | use crate::dma::Request; | 9 | use crate::dma::Request; |
| 10 | use crate::generated::BDMA_CHANNEL_COUNT; | ||
| 10 | use crate::pac; | 11 | use crate::pac; |
| 11 | use crate::pac::bdma::vals; | 12 | use crate::pac::bdma::vals; |
| 12 | 13 | ||
| @@ -22,62 +23,44 @@ impl From<WordSize> for vals::Size { | |||
| 22 | } | 23 | } |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; | ||
| 26 | |||
| 27 | struct State { | 26 | struct State { |
| 28 | ch_wakers: [AtomicWaker; CH_COUNT], | 27 | ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT], |
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | impl State { | 30 | impl 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 | ||
| 40 | static STATE: State = State::new(); | 39 | static STATE: State = State::new(); |
| 41 | 40 | ||
| 42 | macro_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 | |||
| 60 | pub(crate) unsafe fn on_irq() { | 41 | pub(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 |
| 79 | pub(crate) unsafe fn init() { | 62 | pub(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 | ||
| 88 | pac::dma_channels! { | 71 | foreach_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; | |||
| 4 | use embassy::interrupt::{Interrupt, InterruptExt}; | 4 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 5 | use embassy::waitqueue::AtomicWaker; | 5 | use embassy::waitqueue::AtomicWaker; |
| 6 | 6 | ||
| 7 | use crate::generated::DMA_CHANNEL_COUNT; | ||
| 7 | use crate::interrupt; | 8 | use crate::interrupt; |
| 8 | use crate::pac; | 9 | use crate::pac; |
| 9 | use crate::pac::dma::{regs, vals}; | 10 | use crate::pac::dma::{regs, vals}; |
| 10 | 11 | ||
| 11 | use super::{Request, Word, WordSize}; | 12 | use super::{Request, Word, WordSize}; |
| 12 | 13 | ||
| 13 | const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8; | ||
| 14 | |||
| 15 | impl From<WordSize> for vals::Size { | 14 | impl 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 | ||
| 25 | struct State { | 24 | struct State { |
| 26 | ch_wakers: [AtomicWaker; CH_COUNT], | 25 | ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT], |
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | impl State { | 28 | impl 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 | ||
| 38 | static STATE: State = State::new(); | 37 | static STATE: State = State::new(); |
| 39 | 38 | ||
| 40 | macro_rules! dma_num { | ||
| 41 | (DMA1) => { | ||
| 42 | 0 | ||
| 43 | }; | ||
| 44 | (DMA2) => { | ||
| 45 | 1 | ||
| 46 | }; | ||
| 47 | } | ||
| 48 | |||
| 49 | pub(crate) unsafe fn on_irq() { | 39 | pub(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 |
| 70 | pub(crate) unsafe fn init() { | 56 | pub(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 | ||
| 79 | pac::dma_channels! { | 65 | foreach_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 | ||
| 38 | pac::dma_channels! { | 38 | foreach_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 | ||
| 279 | macro_rules! foreach_exti_irq { | 279 | macro_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 | ||
| 130 | crate::pac::peripherals!( | 130 | foreach_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 | ||
| 561 | crate::pac::pins!( | 561 | foreach_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 | ||
| 23 | pub(crate) mod sealed { | 23 | pub(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); | |||
| 36 | dma_trait!(RxDma, Instance); | 37 | dma_trait!(RxDma, Instance); |
| 37 | dma_trait!(TxDma, Instance); | 38 | dma_trait!(TxDma, Instance); |
| 38 | 39 | ||
| 39 | macro_rules! i2c_state { | 40 | foreach_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 | |||
| 57 | crate::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}; | |||
| 7 | use crate::pac::i2c; | 7 | use crate::pac::i2c; |
| 8 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 9 | 9 | ||
| 10 | pub struct State {} | ||
| 11 | |||
| 12 | impl State { | ||
| 13 | pub(crate) const fn new() -> Self { | ||
| 14 | Self {} | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 10 | pub struct I2c<'d, T: Instance> { | 18 | pub 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; | |||
| 13 | use crate::dma::NoDma; | 13 | use crate::dma::NoDma; |
| 14 | use crate::gpio::sealed::AFType; | 14 | use crate::gpio::sealed::AFType; |
| 15 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 15 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| 16 | use crate::pac; | ||
| 17 | use crate::pac::i2c; | 16 | use crate::pac::i2c; |
| 18 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 19 | 18 | ||
| 20 | const I2C_COUNT: usize = pac::peripheral_count!(i2c); | ||
| 21 | |||
| 22 | pub struct State { | 19 | pub struct State { |
| 23 | waker: [AtomicWaker; I2C_COUNT], | 20 | waker: AtomicWaker, |
| 24 | chunks_transferred: [AtomicUsize; I2C_COUNT], | 21 | chunks_transferred: AtomicUsize, |
| 25 | } | 22 | } |
| 26 | 23 | ||
| 27 | impl State { | 24 | impl 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 | ||
| 39 | static STATE: State = State::new(); | ||
| 40 | |||
| 41 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | 33 | pub 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. |
| 13 | pub mod fmt; | 13 | pub mod fmt; |
| 14 | include!(concat!(env!("OUT_DIR"), "/macros.rs")); | ||
| 14 | 15 | ||
| 15 | // Utilities | 16 | // Utilities |
| 16 | pub mod interrupt; | 17 | pub mod interrupt; |
| @@ -62,7 +63,7 @@ pub mod usb_otg; | |||
| 62 | pub mod subghz; | 63 | pub 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. |
| 65 | mod generated { | 66 | pub(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 | ||
| 130 | crate::pac::interrupts! { | 130 | foreach_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 | ||
| 137 | pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral {} | 137 | pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral {} |
| 138 | 138 | ||
| 139 | crate::pac::peripherals!( | 139 | foreach_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 | ||
| 168 | crate::pac::interrupts!( | 168 | foreach_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 | ||
| 1274 | crate::pac::peripherals!( | 1274 | foreach_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); | |||
| 874 | dma_trait!(RxDma, Instance); | 874 | dma_trait!(RxDma, Instance); |
| 875 | dma_trait!(TxDma, Instance); | 875 | dma_trait!(TxDma, Instance); |
| 876 | 876 | ||
| 877 | crate::pac::peripherals!( | 877 | foreach_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)] |
| 30 | type T = peripherals::TIM5; | 30 | type T = peripherals::TIM5; |
| 31 | 31 | ||
| 32 | crate::pac::interrupts! { | 32 | foreach_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 | ||
| 158 | crate::pac::interrupts! { | 158 | foreach_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); | |||
| 601 | dma_trait!(TxDma, Instance); | 601 | dma_trait!(TxDma, Instance); |
| 602 | dma_trait!(RxDma, Instance); | 602 | dma_trait!(RxDma, Instance); |
| 603 | 603 | ||
| 604 | crate::pac::interrupts!( | 604 | foreach_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); | |||
| 135 | pin_trait!(UlpiD6Pin, Instance); | 135 | pin_trait!(UlpiD6Pin, Instance); |
| 136 | pin_trait!(UlpiD7Pin, Instance); | 136 | pin_trait!(UlpiD7Pin, Instance); |
| 137 | 137 | ||
| 138 | crate::pac::peripherals!( | 138 | foreach_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 | ||
| 226 | crate::pac::interrupts!( | 226 | foreach_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 | ||
| 2 | mod inner; | ||
| 3 | |||
| 4 | pub mod common; | ||
| 5 | |||
| 6 | pub 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 @@ | |||
| 1 | use chiptool::generate::CommonModule; | 1 | use chiptool::generate::CommonModule; |
| 2 | use chiptool::{generate, ir, transform}; | ||
| 2 | use proc_macro2::TokenStream; | 3 | use proc_macro2::TokenStream; |
| 3 | use regex::Regex; | 4 | use regex::Regex; |
| 4 | use std::collections::{BTreeMap, HashMap, HashSet}; | 5 | use std::collections::{BTreeMap, HashMap, HashSet}; |
| 5 | use std::fmt::Write as _; | 6 | use std::fmt::{Debug, Write as _}; |
| 6 | use std::fs; | 7 | use std::fs; |
| 7 | use std::fs::File; | 8 | use std::fs::File; |
| 8 | use std::io::Write; | 9 | use std::io::Write; |
| @@ -10,9 +11,6 @@ use std::path::Path; | |||
| 10 | use std::path::PathBuf; | 11 | use std::path::PathBuf; |
| 11 | use std::str::FromStr; | 12 | use std::str::FromStr; |
| 12 | 13 | ||
| 13 | use chiptool::util::ToSanitizedSnakeCase; | ||
| 14 | use chiptool::{generate, ir, transform}; | ||
| 15 | |||
| 16 | mod data; | 14 | mod data; |
| 17 | use data::*; | 15 | use data::*; |
| 18 | 16 | ||
| @@ -27,532 +25,322 @@ struct Metadata<'a> { | |||
| 27 | dma_channels: &'a [DmaChannel], | 25 | dma_channels: &'a [DmaChannel], |
| 28 | } | 26 | } |
| 29 | 27 | ||
| 30 | fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) { | ||
| 31 | write!( | ||
| 32 | out, | ||
| 33 | "#[macro_export] | ||
| 34 | macro_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 | |||
| 44 | fn 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] | ||
| 51 | macro_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 | |||
| 61 | fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { | ||
| 62 | write!( | ||
| 63 | out, | ||
| 64 | "#[macro_export] | ||
| 65 | macro_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 | |||
| 88 | pub struct Options { | 28 | pub 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 | ||
| 94 | pub fn gen_chip( | 34 | pub 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)>, | 40 | impl 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 | ||
| 399 | fn 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 | ||
| 408 | fn 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 | ||
| 414 | pub 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 | ||
| 558 | fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { | 346 | fn 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 | ||
| 352 | fn 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 | |||
| 363 | fn gen_opts() -> generate::Options { | ||
| 364 | generate::Options { | ||
| 365 | common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()), | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 564 | fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { | 369 | fn 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" | |||
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2018" | 4 | edition = "2018" |
| 5 | resolver = "2" | 5 | resolver = "2" |
| 6 | license = "MIT OR Apache-2.0" | ||
| 7 | repository = "https://github.com/embassy-rs/embassy" | ||
| 8 | description = "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. | ||
| 11 | include = [ | ||
| 12 | "**/*.rs", | ||
| 13 | "**/*.x", | ||
| 14 | "Cargo.toml", | ||
| 15 | ] | ||
| 16 | |||
| 17 | [package.metadata.docs.rs] | ||
| 18 | features = ["stm32h755zi-cm7", "pac", "metadata"] | ||
| 19 | default-target = "thumbv7em-none-eabihf" | ||
| 20 | targets = [] | ||
| 6 | 21 | ||
| 7 | [dependencies] | 22 | [dependencies] |
| 8 | cortex-m = "0.7.3" | 23 | cortex-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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 4 | pub struct RW; | ||
| 5 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 6 | pub struct R; | ||
| 7 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 8 | pub struct W; | ||
| 9 | |||
| 10 | mod 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 | |||
| 18 | pub trait Access: sealed::Access + Copy {} | ||
| 19 | impl Access for R {} | ||
| 20 | impl Access for W {} | ||
| 21 | impl Access for RW {} | ||
| 22 | |||
| 23 | pub trait Read: Access {} | ||
| 24 | impl Read for RW {} | ||
| 25 | impl Read for R {} | ||
| 26 | |||
| 27 | pub trait Write: Access {} | ||
| 28 | impl Write for RW {} | ||
| 29 | impl Write for W {} | ||
| 30 | |||
| 31 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 32 | pub struct Reg<T: Copy, A: Access> { | ||
| 33 | ptr: *mut u8, | ||
| 34 | phantom: PhantomData<*mut (T, A)>, | ||
| 35 | } | ||
| 36 | unsafe impl<T: Copy, A: Access> Send for Reg<T, A> {} | ||
| 37 | unsafe impl<T: Copy, A: Access> Sync for Reg<T, A> {} | ||
| 38 | |||
| 39 | impl<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 | |||
| 52 | impl<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 | |||
| 58 | impl<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 | |||
| 64 | impl<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 | |||
| 73 | impl<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 | 6 | pub mod common; |
| 7 | include!(concat!(env!("OUT_DIR"), "/src/lib_inner.rs")); | 7 | |
| 8 | #[cfg(feature = "pac")] | ||
| 9 | include!(env!("STM32_METAPAC_PAC_PATH")); | ||
| 10 | |||
| 11 | #[cfg(feature = "metadata")] | ||
| 12 | pub 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 | |||
