stm32_hal2/
lib.rs

1//! This library provides high-level access to STM32 peripherals.
2//!
3//! **Current family support**: F3, F4, L4, L5, G0, G4, H7, and WB. U5 is planned once its SVD files and PAC
4//! become available.
5//!
6//! Please see the [Readme](https://github.com/David-OConnor/stm32-hal/blob/main/README.md) for a detailed overview,
7//! and the [examples folder on Github](https://github.com/David-OConnor/stm32-hal/tree/main/examples)
8//! for example code and project structure.
9//!
10//! ## Getting started
11//! Review the [syntax overview example](https://github.com/David-OConnor/stm32-hal/tree/main/examples/syntax_overview)
12//! for example uses of many of this library's features. Copy and paste its whole folder (It's set up
13//! using [Knurling's app template](https://github.com/knurling-rs/app-template)), or copy parts of `Cargo.toml`
14//! and `main.rs` as required.
15//!
16//! The [blinky example](https://github.com/David-OConnor/stm32-hal/tree/main/examples/blinky) provides a detailed example and instructions for how to set up a blinking
17//! light (ie hello world) using an STM32F411 "blackpill" board. Its readme provides instructions for how to get
18//! started from scratch, and its code contains detailed comments explaining each part. The
19//! [blinky with timer interrupt example](https://github.com/David-OConnor/stm32-hal/tree/main/examples/blinky_timer_interrupt)
20//! demonstrates how to accomplish the same in a non-blocking way, using a hardware timer. It uses RTIC.
21//!
22//! The [conductivity module example](https://github.com/David-OConnor/stm32-hal/tree/main/examples/conductivity_module)
23//! is a complete example of simple production firmware. It uses the DAC, I2C, Timer, and UART peripherals,
24//! with a simple interupt-based control flow.
25//!
26//! The [PDM mic, DAC output passthrough example](https://github.com/David-OConnor/stm32-hal/tree/main/examples/pdm_mic_dac_output.rs)
27//! demonstrates how to read audio from a digital microphone, output it to headphones or speakers using the DAC, and use DMA
28//! to do this efficiently. It conducts minimal processing, but can be modified to process using DSP between input and output.
29//! This example uses RTIC.
30//!
31//! Additional examples in the [examples folder](https://github.com/David-OConnor/stm32-hal/tree/main/examples) demonstrate
32//! how to use various STM32 peripherals; most of these examples focus on a single peripheral.
33//!
34//! When specifying this crate as a dependency in `Cargo.toml`, you need to specify a feature
35//! representing your MCU. If this is for code that runs on an MCU directly (ie not a library), also
36//!  include a run-time feature, following the template `l4rt`. For example:
37//! ```toml
38//! cortex-m = { version = "^0.7.7", features = ["critical-section-single-core"] }
39//! cortex-m-rt = "0.7.2"
40//! hal = { package = "stm32-hal2", version = "^1.5.5", features = ["l4x3", "l4rt"]}
41//! ```
42//!
43//! If you need `embedded-hal` traits, include the `embedded-hal` feature.
44//!
45//! You can review [this section of Cargo.toml](https://github.com/David-OConnor/stm32-hal/blob/main/Cargo.toml#L61)
46//! to see which MCU and runtime features are available.
47//!
48//! ### Example highlights:
49//! ```rust
50//! use cortex_m;
51//! use cortex_m_rt::entry;
52//! use hal::{
53//!     clocks::Clocks,
54//!     gpio::{Pin, Port, PinMode, OutputType},
55//!     i2c::I2c,
56//!     low_power,
57//!     pac,
58//!     timer::{Timer, TimerInterrupt},
59//! };
60//!
61//! #[entry]
62//! fn main() -> ! {
63//!    let mut dp = pac::Peripherals::take().unwrap();
64//!
65//!    let clock_cfg = Clocks::default();
66//!    clock_cfg.setup().unwrap();
67//!
68//!    let mut pb15 = Pin::new(Port::A, 15, PinMode::Output);
69//!    pb15.set_high();
70//!
71//!    let mut timer = Timer::new_tim3(dp.TIM3, 0.2, Default::default(), &clock_cfg);
72//!    timer.enable_interrupt(TimerInterrupt::Update);
73//!
74//!    let mut scl = Pin::new(Port::B, 6, PinMode::Alt(4));
75//!    scl.output_type(OutputType::OpenDrain);
76//!
77//!    let mut sda = Pin::new(Port::B, 7, PinMode::Alt(4));
78//!    sda.output_type(OutputType::OpenDrain);
79//!
80//!    let mut dma = Dma::new(dp.DMA1);
81//!    dma::mux(DmaPeriph::Dma1, DmaChannel::C1, DmaInput::I2c1Tx);
82//!
83//!    let i2c = I2c::new(dp.I2C1, Default::default(), &clock_cfg);
84//!
85//!    loop {
86//!        i2c.write(0x50, &[1, 2, 3]);
87//!        // Or:
88//!        i2c.write_dma(0x50, &BUF, DmaChannel::C1, Default::default(), DmaPeriph::Dma1);
89//!
90//!        low_power::sleep_now();
91//!    }
92//!}
93//! ```
94//!
95//! Supports the RTIC `Monotonic` trait. To enable, use the `monotonic` feature.
96//!
97//! [This article](https://www.anyleaf.org/blog/writing-embedded-firmware-using-rust) provides some information
98//! on using this library, as well as background information on Rust embedded in general.
99//!
100//! ## Docs caveat
101//! This Rust docs page is built for `STM32H735`, and some aspects are not accurate for other
102//! variants. Clock (RCC) config in particular varies significantly between variants. We currently
103//! don't have a good solution to this problem, and may self-host docs in the future.
104
105// Some overall notes:
106// We generally don't use the named field methods provided by PACs, as these are inconsistently
107// implemented among PACs. Ie f3's may have a `'`.enabled()` method, but `l4` does not;
108// in these cases, writing `set_bit()` works for both.
109
110// We use a combination of macros and feature-gating to handle differences in families, as appropriate.
111// We leverage the `paste` and `cfg-if` crates to improve syntax.
112
113// The main way we divide MCUs is by PAC modules. Note that there are sub-variants that may have differences
114// that this doesn't take into account. (eg different USB memory sizes among f303 variants)
115
116// We use `unsafe` blocks for most multi-fit field writes. This is required by some PACs, but not others.
117// The rust embedded team removes requirement for `unsafe` on fields that are deemed sufficiently
118// constrained as to not need these blocks.
119// Using `unsafe` for all is cleaner than feature-gating, due to how many fields this affects. We've allowed
120// these warnings; ie hidden during build.
121
122#![no_std]
123// Some reg modifications are marked `unsafe` in some PAC crates, but not others.
124// Disable these warnings.
125#![allow(unused_unsafe)]
126// The `doc_cfg` feature allows us to show functionality that is feature-gated on `docs.rs`.
127// todo: Re-implement the doc_cfg feature and the relevant tags (From all modules that impl EH traits)
128// todo oncoe this is in stable.
129// #![feature(doc_cfg)]
130
131// todo: H7B3 has too many changes in v14 PAC; not supporting at this time. (2021-10-07)
132
133// Used for while loops, to allow returning an error instead of hanging.
134pub(crate) const MAX_ITERS: u32 = 300_000; // todo: What should this be?
135
136#[cfg(not(any(
137    feature = "f301",
138    feature = "f302",
139    feature = "f303",
140    feature = "f373",
141    feature = "f3x4",
142    feature = "f401",
143    feature = "f405",
144    feature = "f407",
145    feature = "f410",
146    feature = "f411",
147    feature = "f412",
148    feature = "f413",
149    feature = "f427",
150    feature = "f429",
151    feature = "f446",
152    feature = "f469",
153    feature = "l4x1",
154    feature = "l4x2",
155    feature = "l412",
156    feature = "l4x3",
157    feature = "l4x5",
158    feature = "l4x6",
159    feature = "l552",
160    feature = "l562",
161    feature = "g030",
162    feature = "g031",
163    feature = "g041",
164    feature = "g050",
165    feature = "g051",
166    feature = "g061",
167    feature = "g070",
168    feature = "g071",
169    feature = "g081",
170    feature = "g0b0",
171    feature = "g0b1",
172    feature = "g0c1",
173    feature = "g431",
174    feature = "g441",
175    feature = "g471",
176    feature = "g473",
177    feature = "g474",
178    feature = "g483",
179    feature = "g484",
180    feature = "g491",
181    feature = "g4a1",
182    feature = "h503",
183    feature = "h562",
184    feature = "h563",
185    feature = "h573",
186    feature = "h735",
187    feature = "h743",
188    feature = "h743v",
189    feature = "h747cm4",
190    feature = "h747cm7",
191    feature = "h753",
192    feature = "h753v",
193    feature = "h7b3",
194    feature = "wb55",
195    feature = "wle5",
196)))]
197compile_error!("This crate requires an MCU-specifying feature to be enabled. eg `l552`.");
198
199// Re-export of the [svd2rust](https://crates.io/crates/svd2rust) auto-generated API for
200// stm32 peripherals.
201
202// todo: U5 once SVD is out.
203use cfg_if::cfg_if;
204use cortex_m::{self, delay::Delay};
205#[cfg(feature = "f3x4")]
206pub use stm32f3::stm32f3x4 as pac;
207#[cfg(feature = "f301")]
208pub use stm32f3::stm32f301 as pac;
209#[cfg(feature = "f302")]
210pub use stm32f3::stm32f302 as pac;
211#[cfg(feature = "f303")]
212pub use stm32f3::stm32f303 as pac;
213#[cfg(feature = "f373")]
214pub use stm32f3::stm32f373 as pac;
215// F4 PAC
216#[cfg(feature = "f401")]
217pub use stm32f4::stm32f401 as pac;
218#[cfg(feature = "f405")]
219pub use stm32f4::stm32f405 as pac;
220#[cfg(feature = "f407")]
221pub use stm32f4::stm32f407 as pac;
222#[cfg(feature = "f410")]
223pub use stm32f4::stm32f410 as pac;
224#[cfg(feature = "f411")]
225pub use stm32f4::stm32f411 as pac;
226#[cfg(feature = "f412")]
227pub use stm32f4::stm32f412 as pac;
228#[cfg(feature = "f413")]
229pub use stm32f4::stm32f413 as pac;
230#[cfg(feature = "f427")]
231pub use stm32f4::stm32f427 as pac;
232#[cfg(feature = "f429")]
233pub use stm32f4::stm32f429 as pac;
234#[cfg(feature = "f446")]
235pub use stm32f4::stm32f446 as pac;
236#[cfg(feature = "f469")]
237pub use stm32f4::stm32f469 as pac;
238#[cfg(feature = "g0b0")]
239pub use stm32g0::stm32g0b0 as pac;
240#[cfg(feature = "g0b1")]
241pub use stm32g0::stm32g0b1 as pac;
242#[cfg(feature = "g0c1")]
243pub use stm32g0::stm32g0c1 as pac;
244// todo: Test and make accomodations for recently added G0 variants 50, 51, 61, B0, B1 and C1, in
245// todo the individual modules.
246
247// G0 PAC
248#[cfg(feature = "g030")]
249pub use stm32g0::stm32g030 as pac;
250#[cfg(feature = "g031")]
251pub use stm32g0::stm32g031 as pac;
252#[cfg(feature = "g041")]
253pub use stm32g0::stm32g041 as pac;
254#[cfg(feature = "g050")]
255pub use stm32g0::stm32g050 as pac;
256#[cfg(feature = "g051")]
257pub use stm32g0::stm32g051 as pac;
258#[cfg(feature = "g061")]
259pub use stm32g0::stm32g061 as pac;
260#[cfg(feature = "g070")]
261pub use stm32g0::stm32g070 as pac;
262#[cfg(feature = "g071")]
263pub use stm32g0::stm32g071 as pac;
264#[cfg(feature = "g081")]
265pub use stm32g0::stm32g081 as pac;
266#[cfg(feature = "g4a1")]
267pub use stm32g4::stm32g4a1 as pac;
268// G4 PAC
269#[cfg(feature = "g431")]
270pub use stm32g4::stm32g431 as pac;
271#[cfg(feature = "g441")]
272pub use stm32g4::stm32g441 as pac;
273#[cfg(feature = "g471")]
274pub use stm32g4::stm32g471 as pac;
275#[cfg(feature = "g473")]
276pub use stm32g4::stm32g473 as pac;
277#[cfg(feature = "g474")]
278pub use stm32g4::stm32g474 as pac;
279#[cfg(feature = "g483")]
280pub use stm32g4::stm32g483 as pac;
281#[cfg(feature = "g484")]
282pub use stm32g4::stm32g484 as pac;
283#[cfg(feature = "g491")]
284pub use stm32g4::stm32g491 as pac;
285// H5 PAC
286#[cfg(feature = "h503")]
287pub use stm32h5::stm32h503 as pac;
288#[cfg(feature = "h562")]
289pub use stm32h5::stm32h562 as pac;
290#[cfg(feature = "h563")]
291pub use stm32h5::stm32h563 as pac;
292#[cfg(feature = "h573")]
293pub use stm32h5::stm32h573 as pac;
294#[cfg(feature = "h7b3")]
295pub use stm32h7::stm32h7b3 as pac;
296// H7 PAC
297#[cfg(feature = "h735")]
298pub use stm32h7::stm32h735 as pac;
299#[cfg(feature = "h743")]
300pub use stm32h7::stm32h743 as pac;
301#[cfg(feature = "h743v")]
302pub use stm32h7::stm32h743v as pac;
303#[cfg(feature = "h747cm4")]
304pub use stm32h7::stm32h747cm4 as pac;
305#[cfg(feature = "h747cm7")]
306pub use stm32h7::stm32h747cm7 as pac;
307#[cfg(feature = "h753")]
308pub use stm32h7::stm32h753 as pac;
309#[cfg(feature = "h753v")]
310pub use stm32h7::stm32h753v as pac;
311// L4 PAC
312#[cfg(feature = "l4x1")]
313pub use stm32l4::stm32l4x1 as pac;
314#[cfg(feature = "l4x2")]
315pub use stm32l4::stm32l4x2 as pac;
316#[cfg(feature = "l4x3")]
317pub use stm32l4::stm32l4x3 as pac;
318#[cfg(feature = "l4x5")]
319pub use stm32l4::stm32l4x5 as pac;
320#[cfg(feature = "l4x6")]
321pub use stm32l4::stm32l4x6 as pac;
322#[cfg(feature = "l412")]
323pub use stm32l4::stm32l412 as pac;
324// L5 PAC
325#[cfg(feature = "l552")]
326pub use stm32l5::stm32l552 as pac;
327#[cfg(feature = "l562")]
328pub use stm32l5::stm32l562 as pac;
329#[cfg(feature = "wb55")]
330pub use stm32wb::stm32wb55 as pac;
331#[cfg(feature = "wle5")]
332pub use stm32wl::stm32wle5 as pac;
333
334#[cfg(not(any(feature = "f301", feature = "f302")))]
335pub mod adc;
336
337// bxCAN families: F3, F4, L4,
338// fdCAN families: L5, U5, G4, H7
339// H7 suppords fd and can_ccu. (What's that?)
340// WB and WL?
341#[cfg(all(
342    any(feature = "can_bx", feature = "can_fd_g", feature = "can_fd_h"),
343    // not(any(feature = "f301", feature = "f401", feature = "f410", feature = "f411"))
344))]
345pub mod can;
346
347// For now, we're using the `fdcan` crate
348// #[cfg(any(feature = "g0c1", feature = "g4", feature = "h7"))]
349// pub mod fd_can;
350
351pub mod clocks;
352// todo: You could get CRC working on these.
353#[cfg(not(any(
354    feature = "f3",
355    feature = "f4",
356    feature = "wb",
357    feature = "wl",
358    feature = "h5", // todo: COme back to
359)))]
360pub mod crc;
361
362#[cfg(not(any(
363    feature = "f401",
364    feature = "f411",
365    feature = "f412",
366    feature = "wb",
367    feature = "g0",
368    feature = "h5", // todo: H5 DAC pending PAC fix.
369)))]
370// WB doesn't have a DAC. Some G0 variants do - add it! Most F4 variants have it, some don't
371pub mod dac;
372
373#[cfg(not(any(
374    feature = "f3",
375    feature = "f4",
376    feature = "l4x1",
377    feature = "l4x2",
378    feature = "l412",
379    feature = "l4x3",
380    feature = "l4x5",
381    feature = "g0",
382    feature = "g4",
383    feature = "wb",
384    feature = "wl",
385    feature = "h5", // todo: Check PAC.
386// todo: DFSDM support for other platforms that don't support clustering
387)))]
388pub mod dfsdm;
389
390#[cfg(not(any(feature = "f4", feature = "l552", feature = "h5")))]
391pub mod dma;
392
393#[cfg(all(feature = "h7", feature = "net"))]
394pub mod ethernet;
395
396#[cfg(not(feature = "h5"))] // todo: Come back to
397pub mod flash;
398
399// todo: PAC doesn't yet support these newer H7 MCUs that use FMAC.
400// #[cfg(any(feature = "h723", feature = "h725", feature = "h733", feature = "h735"))]
401// todo: Also G4.
402// pub mod fmac;
403
404pub mod gpio;
405
406#[cfg(feature = "wb")]
407pub mod hsem;
408
409#[cfg(not(any(feature = "f4")))]
410pub mod i2c;
411#[cfg(feature = "f4")]
412pub mod i2c_f4;
413#[cfg(feature = "f4")]
414pub use i2c_f4 as i2c;
415
416#[cfg(feature = "wb")]
417pub mod ipcc;
418
419pub mod iwdg;
420
421pub mod low_power;
422
423#[cfg(any(feature = "h747cm4", feature = "h747cm7"))]
424pub mod power;
425
426// F3, F4, G0, and WL don't have Quad SPI. L5 and newer H variants (eg H735) use OctoSPI,
427// also supported by this module.
428#[cfg(not(any(
429feature = "f3",
430feature = "f4",
431feature = "l4x3", // todo: PAC bug?
432feature = "g0",
433feature = "g431",
434feature = "g441",
435feature = "g471",
436feature = "g491",
437feature = "g4a1",
438feature = "wl",
439feature = "l5", // todo: PAC errors on some regs.
440feature = "h5",
441)))]
442pub mod qspi;
443
444// Note: Some F4 variants support RNG, but we haven't figured out the details yet. Send a PR if interested.
445#[cfg(not(any(
446    feature = "f3",
447    feature = "f4",
448    feature = "g030",
449    feature = "g031",
450    feature = "g070",
451    feature = "g071",
452    feature = "g0b1",
453    feature = "g0c1",
454)))]
455pub mod rng;
456
457pub mod rtc;
458
459#[cfg(not(any(
460    feature = "f3",
461    feature = "f4",
462    feature = "g0",
463    // feature = "g4", // todo: G4 PAC issue re getting channel-specific reg blocks.
464    feature = "h7b3",
465    feature = "wl",
466    feature = "h5", // todo
467)))]
468pub mod sai;
469
470#[cfg(not(feature = "h5"))] // todo: Add H5 SPI!
471pub mod spi;
472
473#[cfg(not(feature = "h5"))] // todo temp
474pub mod timer;
475
476// #[cfg(not(feature = "h5"))] // todo temp. Needs CR1 and ISR added, among other things.
477pub mod usart;
478
479#[cfg(any(
480    feature = "l4",
481    // feature = "g4",
482    feature = "g473", // todo: Not compiling on G431
483    feature = "h7"
484))]
485pub mod comp;
486
487// See note at top of `usb` module for info on G0; not avail on modules the PAC has avail.
488cfg_if! {
489    if #[cfg(all(
490        feature = "usb",
491        all(
492            any(
493                feature = "f303",
494                feature = "l4x2",
495                feature = "l412",
496                feature = "l4x3",
497                feature = "l4x5",
498                feature = "l5",
499                feature = "g4",
500                feature = "wb",
501            ),
502        not(feature = "g4a1"))
503    ))] {
504        pub mod usb;
505    } else if #[cfg(all(
506        // H7 has HS (high-speed), while F4 and L4 have FS. The names get confusing, starting
507        // on ST's side.
508        any(feature = "usbotg_fs", feature = "usbotg_hs"),
509        any(feature = "f4", feature = "l4x6", feature = "h7"),
510        not(feature = "f410")
511    ))] {
512        pub mod usb_otg;
513        pub use usb_otg as usb;
514    }
515}
516
517// For use with timers; converting ticks to real time.
518pub mod instant;
519mod util;
520pub use util::{BaudPeriph, RccPeriph};
521
522// todo: should these helper macros be removed from this library? It has nothing to do with STM32.
523
524/// Syntax helper for getting global variables of the form `Mutex<RefCell<Option>>>` from an interrupt-free
525/// context - eg in interrupt handlers.
526///
527/// Example: `access_global!(DELAY, delay, cs)`
528#[macro_export]
529macro_rules! access_global {
530    ($NAME_GLOBAL:ident, $name_local:ident, $cs:expr) => {
531        let mut part1 = $NAME_GLOBAL.borrow($cs).borrow_mut();
532        let $name_local = part1.as_mut().unwrap();
533    };
534}
535
536/// Similar to `access_global`, but combining multiple calls.
537///
538/// Example: `access_globals!([
539///     (USB_DEV, usb_dev),
540///     (USB_SERIAL, usb_serial),
541/// ], cs);`
542#[macro_export]
543macro_rules! access_globals {
544    ([$(($NAME_GLOBAL:ident, $name_local:ident)),* $(,)?], $cs:expr) => {
545        $(
546            let mut part = $NAME_GLOBAL.borrow($cs).borrow_mut();
547            let $name_local = part.as_mut().unwrap();
548        )*
549    };
550}
551
552/// Syntax helper for setting global variables of the form `Mutex<RefCell<Option>>>`.
553/// eg in interrupt handlers. Ideal for non-copy-type variables that can't be initialized
554/// immediatiately.
555///
556/// Example: `make_globals!(
557///     (USB_SERIAL, SerialPort<UsbBusType>),
558///     (DELAY, Delay),
559/// )`
560#[macro_export]
561macro_rules! make_globals {
562    ($(($NAME:ident, $type:ty)),+ $(,)?) => {
563        $(
564            static $NAME: Mutex<RefCell<Option<$type>>> = Mutex::new(RefCell::new(None));
565        )+
566    };
567}
568
569/// Syntax helper for setting global variables of the form `Mutex<Cell<>>>`.
570/// eg in interrupt handlers. Ideal for copy-type variables.
571///
572/// Example: `make_simple_globals!(
573///     (VALUE, f32, 2.),
574///     (SETTING, Setting, Setting::A),
575/// )`
576#[macro_export]
577macro_rules! make_simple_globals {
578    ($(($NAME:ident, $type:ty, $val:expr)),+ $(,)?) => {
579        $(
580            static $NAME: Mutex<Cell<$type>> = Mutex::new(Cell::new($val));
581        )+
582    };
583}
584
585/// Automates Cortex-M NVIC setup. The second value is NVIC priority; lower
586/// is higher priority. Example use:
587/// setup_nvic!([
588///     (TIM2, 6),
589///     (TIM3, 7),
590///     (EXTI0, 4),
591/// ], cp)
592#[macro_export]
593macro_rules! setup_nvic {
594    (
595        [ $( ($int:ident, $prio:expr) ),* $(,)? ],
596        $cp:ident
597    ) => {
598        unsafe {
599            // unmask all interrupts
600            $(
601                NVIC::unmask(pac::Interrupt::$int);
602            )*
603            // then set their priorities
604            $(
605                $cp.NVIC.set_priority(pac::Interrupt::$int, $prio);
606            )*
607        }
608    };
609}
610
611/// Syntax helper for parsing multi-byte fields into primitives.
612///
613/// Example: `parse_le!(bytes, i32, 5..9);`
614#[macro_export]
615macro_rules! parse_le {
616    ($bytes:expr, $t:ty, $range:expr) => {{ <$t>::from_le_bytes($bytes[$range].try_into().unwrap()) }};
617}
618
619/// Syntax helper for parsing multi-byte fields into primitives.
620///
621/// Example: `parse_be!(bytes, i32, 5..9);`
622#[macro_export]
623macro_rules! parse_be {
624    ($bytes:expr, $t:ty, $range:expr) => {{ <$t>::from_be_bytes($bytes[$range].try_into().unwrap()) }};
625}
626
627/// Syntax helper for converting primitives to multi-byte fields.
628///
629/// Example: `copy_le!(bytes, self.position, 5..9);`
630#[macro_export]
631macro_rules! copy_le {
632    ($dest:expr, $src:expr, $range:expr) => {{ $dest[$range].copy_from_slice(&$src.to_le_bytes()) }};
633}
634
635/// Syntax helper for converting primitives to multi-byte fields.
636///
637/// Example: `copy_be!(bytes, self.position, i32, 5..9);`
638#[macro_export]
639macro_rules! copy_be {
640    ($dest:expr, $src:expr, $range:expr) => {{ $dest[$range].copy_from_slice(&$src.to_be_bytes()) }};
641}
642
643// todo: Remove this debug_workaroudn function on MCUs that don't require it. Ie, is this required on G4? G0?
644#[cfg(not(any(feature = "g0")))]
645/// Workaround due to debugger disconnecting in WFI (and low-power) modes.
646/// This affects most (all?) STM32 devices. In production on battery-powered
647/// devices that don't use DMA, consider removing this, to prevent power
648/// use by the DMA clock.
649/// For why we enable the DMA clock, see STM32F446 errata, section 2.1.1.
650pub fn debug_workaround() {
651    let dbgmcu = unsafe { &(*pac::DBGMCU::ptr()) };
652
653    cfg_if! {
654        if #[cfg(all(feature = "h7", not(any(feature = "h747cm4", feature = "h747cm7"))))] {
655            dbgmcu.cr.modify(|_, w| w.dbgsleep_d1().set_bit());
656            dbgmcu.cr.modify(|_, w| w.dbgstop_d1().set_bit());
657            dbgmcu.cr.modify(|_, w| w.dbgstby_d1().set_bit());
658        } else if #[cfg(feature = "h7")] {
659            dbgmcu.cr.modify(|_, w| w.dbgslpd1().set_bit());
660            dbgmcu.cr.modify(|_, w| w.dbgstpd1().set_bit());
661            dbgmcu.cr.modify(|_, w| w.dbgstbd1().set_bit());
662        } else {
663            #[cfg(not(any(feature = "l5", feature = "h5")))]
664            dbgmcu.cr.modify(|_, w| w.dbg_sleep().set_bit());
665            dbgmcu.cr.modify(|_, w| w.dbg_stop().set_bit());
666            dbgmcu.cr.modify(|_, w| w.dbg_standby().set_bit());
667        }
668    }
669
670    let rcc = unsafe { &(*pac::RCC::ptr()) };
671
672    // todo Some MCUs may need the dbgmcu lines, but not DMA enabled.
673    // todo: Remove this part on MCUs not affected. F4 and L4 are confirmed affected.
674
675    cfg_if! {
676        if #[cfg(feature = "f3")] {
677            rcc.ahbenr.modify(|_, w| w.dma1en().set_bit());
678        } else if #[cfg(feature = "h5")] {
679            rcc.ahb1enr.modify(|_, w| w.gpdma1en().set_bit());
680        } else {
681            rcc.ahb1enr.modify(|_, w| w.dma1en().set_bit());
682        }
683    }
684}
685
686/// A blocking delay, for a specified time in ms.
687pub fn delay_ms(num_ms: u32, ahb_freq: u32) {
688    let cp = unsafe { cortex_m::Peripherals::steal() };
689    let mut delay = Delay::new(cp.SYST, ahb_freq);
690    delay.delay_ms(num_ms);
691}
692
693/// A blocking delay, for a specified time in μs.
694pub fn delay_us(num_us: u32, ahb_freq: u32) {
695    let cp = unsafe { cortex_m::Peripherals::steal() };
696    let mut delay = Delay::new(cp.SYST, ahb_freq);
697    delay.delay_us(num_us);
698}
699
700/// In the prelude, we export helper macros.
701pub mod prelude {
702    pub use access_global;
703    pub use access_globals;
704    pub use make_globals;
705    pub use make_simple_globals;
706}