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(iwdg)]
129pub mod wdg;
130
131pub(crate) mod _generated {
133 #![allow(dead_code)]
134 #![allow(unused_imports)]
135 #![allow(non_snake_case)]
136 #![allow(missing_docs)]
137
138 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
139}
140
141pub use crate::_generated::interrupt;
142
143#[macro_export]
173macro_rules! bind_interrupts {
174 ($vis:vis struct $name:ident {
175 $(
176 $(#[cfg($cond_irq:meta)])?
177 $irq:ident => $(
178 $(#[cfg($cond_handler:meta)])?
179 $handler:ty
180 ),*;
181 )*
182 }) => {
183 #[derive(Copy, Clone)]
184 $vis struct $name;
185
186 $(
187 #[allow(non_snake_case)]
188 #[no_mangle]
189 $(#[cfg($cond_irq)])?
190 unsafe extern "C" fn $irq() {
191 $(
192 $(#[cfg($cond_handler)])?
193 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
194
195 )*
196 }
197
198 $(#[cfg($cond_irq)])?
199 $crate::bind_interrupts!(@inner
200 $(
201 $(#[cfg($cond_handler)])?
202 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
203 )*
204 );
205 )*
206 };
207 (@inner $($t:tt)*) => {
208 $($t)*
209 }
210}
211
212pub use _generated::{peripherals, Peripherals};
214pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
215#[cfg(feature = "unstable-pac")]
216pub use stm32_metapac as pac;
217#[cfg(not(feature = "unstable-pac"))]
218pub(crate) use stm32_metapac as pac;
219
220use crate::interrupt::Priority;
221#[cfg(feature = "rt")]
222pub use crate::pac::NVIC_PRIO_BITS;
223
224#[non_exhaustive]
226#[derive(Clone, Copy)]
227pub struct Config {
228 pub rcc: rcc::Config,
230
231 #[cfg(dbgmcu)]
235 pub enable_debug_during_sleep: bool,
236
237 #[cfg(any(stm32l4, stm32l5, stm32u5))]
243 pub enable_independent_io_supply: bool,
244
245 #[cfg(stm32u5)]
247 pub enable_independent_analog_supply: bool,
248
249 #[cfg(bdma)]
253 pub bdma_interrupt_priority: Priority,
254
255 #[cfg(dma)]
259 pub dma_interrupt_priority: Priority,
260
261 #[cfg(gpdma)]
265 pub gpdma_interrupt_priority: Priority,
266
267 #[cfg(peri_ucpd1)]
271 pub enable_ucpd1_dead_battery: bool,
272
273 #[cfg(peri_ucpd2)]
277 pub enable_ucpd2_dead_battery: bool,
278}
279
280impl Default for Config {
281 fn default() -> Self {
282 Self {
283 rcc: Default::default(),
284 #[cfg(dbgmcu)]
285 enable_debug_during_sleep: true,
286 #[cfg(any(stm32l4, stm32l5, stm32u5))]
287 enable_independent_io_supply: true,
288 #[cfg(stm32u5)]
289 enable_independent_analog_supply: true,
290 #[cfg(bdma)]
291 bdma_interrupt_priority: Priority::P0,
292 #[cfg(dma)]
293 dma_interrupt_priority: Priority::P0,
294 #[cfg(gpdma)]
295 gpdma_interrupt_priority: Priority::P0,
296 #[cfg(peri_ucpd1)]
297 enable_ucpd1_dead_battery: false,
298 #[cfg(peri_ucpd2)]
299 enable_ucpd2_dead_battery: false,
300 }
301 }
302}
303
304#[cfg(not(feature = "_dual-core"))]
310pub fn init(config: Config) -> Peripherals {
311 init_hw(config)
312}
313
314#[cfg(feature = "_dual-core")]
315mod dual_core {
316 use core::cell::UnsafeCell;
317 use core::mem::MaybeUninit;
318 use core::sync::atomic::{AtomicUsize, Ordering};
319
320 use rcc::Clocks;
321
322 use super::*;
323
324 #[repr(C)]
340 pub struct SharedData {
341 init_flag: AtomicUsize,
342 clocks: UnsafeCell<MaybeUninit<Clocks>>,
343 config: UnsafeCell<MaybeUninit<SharedConfig>>,
344 }
345
346 unsafe impl Sync for SharedData {}
347
348 const INIT_DONE_FLAG: usize = 0xca11ab1e;
349
350 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
361 let shared_data = unsafe { shared_data.assume_init_ref() };
362
363 shared_data.init_flag.store(0, Ordering::SeqCst);
367
368 rcc::set_freqs_ptr(shared_data.clocks.get());
369 let p = init_hw(config);
370
371 unsafe { *shared_data.config.get() }.write(config.into());
372
373 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
374
375 p
376 }
377
378 pub fn try_init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Option<Peripherals> {
388 let shared_data = unsafe { shared_data.assume_init_ref() };
389
390 if shared_data.init_flag.load(Ordering::SeqCst) != INIT_DONE_FLAG {
391 return None;
392 }
393
394 shared_data.init_flag.store(0, Ordering::SeqCst);
396
397 Some(init_secondary_hw(shared_data))
398 }
399
400 pub fn init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
410 loop {
411 if let Some(p) = try_init_secondary(shared_data) {
412 return p;
413 }
414 }
415 }
416
417 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
418 rcc::set_freqs_ptr(shared_data.clocks.get());
419
420 let config = unsafe { (*shared_data.config.get()).assume_init() };
421
422 critical_section::with(|cs| {
424 unsafe {
425 dma::init(
426 cs,
427 #[cfg(bdma)]
428 config.bdma_interrupt_priority,
429 #[cfg(dma)]
430 config.dma_interrupt_priority,
431 #[cfg(gpdma)]
432 config.gpdma_interrupt_priority,
433 )
434 }
435
436 #[cfg(feature = "_time-driver")]
437 time_driver::init(cs);
439 });
440
441 Peripherals::take()
442 }
443
444 #[repr(C)]
445 #[derive(Clone, Copy)]
446 struct SharedConfig {
447 #[cfg(bdma)]
448 bdma_interrupt_priority: Priority,
449 #[cfg(dma)]
450 dma_interrupt_priority: Priority,
451 #[cfg(gpdma)]
452 gpdma_interrupt_priority: Priority,
453 }
454
455 impl From<Config> for SharedConfig {
456 fn from(value: Config) -> Self {
457 let Config {
458 #[cfg(bdma)]
459 bdma_interrupt_priority,
460 #[cfg(dma)]
461 dma_interrupt_priority,
462 #[cfg(gpdma)]
463 gpdma_interrupt_priority,
464 ..
465 } = value;
466
467 SharedConfig {
468 #[cfg(bdma)]
469 bdma_interrupt_priority,
470 #[cfg(dma)]
471 dma_interrupt_priority,
472 #[cfg(gpdma)]
473 gpdma_interrupt_priority,
474 }
475 }
476 }
477}
478
479#[cfg(feature = "_dual-core")]
480pub use dual_core::*;
481
482fn init_hw(config: Config) -> Peripherals {
483 critical_section::with(|cs| {
484 let p = Peripherals::take_with_cs(cs);
485
486 #[cfg(dbgmcu)]
487 crate::pac::DBGMCU.cr().modify(|cr| {
488 #[cfg(dbgmcu_h5)]
489 {
490 cr.set_stop(config.enable_debug_during_sleep);
491 cr.set_standby(config.enable_debug_during_sleep);
492 }
493 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))]
494 {
495 cr.set_dbg_stop(config.enable_debug_during_sleep);
496 cr.set_dbg_standby(config.enable_debug_during_sleep);
497 }
498 #[cfg(any(
499 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
500 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
501 ))]
502 {
503 cr.set_dbg_sleep(config.enable_debug_during_sleep);
504 cr.set_dbg_stop(config.enable_debug_during_sleep);
505 cr.set_dbg_standby(config.enable_debug_during_sleep);
506 }
507 #[cfg(dbgmcu_h7)]
508 {
509 cr.set_d1dbgcken(config.enable_debug_during_sleep);
510 cr.set_d3dbgcken(config.enable_debug_during_sleep);
511 cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
512 cr.set_dbgstby_d1(config.enable_debug_during_sleep);
513 cr.set_dbgstop_d1(config.enable_debug_during_sleep);
514 }
515 });
516
517 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
518 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
519 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
520 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
521 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))]
522 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
523
524 #[cfg(any(stm32l4, stm32l5))]
527 {
528 crate::pac::PWR.cr2().modify(|w| {
529 w.set_iosv(config.enable_independent_io_supply);
533 });
534 }
535 #[cfg(stm32u5)]
536 {
537 crate::pac::PWR.svmcr().modify(|w| {
538 w.set_io2sv(config.enable_independent_io_supply);
539 });
540 if config.enable_independent_analog_supply {
541 crate::pac::PWR.svmcr().modify(|w| {
542 w.set_avm1en(true);
543 });
544 while !crate::pac::PWR.svmsr().read().vdda1rdy() {}
545 crate::pac::PWR.svmcr().modify(|w| {
546 w.set_asv(true);
547 });
548 } else {
549 crate::pac::PWR.svmcr().modify(|w| {
550 w.set_avm1en(false);
551 w.set_avm2en(false);
552 });
553 }
554 }
555
556 #[cfg(any(stm32g070, stm32g0b0))]
559 {
560 crate::pac::SYSCFG.cfgr1().modify(|w| {
561 w.set_ucpd1_strobe(true);
562 w.set_ucpd2_strobe(true);
563 });
564 }
565
566 unsafe {
567 #[cfg(ucpd)]
568 ucpd::init(
569 cs,
570 #[cfg(peri_ucpd1)]
571 config.enable_ucpd1_dead_battery,
572 #[cfg(peri_ucpd2)]
573 config.enable_ucpd2_dead_battery,
574 );
575
576 #[cfg(feature = "_split-pins-enabled")]
577 crate::pac::SYSCFG.pmcr().modify(|pmcr| {
578 #[cfg(feature = "split-pa0")]
579 pmcr.set_pa0so(true);
580 #[cfg(feature = "split-pa1")]
581 pmcr.set_pa1so(true);
582 #[cfg(feature = "split-pc2")]
583 pmcr.set_pc2so(true);
584 #[cfg(feature = "split-pc3")]
585 pmcr.set_pc3so(true);
586 });
587
588 gpio::init(cs);
589 dma::init(
590 cs,
591 #[cfg(bdma)]
592 config.bdma_interrupt_priority,
593 #[cfg(dma)]
594 config.dma_interrupt_priority,
595 #[cfg(gpdma)]
596 config.gpdma_interrupt_priority,
597 );
598 #[cfg(feature = "exti")]
599 exti::init(cs);
600
601 rcc::init(config.rcc);
602
603 #[cfg(feature = "_time-driver")]
605 time_driver::init(cs);
606
607 #[cfg(feature = "low-power")]
608 {
609 crate::rcc::REFCOUNT_STOP2 = 0;
610 crate::rcc::REFCOUNT_STOP1 = 0;
611 }
612 }
613
614 p
615 })
616}