consortium-hal-stm32mp2 0.5.0

Consortium HAL for STM32MP2 family devices
Documentation
#![no_std]
// Copyright 2026 Ethan Wu
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//! Consortium HAL for STM32MP2 family devices.
//!
//! Peripherals are owned, not addressed. [`init`] hands out the chip's
//! singletons once as a [`Peripherals`] struct, and each driver's constructor
//! consumes the one it drives:
//!
//! ```ignore
//! let p = consortium_hal_stm32mp2::init();
//! let i2c = consortium_hal_stm32mp2::i2c::I2c::new(p.I2C1, 64_000_000, 400_000);
//! ```
//!
//! Because the base address and NVIC line travel with the singleton, no driver
//! takes an MMIO pointer and no constructor is `unsafe`. Bring-up that runs
//! outside [`init`] — a second-stage loader, a test harness — can still reach a
//! peripheral through `peripherals::<NAME>::steal()`, which carries the
//! exclusivity obligation the safe path discharges.
//!
//! # Layering
//!
//! ```text
//! consortium-hal              Peri, PeripheralType, peripherals!, narrow traits
//!   └── consortium-hal-stm32mp2  (this crate) drivers + generated singletons
//!         └── consortium-pac-stm32mp2   register blocks, Interrupt, vector table
//! ```
//!
//! Both are re-exported ([`hal`], [`pac`]), so a firmware crate needs one dependency.
//! [`interrupts`], [`Interrupt`], and — behind `rt` — the `interrupt` attribute macro
//! come straight from the PAC.
//!
//! # Drivers
//!
//! Each is behind a feature, all on by default: `adc`, `can`, `dma`, `gpio`,
//! `i2c`, `i3c`, `lptim`, `spi`, `timer`, `timer_driver`, `uart`, `watchdog`.
//!
//! `timer_driver` (`time-driver-gp-tim`) is the Embassy time driver over TIM2;
//! `consortium-cfg` emits its bring-up into the generated `init()` unless
//! `[profile] time_driver = false`.
//!
//! # Chip selection
//!
//! `stm32mp21x`, `stm32mp23x`, or `stm32mp25x` — **exactly one**.
//!
//! `stm32mp23x` and `stm32mp25x` share one die, memory map and interrupt numbering
//! (RM0457), so both forward to the PAC's `stm32mp257` chip. Each has its own
//! singleton map: MP23 lacks the instances its datasheet (DS14634) rules out, such
//! as I2C3–6, FDCAN3, TIM20, LPDMA and IPCC2. `stm32mp21x` has its own map. Enabling
//! several is a duplicate-definition error.
//!
//! Default is `stm32mp25x`. **A dependent selecting another chip must set
//! `default-features = false`**, or `stm32mp25x` comes along too and the PAC's
//! `Interrupt` enum becomes ambiguous. The doorbell and UART-transport crates all do
//! this.
//!
//! # Interrupts are the application's
//!
//! This crate installs no `#[interrupt]` handlers. The application owns the vector
//! table and forwards each vector into the driver's entry point, parameterized with
//! the same singleton the driver consumed:
//!
//! ```rust,ignore
//! #[interrupt]
//! fn USART2() {
//!     consortium_hal_stm32mp2::uart::on_buffered_interrupt::<peripherals::USART2>();
//! }
//! ```
//!
//! Enable `rt` so the `#[interrupt]` macro and PAC vector table are available there.
//! The same applies to the doorbell crates: HSEM and IPCC RX vectors are forwarded by
//! application code, not installed here.
//!
//! # Generated code
//!
//! `src/peripherals/<chip>.rs` is generated by `scripts/pac/gen_peripherals.py` from
//! the same `consortium-data` chip dumps that feed `gen_interrupts.py`. It declares the
//! singletons and invokes each driver's `impl_<driver>!` macro with that instance's
//! base and NVIC line — so the generated file is **data only** and the driver module
//! owns the logic. Re-run the generator after changing a chip dump rather than editing
//! it.
//!
//! # Secure aliases
//!
//! The singletons carry only the **non-secure** alias of each peripheral window. That
//! is why `consortium-cfg` rejects `[peripheral.*]` entries with `secure = true`: there
//! is no singleton to hand out for the secure view.

#[cfg(test)]
extern crate std;

pub use consortium_hal as hal;
/// Ownership handle and marker trait for peripheral singletons, re-exported so
/// drivers in other crates can name them without depending on Embassy directly.
pub use consortium_hal::{Peri, PeripheralType};
pub use consortium_pac_stm32mp2 as pac;

// Peripheral singletons and their driver bindings, generated from the chip
// databases by `scripts/pac/gen_peripherals.py`. Chip features are mutually
// exclusive; enabling several is a duplicate-definition error, matching the PAC.
// `stm32mp23x` shares the PAC's STM32MP257 interrupt table but has its own map.
#[cfg(feature = "stm32mp25x")]
#[path = "peripherals/stm32mp25.rs"]
mod chip;
#[cfg(feature = "stm32mp23x")]
#[path = "peripherals/stm32mp23.rs"]
mod chip;
#[cfg(feature = "stm32mp21x")]
#[path = "peripherals/stm32mp21.rs"]
mod chip;

#[cfg(any(feature = "stm32mp21x", feature = "stm32mp23x", feature = "stm32mp25x"))]
pub use chip::{Peripherals, peripherals};

/// Take the chip's peripheral singletons.
///
/// # Panics
///
/// Panics if called more than once — the singletons are exactly that, and
/// handing them out twice would let two drivers claim the same registers.
#[cfg(any(feature = "stm32mp21x", feature = "stm32mp23x", feature = "stm32mp25x"))]
pub fn init() -> Peripherals {
    Peripherals::take()
}

/// Interrupt lines for the selected chip, re-exported from the PAC for direct
/// HAL consumers.
pub use pac::interrupts;
pub use pac::interrupts::Interrupt;
/// The `#[interrupt]` attribute macro, available when the `rt` feature is on.
#[cfg(feature = "rt")]
pub use pac::interrupts::interrupt;

#[cfg(feature = "adc")]
pub mod adc;

#[cfg(feature = "can")]
pub mod can;

#[cfg(feature = "dma")]
pub mod dma;

#[cfg(feature = "gpio")]
pub mod gpio;

#[cfg(feature = "i2c")]
pub mod i2c;

#[cfg(feature = "i3c")]
pub mod i3c;

#[cfg(feature = "lptim")]
pub mod lptim;

#[cfg(feature = "spi")]
pub mod spi;

#[cfg(feature = "time-driver-gp-tim")]
pub mod timer_driver;

#[cfg(feature = "timer")]
pub mod timer;

#[cfg(feature = "uart")]
pub mod uart;

#[cfg(feature = "watchdog")]
pub mod watchdog;