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