1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
4#![cfg_attr(
5 docsrs,
6 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n"
7)]
8#![doc = include_str!("../README.md")]
9#![warn(missing_docs)]
10
11#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
13
14mod fmt;
16include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
17
18mod macros;
20pub mod time;
21pub mod mode {
23 trait SealedMode {}
24
25 #[allow(private_bounds)]
27 pub trait Mode: SealedMode {}
28
29 macro_rules! impl_mode {
30 ($name:ident) => {
31 impl SealedMode for $name {}
32 impl Mode for $name {}
33 };
34 }
35
36 pub struct Blocking;
38 pub struct Async;
40
41 impl_mode!(Blocking);
42 impl_mode!(Async);
43}
44
45pub mod dma;
47pub mod gpio;
48pub mod rcc;
49#[cfg(feature = "_time-driver")]
50mod time_driver;
51pub mod timer;
52
53#[cfg(adc)]
56pub mod adc;
57#[cfg(aes_v3b)]
58pub mod aes;
59#[cfg(backup_sram)]
60pub mod backup_sram;
61#[cfg(can)]
62pub mod can;
63#[cfg(any(comp_u5, comp_v2))]
64pub mod comp;
65#[cfg(cordic)]
66pub mod cordic;
67
68#[cfg(all(comp, not(any(comp_u5, comp_v2))))]
72#[allow(unused_macros)]
73macro_rules! impl_comp_inp_pin {
74 ($inst:ident, $pin:ident, $ch:expr) => {};
75}
76#[cfg(all(comp, not(any(comp_u5, comp_v2))))]
77#[allow(unused_macros)]
78macro_rules! impl_comp_inm_pin {
79 ($inst:ident, $pin:ident, $ch:expr) => {};
80}
81#[cfg(any(ipcc, hsem))]
82pub mod cpu;
83#[cfg(crc)]
84pub mod crc;
85#[cfg(cryp)]
86pub mod cryp;
87#[cfg(dac)]
88pub mod dac;
89#[cfg(dcmi)]
90pub mod dcmi;
91#[cfg(dsihost)]
92pub mod dsihost;
93#[cfg(dts)]
94pub mod dts;
95#[cfg(eth)]
96pub mod eth;
97#[cfg(feature = "exti")]
98pub mod exti;
99#[cfg(flash)]
100pub mod flash;
101#[cfg(fmc)]
102pub mod fmc;
103#[cfg(hash)]
104pub mod hash;
105#[cfg(all(hrtim, feature = "stm32-hrtim"))]
106pub mod hrtim;
107#[cfg(hsem)]
108pub mod hsem;
109#[cfg(hspi)]
110pub mod hspi;
111#[cfg(i2c)]
112pub mod i2c;
113#[cfg(any(spi_v1_i2s, spi_v2_i2s, spi_v3_i2s, spi_v4_i2s, spi_v5_i2s))]
114pub mod i2s;
115#[cfg(any(stm32wb, stm32wl5x))]
116pub mod ipcc;
117#[cfg(lcd)]
118pub mod lcd;
119#[cfg(feature = "low-power")]
120pub mod low_power;
121#[cfg(lptim)]
122pub mod lptim;
123#[cfg(ltdc)]
124pub mod ltdc;
125#[cfg(opamp)]
126pub mod opamp;
127#[cfg(octospi)]
128pub mod ospi;
129#[cfg(pka_v1a)]
130pub mod pka;
131#[cfg(quadspi)]
132pub mod qspi;
133#[cfg(rng)]
134pub mod rng;
135#[cfg(all(rtc, not(rtc_v1)))]
136pub mod rtc;
137#[cfg(saes_v1a)]
138pub mod saes;
139#[cfg(sai)]
140pub mod sai;
141#[cfg(sdmmc)]
142pub mod sdmmc;
143#[cfg(spdifrx)]
144pub mod spdifrx;
145#[cfg(spi)]
146pub mod spi;
147#[cfg(tsc)]
148pub mod tsc;
149#[cfg(ucpd)]
150pub mod ucpd;
151#[cfg(uid)]
152pub mod uid;
153#[cfg(usart)]
154pub mod usart;
155#[cfg(any(usb, otg))]
156pub mod usb;
157#[cfg(vrefbuf)]
158pub mod vrefbuf;
159#[cfg(iwdg)]
160pub mod wdg;
161#[cfg(xspi)]
162pub mod xspi;
163
164#[cfg(feature = "_executor")]
165pub mod executor;
166
167pub(crate) mod _generated {
169 #![allow(dead_code)]
170 #![allow(unused_imports)]
171 #![allow(non_snake_case)]
172 #![allow(missing_docs)]
173
174 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
175}
176
177pub use crate::_generated::{interrupt, triggers};
178
179#[macro_export]
215macro_rules! bind_interrupts {
216 ($(#[$outer:meta])* $vis:vis struct $name:ident {
217 $(
218 $(#[doc = $doc:literal])*
219 $(#[cfg($cond_irq:meta)])?
220 $irq:ident => $(
221 $(#[cfg($cond_handler:meta)])?
222 $handler:ty
223 ),*;
224 )*
225 }) => {
226 #[derive(Copy, Clone)]
227 $(#[$outer])*
228 $vis struct $name;
229
230 $(
231 #[allow(non_snake_case)]
232 #[unsafe(no_mangle)]
233 $(#[cfg($cond_irq)])?
234 $(#[doc = $doc])*
235 unsafe extern "C" fn $irq() {
236 unsafe {
237 $(
238 $(#[cfg($cond_handler)])?
239 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
240
241 )*
242 }
243 }
244
245 $(#[cfg($cond_irq)])?
246 $crate::bind_interrupts!(@inner
247 $(
248 $(#[cfg($cond_handler)])?
249 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
250 )*
251 );
252 )*
253 };
254 (@inner $($t:tt)*) => {
255 $($t)*
256 }
257}
258
259pub use _generated::{Peripherals, peripherals};
261pub use embassy_hal_internal::{Peri, PeripheralType};
262#[cfg(feature = "unstable-pac")]
263pub use stm32_metapac as pac;
264#[cfg(not(feature = "unstable-pac"))]
265pub(crate) use stm32_metapac as pac;
266
267use crate::interrupt::Priority;
268#[cfg(feature = "rt")]
269pub use crate::pac::NVIC_PRIO_BITS;
270
271#[non_exhaustive]
273#[derive(Clone, Copy)]
274pub struct Config {
275 pub rcc: rcc::Config,
277
278 #[cfg(feature = "low-power")]
279 pub rtc: rtc::RtcConfig,
281
282 #[cfg(feature = "low-power")]
283 pub min_stop_pause: embassy_time::Duration,
285
286 #[cfg(dbgmcu)]
290 pub enable_debug_during_sleep: bool,
291
292 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u3, stm32wba))]
298 pub enable_independent_io_supply: bool,
299
300 #[cfg(any(stm32u5, stm32u3))]
302 pub enable_independent_analog_supply: bool,
303
304 #[cfg(bdma)]
308 pub bdma_interrupt_priority: Priority,
309
310 #[cfg(dma)]
314 pub dma_interrupt_priority: Priority,
315
316 #[cfg(gpdma)]
320 pub gpdma_interrupt_priority: Priority,
321
322 #[cfg(mdma)]
326 pub mdma_interrupt_priority: Priority,
327
328 #[cfg(peri_ucpd1)]
332 pub enable_ucpd1_dead_battery: bool,
333
334 #[cfg(peri_ucpd2)]
338 pub enable_ucpd2_dead_battery: bool,
339
340 #[cfg(stm32f1)]
342 pub swj: gpio::SwjCfg,
343}
344
345impl Default for Config {
346 fn default() -> Self {
347 Self {
348 rcc: Default::default(),
349 #[cfg(feature = "low-power")]
350 rtc: Default::default(),
351 #[cfg(feature = "low-power")]
352 min_stop_pause: embassy_time::Duration::from_millis(250),
353 #[cfg(dbgmcu)]
354 enable_debug_during_sleep: true,
355 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u3, stm32wba))]
356 enable_independent_io_supply: true,
357 #[cfg(any(stm32u5, stm32u3))]
358 enable_independent_analog_supply: true,
359 #[cfg(bdma)]
360 bdma_interrupt_priority: Priority::P0,
361 #[cfg(dma)]
362 dma_interrupt_priority: Priority::P0,
363 #[cfg(gpdma)]
364 gpdma_interrupt_priority: Priority::P0,
365 #[cfg(mdma)]
366 mdma_interrupt_priority: Priority::P0,
367 #[cfg(peri_ucpd1)]
368 enable_ucpd1_dead_battery: false,
369 #[cfg(peri_ucpd2)]
370 enable_ucpd2_dead_battery: false,
371 #[cfg(stm32f1)]
372 swj: Default::default(),
373 }
374 }
375}
376
377#[cfg(not(feature = "_dual-core"))]
383pub fn init(config: Config) -> Peripherals {
384 init_hw(config)
385}
386
387#[cfg(feature = "_dual-core")]
388mod dual_core {
389 use core::cell::UnsafeCell;
390 use core::mem::MaybeUninit;
391 use core::sync::atomic::{AtomicUsize, Ordering};
392
393 use rcc::Clocks;
394
395 use super::*;
396
397 #[repr(C)]
413 pub struct SharedData {
414 init_flag: AtomicUsize,
415 clocks: UnsafeCell<MaybeUninit<Clocks>>,
416 config: UnsafeCell<MaybeUninit<SharedConfig>>,
417 #[cfg(feature = "low-power")]
418 rcc_config: UnsafeCell<MaybeUninit<Option<rcc::Config>>>,
419 }
420
421 unsafe impl Sync for SharedData {}
422
423 const INIT_DONE_FLAG: usize = 0xca11ab1e;
424
425 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
436 let shared_data = unsafe { shared_data.assume_init_ref() };
437
438 shared_data.init_flag.store(0, Ordering::SeqCst);
442
443 rcc::set_freqs_ptr(shared_data.clocks.get());
444 #[cfg(feature = "low-power")]
445 rcc::set_rcc_config_ptr(shared_data.rcc_config.get());
446 let p = init_hw(config);
447
448 unsafe { *shared_data.config.get() }.write(config.into());
449
450 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
451
452 p
453 }
454
455 pub fn try_init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Option<Peripherals> {
465 let shared_data = unsafe { shared_data.assume_init_ref() };
466
467 if shared_data.init_flag.load(Ordering::SeqCst) != INIT_DONE_FLAG {
468 return None;
469 }
470
471 shared_data.init_flag.store(0, Ordering::SeqCst);
473
474 Some(init_secondary_hw(shared_data))
475 }
476
477 pub fn init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
487 loop {
488 if let Some(p) = try_init_secondary(shared_data) {
489 return p;
490 }
491 }
492 }
493
494 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
495 rcc::set_freqs_ptr(shared_data.clocks.get());
496 #[cfg(feature = "low-power")]
497 rcc::set_rcc_config_ptr(shared_data.rcc_config.get());
498
499 let config = unsafe { (*shared_data.config.get()).assume_init() };
500
501 critical_section::with(|cs| {
503 unsafe {
504 dma::init(
505 cs,
506 #[cfg(bdma)]
507 config.bdma_interrupt_priority,
508 #[cfg(dma)]
509 config.dma_interrupt_priority,
510 #[cfg(gpdma)]
511 config.gpdma_interrupt_priority,
512 #[cfg(mdma)]
513 config.mdma_interrupt_priority,
514 )
515 }
516
517 #[cfg(feature = "_time-driver")]
518 time_driver::init(cs);
520 });
521
522 Peripherals::take()
523 }
524
525 #[repr(C)]
526 #[derive(Clone, Copy)]
527 struct SharedConfig {
528 #[cfg(bdma)]
529 bdma_interrupt_priority: Priority,
530 #[cfg(dma)]
531 dma_interrupt_priority: Priority,
532 #[cfg(gpdma)]
533 gpdma_interrupt_priority: Priority,
534 #[cfg(mdma)]
535 mdma_interrupt_priority: Priority,
536 }
537
538 impl From<Config> for SharedConfig {
539 fn from(value: Config) -> Self {
540 let Config {
541 #[cfg(bdma)]
542 bdma_interrupt_priority,
543 #[cfg(dma)]
544 dma_interrupt_priority,
545 #[cfg(gpdma)]
546 gpdma_interrupt_priority,
547 #[cfg(mdma)]
548 mdma_interrupt_priority,
549 ..
550 } = value;
551
552 SharedConfig {
553 #[cfg(bdma)]
554 bdma_interrupt_priority,
555 #[cfg(dma)]
556 dma_interrupt_priority,
557 #[cfg(gpdma)]
558 gpdma_interrupt_priority,
559 #[cfg(mdma)]
560 mdma_interrupt_priority,
561 }
562 }
563 }
564}
565
566#[cfg(feature = "_dual-core")]
567pub use dual_core::*;
568
569fn init_hw(config: Config) -> Peripherals {
570 critical_section::with(|cs| {
571 let p = Peripherals::take_with_cs(cs);
572
573 #[cfg(dbgmcu_n6)]
574 {
575 crate::pac::RCC.miscensr().write(|w| w.set_dbgens(true));
576 crate::pac::RCC.miscenr().read(); crate::pac::DBGMCU
578 .cr()
579 .modify(|w| w.set_dbgclken(stm32_metapac::dbgmcu::vals::Dbgclken::B_0X1));
580 crate::pac::DBGMCU.cr().read();
581 }
582
583 #[cfg(dbgmcu)]
584 crate::pac::DBGMCU.cr().modify(|cr| {
585 #[cfg(dbgmcu_h5)]
586 {
587 cr.set_stop(config.enable_debug_during_sleep);
588 cr.set_standby(config.enable_debug_during_sleep);
589 }
590 #[cfg(any(
591 dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u3, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5
592 ))]
593 {
594 cr.set_dbg_stop(config.enable_debug_during_sleep);
595 cr.set_dbg_standby(config.enable_debug_during_sleep);
596 }
597 #[cfg(any(
598 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
599 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6
600 ))]
601 {
602 cr.set_dbg_sleep(config.enable_debug_during_sleep);
603 cr.set_dbg_stop(config.enable_debug_during_sleep);
604 cr.set_dbg_standby(config.enable_debug_during_sleep);
605 }
606 #[cfg(dbgmcu_h7)]
607 {
608 cr.set_d1dbgcken(config.enable_debug_during_sleep);
609 cr.set_d3dbgcken(config.enable_debug_during_sleep);
610 cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
611 cr.set_dbgstby_d1(config.enable_debug_during_sleep);
612 cr.set_dbgstop_d1(config.enable_debug_during_sleep);
613 }
614 });
615
616 #[cfg(any(stm32h7rs))]
617 rcc::enable_with_cs::<peripherals::SYSCFG>(cs);
619 #[cfg(not(any(stm32f1, stm32wb, stm32wl, stm32h7rs)))]
620 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
621 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
622 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
623 #[cfg(all(flash, not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))))]
624 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
625
626 #[cfg(any(stm32l4, stm32l5))]
629 {
630 crate::pac::PWR.cr2().modify(|w| {
631 w.set_iosv(config.enable_independent_io_supply);
635 });
636 }
637 #[cfg(stm32wba)]
638 {
639 use crate::pac::pwr::vals;
640 crate::pac::PWR.svmcr().modify(|w| {
641 w.set_io2sv(if config.enable_independent_io_supply {
642 vals::Io2sv::B_0X1
643 } else {
644 vals::Io2sv::B_0X0
645 });
646 });
647 }
648 #[cfg(any(stm32u5, stm32u3))]
649 {
650 crate::pac::PWR.svmcr().modify(|w| {
651 w.set_io2sv(config.enable_independent_io_supply);
652 });
653 if config.enable_independent_analog_supply {
654 crate::pac::PWR.svmcr().modify(|w| {
655 w.set_avm1en(true);
656 });
657 while !crate::pac::PWR.svmsr().read().vdda1rdy() {}
658 crate::pac::PWR.svmcr().modify(|w| {
659 w.set_asv(true);
660 });
661 } else {
662 crate::pac::PWR.svmcr().modify(|w| {
663 w.set_avm1en(false);
664 w.set_avm2en(false);
665 });
666 }
667 }
668
669 #[cfg(any(stm32g070, stm32g0b0))]
672 {
673 crate::pac::SYSCFG.cfgr1().modify(|w| {
674 w.set_ucpd1_strobe(true);
675 w.set_ucpd2_strobe(true);
676 });
677 }
678
679 unsafe {
680 #[cfg(ucpd)]
681 ucpd::init(
682 cs,
683 #[cfg(all(peri_ucpd1, not(stm32n6)))]
684 config.enable_ucpd1_dead_battery,
685 #[cfg(peri_ucpd2)]
686 config.enable_ucpd2_dead_battery,
687 );
688
689 #[cfg(feature = "_split-pins-enabled")]
690 crate::pac::SYSCFG.pmcr().modify(|pmcr| {
691 #[cfg(feature = "split-pa0")]
692 pmcr.set_pa0so(true);
693 #[cfg(feature = "split-pa1")]
694 pmcr.set_pa1so(true);
695 #[cfg(feature = "split-pc2")]
696 pmcr.set_pc2so(true);
697 #[cfg(feature = "split-pc3")]
698 pmcr.set_pc3so(true);
699 });
700
701 gpio::init(cs);
702
703 #[cfg(stm32f1)]
704 crate::pac::AFIO.mapr().modify(|w| w.set_swj_cfg(config.swj.into()));
705
706 dma::init(
707 cs,
708 #[cfg(bdma)]
709 config.bdma_interrupt_priority,
710 #[cfg(dma)]
711 config.dma_interrupt_priority,
712 #[cfg(gpdma)]
713 config.gpdma_interrupt_priority,
714 #[cfg(mdma)]
715 config.mdma_interrupt_priority,
716 );
717 #[cfg(feature = "exti")]
718 exti::init(cs);
719
720 rcc::init_rcc(cs, config.rcc);
721
722 #[cfg(all(any(stm32wb, stm32wl5x), feature = "low-power"))]
724 hsem::init_hsem(cs);
725
726 #[cfg(feature = "_time-driver")]
728 crate::time_driver::init(cs);
729
730 #[cfg(all(feature = "low-power", not(feature = "_lp-time-driver")))]
732 rtc::init_rtc(cs, config.rtc, config.min_stop_pause);
733 }
734
735 p
736 })
737}
738
739#[allow(unused)]
741pub(crate) fn block_for_us(us: u64) {
742 cortex_m::asm::delay(unsafe { rcc::get_freqs().sys.to_hertz().unwrap().0 as u64 * us / 1_000_000 } as u32);
743}