1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)]
3#![cfg_attr(
4 docsrs,
5 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"
6)]
7#![doc = include_str!("../README.md")]
8#![warn(missing_docs)]
9
10#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
12
13mod fmt;
15include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
16
17mod macros;
19pub mod time;
20pub mod mode {
22 trait SealedMode {}
23
24 #[allow(private_bounds)]
26 pub trait Mode: SealedMode {}
27
28 macro_rules! impl_mode {
29 ($name:ident) => {
30 impl SealedMode for $name {}
31 impl Mode for $name {}
32 };
33 }
34
35 pub struct Blocking;
37 pub struct Async;
39
40 impl_mode!(Blocking);
41 impl_mode!(Async);
42}
43
44pub mod dma;
46pub mod gpio;
47pub mod rcc;
48#[cfg(feature = "_time-driver")]
49mod time_driver;
50pub mod timer;
51
52#[cfg(adc)]
55pub mod adc;
56#[cfg(can)]
57pub mod can;
58#[cfg(all(cordic, not(any(stm32u5a5, stm32u5a9))))]
60pub mod cordic;
61#[cfg(crc)]
62pub mod crc;
63#[cfg(cryp)]
64pub mod cryp;
65#[cfg(dac)]
66pub mod dac;
67#[cfg(dcmi)]
68pub mod dcmi;
69#[cfg(dsihost)]
70pub mod dsihost;
71#[cfg(dts)]
72pub mod dts;
73#[cfg(eth)]
74pub mod eth;
75#[cfg(feature = "exti")]
76pub mod exti;
77pub mod flash;
78#[cfg(fmc)]
79pub mod fmc;
80#[cfg(hash)]
81pub mod hash;
82#[cfg(hrtim)]
83pub mod hrtim;
84#[cfg(hsem)]
85pub mod hsem;
86#[cfg(hspi)]
87pub mod hspi;
88#[cfg(i2c)]
89pub mod i2c;
90#[cfg(any(all(spi_v1, rcc_f4), spi_v3))]
91pub mod i2s;
92#[cfg(stm32wb)]
93pub mod ipcc;
94#[cfg(feature = "low-power")]
95pub mod low_power;
96#[cfg(lptim)]
97pub mod lptim;
98#[cfg(ltdc)]
99pub mod ltdc;
100#[cfg(opamp)]
101pub mod opamp;
102#[cfg(octospi)]
103pub mod ospi;
104#[cfg(quadspi)]
105pub mod qspi;
106#[cfg(rng)]
107pub mod rng;
108#[cfg(all(rtc, not(rtc_v1)))]
109pub mod rtc;
110#[cfg(sai)]
111pub mod sai;
112#[cfg(sdmmc)]
113pub mod sdmmc;
114#[cfg(spdifrx)]
115pub mod spdifrx;
116#[cfg(spi)]
117pub mod spi;
118#[cfg(tsc)]
119pub mod tsc;
120#[cfg(ucpd)]
121pub mod ucpd;
122#[cfg(uid)]
123pub mod uid;
124#[cfg(usart)]
125pub mod usart;
126#[cfg(any(usb, otg))]
127pub mod usb;
128#[cfg(vrefbuf)]
129pub mod vrefbuf;
130#[cfg(iwdg)]
131pub mod wdg;
132#[cfg(xspi)]
133pub mod xspi;
134
135pub(crate) mod _generated {
137 #![allow(dead_code)]
138 #![allow(unused_imports)]
139 #![allow(non_snake_case)]
140 #![allow(missing_docs)]
141
142 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
143}
144
145pub use crate::_generated::interrupt;
146
147#[macro_export]
180macro_rules! bind_interrupts {
181 ($(#[$outer:meta])* $vis:vis struct $name:ident {
182 $(
183 $(#[doc = $doc:literal])*
184 $(#[cfg($cond_irq:meta)])?
185 $irq:ident => $(
186 $(#[cfg($cond_handler:meta)])?
187 $handler:ty
188 ),*;
189 )*
190 }) => {
191 #[derive(Copy, Clone)]
192 $(#[$outer])*
193 $vis struct $name;
194
195 $(
196 #[allow(non_snake_case)]
197 #[no_mangle]
198 $(#[cfg($cond_irq)])?
199 $(#[doc = $doc])*
200 unsafe extern "C" fn $irq() {
201 unsafe {
202 $(
203 $(#[cfg($cond_handler)])?
204 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
205
206 )*
207 }
208 }
209
210 $(#[cfg($cond_irq)])?
211 $crate::bind_interrupts!(@inner
212 $(
213 $(#[cfg($cond_handler)])?
214 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
215 )*
216 );
217 )*
218 };
219 (@inner $($t:tt)*) => {
220 $($t)*
221 }
222}
223
224pub use _generated::{peripherals, Peripherals};
226pub use embassy_hal_internal::{Peri, PeripheralType};
227#[cfg(feature = "unstable-pac")]
228pub use stm32_metapac as pac;
229#[cfg(not(feature = "unstable-pac"))]
230pub(crate) use stm32_metapac as pac;
231
232use crate::interrupt::Priority;
233#[cfg(feature = "rt")]
234pub use crate::pac::NVIC_PRIO_BITS;
235
236#[non_exhaustive]
238#[derive(Clone, Copy)]
239pub struct Config {
240 pub rcc: rcc::Config,
242
243 #[cfg(dbgmcu)]
247 pub enable_debug_during_sleep: bool,
248
249 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
255 pub enable_independent_io_supply: bool,
256
257 #[cfg(stm32u5)]
259 pub enable_independent_analog_supply: bool,
260
261 #[cfg(bdma)]
265 pub bdma_interrupt_priority: Priority,
266
267 #[cfg(dma)]
271 pub dma_interrupt_priority: Priority,
272
273 #[cfg(gpdma)]
277 pub gpdma_interrupt_priority: Priority,
278
279 #[cfg(peri_ucpd1)]
283 pub enable_ucpd1_dead_battery: bool,
284
285 #[cfg(peri_ucpd2)]
289 pub enable_ucpd2_dead_battery: bool,
290}
291
292impl Default for Config {
293 fn default() -> Self {
294 Self {
295 rcc: Default::default(),
296 #[cfg(dbgmcu)]
297 enable_debug_during_sleep: true,
298 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
299 enable_independent_io_supply: true,
300 #[cfg(stm32u5)]
301 enable_independent_analog_supply: true,
302 #[cfg(bdma)]
303 bdma_interrupt_priority: Priority::P0,
304 #[cfg(dma)]
305 dma_interrupt_priority: Priority::P0,
306 #[cfg(gpdma)]
307 gpdma_interrupt_priority: Priority::P0,
308 #[cfg(peri_ucpd1)]
309 enable_ucpd1_dead_battery: false,
310 #[cfg(peri_ucpd2)]
311 enable_ucpd2_dead_battery: false,
312 }
313 }
314}
315
316#[cfg(not(feature = "_dual-core"))]
322pub fn init(config: Config) -> Peripherals {
323 init_hw(config)
324}
325
326#[cfg(feature = "_dual-core")]
327mod dual_core {
328 use core::cell::UnsafeCell;
329 use core::mem::MaybeUninit;
330 use core::sync::atomic::{AtomicUsize, Ordering};
331
332 use rcc::Clocks;
333
334 use super::*;
335
336 #[repr(C)]
352 pub struct SharedData {
353 init_flag: AtomicUsize,
354 clocks: UnsafeCell<MaybeUninit<Clocks>>,
355 config: UnsafeCell<MaybeUninit<SharedConfig>>,
356 }
357
358 unsafe impl Sync for SharedData {}
359
360 const INIT_DONE_FLAG: usize = 0xca11ab1e;
361
362 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
373 let shared_data = unsafe { shared_data.assume_init_ref() };
374
375 shared_data.init_flag.store(0, Ordering::SeqCst);
379
380 rcc::set_freqs_ptr(shared_data.clocks.get());
381 let p = init_hw(config);
382
383 unsafe { *shared_data.config.get() }.write(config.into());
384
385 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
386
387 p
388 }
389
390 pub fn try_init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Option<Peripherals> {
400 let shared_data = unsafe { shared_data.assume_init_ref() };
401
402 if shared_data.init_flag.load(Ordering::SeqCst) != INIT_DONE_FLAG {
403 return None;
404 }
405
406 shared_data.init_flag.store(0, Ordering::SeqCst);
408
409 Some(init_secondary_hw(shared_data))
410 }
411
412 pub fn init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
422 loop {
423 if let Some(p) = try_init_secondary(shared_data) {
424 return p;
425 }
426 }
427 }
428
429 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
430 rcc::set_freqs_ptr(shared_data.clocks.get());
431
432 let config = unsafe { (*shared_data.config.get()).assume_init() };
433
434 critical_section::with(|cs| {
436 unsafe {
437 dma::init(
438 cs,
439 #[cfg(bdma)]
440 config.bdma_interrupt_priority,
441 #[cfg(dma)]
442 config.dma_interrupt_priority,
443 #[cfg(gpdma)]
444 config.gpdma_interrupt_priority,
445 )
446 }
447
448 #[cfg(feature = "_time-driver")]
449 time_driver::init(cs);
451 });
452
453 Peripherals::take()
454 }
455
456 #[repr(C)]
457 #[derive(Clone, Copy)]
458 struct SharedConfig {
459 #[cfg(bdma)]
460 bdma_interrupt_priority: Priority,
461 #[cfg(dma)]
462 dma_interrupt_priority: Priority,
463 #[cfg(gpdma)]
464 gpdma_interrupt_priority: Priority,
465 }
466
467 impl From<Config> for SharedConfig {
468 fn from(value: Config) -> Self {
469 let Config {
470 #[cfg(bdma)]
471 bdma_interrupt_priority,
472 #[cfg(dma)]
473 dma_interrupt_priority,
474 #[cfg(gpdma)]
475 gpdma_interrupt_priority,
476 ..
477 } = value;
478
479 SharedConfig {
480 #[cfg(bdma)]
481 bdma_interrupt_priority,
482 #[cfg(dma)]
483 dma_interrupt_priority,
484 #[cfg(gpdma)]
485 gpdma_interrupt_priority,
486 }
487 }
488 }
489}
490
491#[cfg(feature = "_dual-core")]
492pub use dual_core::*;
493
494fn init_hw(config: Config) -> Peripherals {
495 critical_section::with(|cs| {
496 let p = Peripherals::take_with_cs(cs);
497
498 #[cfg(dbgmcu)]
499 crate::pac::DBGMCU.cr().modify(|cr| {
500 #[cfg(dbgmcu_h5)]
501 {
502 cr.set_stop(config.enable_debug_during_sleep);
503 cr.set_standby(config.enable_debug_during_sleep);
504 }
505 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))]
506 {
507 cr.set_dbg_stop(config.enable_debug_during_sleep);
508 cr.set_dbg_standby(config.enable_debug_during_sleep);
509 }
510 #[cfg(any(
511 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
512 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
513 ))]
514 {
515 cr.set_dbg_sleep(config.enable_debug_during_sleep);
516 cr.set_dbg_stop(config.enable_debug_during_sleep);
517 cr.set_dbg_standby(config.enable_debug_during_sleep);
518 }
519 #[cfg(dbgmcu_h7)]
520 {
521 cr.set_d1dbgcken(config.enable_debug_during_sleep);
522 cr.set_d3dbgcken(config.enable_debug_during_sleep);
523 cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
524 cr.set_dbgstby_d1(config.enable_debug_during_sleep);
525 cr.set_dbgstop_d1(config.enable_debug_during_sleep);
526 }
527 });
528
529 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
530 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
531 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
532 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
533 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))]
534 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
535
536 #[cfg(any(stm32l4, stm32l5))]
539 {
540 crate::pac::PWR.cr2().modify(|w| {
541 w.set_iosv(config.enable_independent_io_supply);
545 });
546 }
547 #[cfg(stm32wba)]
548 {
549 use crate::pac::pwr::vals;
550 crate::pac::PWR.svmcr().modify(|w| {
551 w.set_io2sv(if config.enable_independent_io_supply {
552 vals::Io2sv::B_0X1
553 } else {
554 vals::Io2sv::B_0X0
555 });
556 });
557 }
558 #[cfg(stm32u5)]
559 {
560 crate::pac::PWR.svmcr().modify(|w| {
561 w.set_io2sv(config.enable_independent_io_supply);
562 });
563 if config.enable_independent_analog_supply {
564 crate::pac::PWR.svmcr().modify(|w| {
565 w.set_avm1en(true);
566 });
567 while !crate::pac::PWR.svmsr().read().vdda1rdy() {}
568 crate::pac::PWR.svmcr().modify(|w| {
569 w.set_asv(true);
570 });
571 } else {
572 crate::pac::PWR.svmcr().modify(|w| {
573 w.set_avm1en(false);
574 w.set_avm2en(false);
575 });
576 }
577 }
578
579 #[cfg(any(stm32g070, stm32g0b0))]
582 {
583 crate::pac::SYSCFG.cfgr1().modify(|w| {
584 w.set_ucpd1_strobe(true);
585 w.set_ucpd2_strobe(true);
586 });
587 }
588
589 unsafe {
590 #[cfg(ucpd)]
591 ucpd::init(
592 cs,
593 #[cfg(peri_ucpd1)]
594 config.enable_ucpd1_dead_battery,
595 #[cfg(peri_ucpd2)]
596 config.enable_ucpd2_dead_battery,
597 );
598
599 #[cfg(feature = "_split-pins-enabled")]
600 crate::pac::SYSCFG.pmcr().modify(|pmcr| {
601 #[cfg(feature = "split-pa0")]
602 pmcr.set_pa0so(true);
603 #[cfg(feature = "split-pa1")]
604 pmcr.set_pa1so(true);
605 #[cfg(feature = "split-pc2")]
606 pmcr.set_pc2so(true);
607 #[cfg(feature = "split-pc3")]
608 pmcr.set_pc3so(true);
609 });
610
611 gpio::init(cs);
612 dma::init(
613 cs,
614 #[cfg(bdma)]
615 config.bdma_interrupt_priority,
616 #[cfg(dma)]
617 config.dma_interrupt_priority,
618 #[cfg(gpdma)]
619 config.gpdma_interrupt_priority,
620 );
621 #[cfg(feature = "exti")]
622 exti::init(cs);
623
624 rcc::init_rcc(cs, config.rcc);
625 }
626
627 p
628 })
629}