1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
//! Hardware Abstraction Layer for STM32 Memory Controllers (FMC/FSMC)
//!
//!
//! # Implementation Guide
//!
//! You can use the functionality in this crate by implementing the
//! [`FmcPeripheral`](FmcPeripheral) trait. You should implement this trait for a
//! structure that:
//!
//! * Takes ownership of the `FMC`/`FSMC` peripheral
//! * Takes ownership of any structures / ZSTs related to the power or clock for the `FMC`/`FSMC` peripheral
//! * Contains the frequency of the `FMC`/`FSMC` source clock (usually HCLK)
//!
//! A basic structure:
//!
//! ```
//! pub struct FMC {
//! source_clock: u32,
//! // any other fields here...
//! }
//! ```
//!
//! An implementation of [`FmcPeripheral`](FmcPeripheral):
//!
//! ```rust
//! # mod stm32 { pub struct FMC {} impl FMC { pub const fn ptr() -> *const u32 { &0 } } }
//! # struct FMC { source_clock: u32 }
//! use stm32_fmc::FmcPeripheral;
//!
//! unsafe impl Sync for FMC {}
//! unsafe impl FmcPeripheral for FMC {
//! const REGISTERS: *const () = stm32::FMC::ptr() as *const ();
//!
//! fn enable(&mut self) {
//! // Enable and reset the FMC/FSMC using the RCC registers
//! // Typically RCC.AHBxEN and RCC.AHBxRST
//! }
//!
//! fn memory_controller_enable(&mut self) {
//! // Only required if your part has an `FMCEN` bit
//! }
//!
//! fn source_clock_hz(&self) -> u32 {
//! self.source_clock
//! }
//! }
//! ```
//!
//! In a HAL, you can allow users to construct your structure by implementing a
//! `new` method, or by making the fields public.
//!
//! ## Wrap constructor methods
//!
//! Each memory controller type ([`Sdram`](Sdram), [`Nand`](Nand), ..) provides both
//! `new` and `new_unchecked` methods.
//!
//! For the convenience of users, you may want to wrap these with your `new` method,
//! so that each memory can be created from the peripheral in one step.
//!
//! ```
//! # mod stm32 { pub struct FMC {} }
//! # type CoreClocks = u32;
//! # struct FMC {}
//! # impl FMC { pub fn new(_: stm32::FMC, _: &CoreClocks) -> Self { Self {} } }
//! # unsafe impl stm32_fmc::FmcPeripheral for FMC {
//! # const REGISTERS: *const () = &0 as *const _ as *const ();
//! # fn enable(&mut self) { }
//! # fn source_clock_hz(&self) -> u32 { 0 }
//! # }
//! use stm32_fmc::{
//! AddressPinSet, PinsSdram, Sdram, SdramChip, SdramPinSet, SdramTargetBank,
//! };
//!
//! impl FMC {
//! /// A new SDRAM memory via the Flexible Memory Controller
//! pub fn sdram<
//! BANK: SdramPinSet,
//! ADDR: AddressPinSet,
//! PINS: PinsSdram<BANK, ADDR>,
//! CHIP: SdramChip,
//! >(
//! fmc: stm32::FMC,
//! pins: PINS,
//! chip: CHIP,
//! clocks: &CoreClocks,
//! ) -> Sdram<FMC, CHIP> {
//! let fmc = Self::new(fmc, clocks);
//! Sdram::new(fmc, pins, chip)
//! }
//!
//! /// A new SDRAM memory via the Flexible Memory Controller
//! pub fn sdram_unchecked<CHIP: SdramChip, BANK: Into<SdramTargetBank>>(
//! fmc: stm32::FMC,
//! bank: BANK,
//! chip: CHIP,
//! clocks: &CoreClocks,
//! ) -> Sdram<FMC, CHIP> {
//! let fmc = Self::new(fmc, clocks);
//! Sdram::new_unchecked(fmc, bank, chip)
//! }
//! }
//! ```
//!
//! # Pin implementations
//!
//! In contrast with the `new_unchecked` methods, the `new` methods require the user
//! pass a tuple as the `pins` argument. In a HAL, you can mark which types are
//! suitable as follows:
//!
//! ```rust
//! # pub use core::marker::PhantomData;
//! # struct AF12 {}
//! # struct Alternate<AF> { _af: PhantomData<AF> }
//! # mod gpiof { pub use core::marker::PhantomData; pub struct PF0<A> { _a: PhantomData<A> } }
//! impl stm32_fmc::A0 for gpiof::PF0<Alternate<AF12>> {}
//! // ...
//! ```
//!
#![no_std]
// rustc lints.
#![warn(
bare_trait_objects,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_qualifications,
unused_results
)]
#[macro_use]
mod macros;
mod fmc;
pub use fmc::*;
#[cfg(feature = "sdram")]
mod sdram;
#[cfg(feature = "sdram")]
pub use sdram::{
PinsSdram, Sdram, SdramChip, SdramConfiguration, SdramPinSet,
SdramTargetBank, SdramTiming,
};
#[cfg(feature = "nand")]
mod nand;
#[cfg(feature = "nand")]
pub use nand::device as nand_device;
#[cfg(feature = "nand")]
pub use nand::{Nand, NandChip, NandConfiguration, NandTiming, PinsNand};
/// Memory device definitions
pub mod devices;
mod ral;
/// A trait for device-specific FMC peripherals. Implement this to add support
/// for a new hardware platform. Peripherals that have this trait must have the
/// same register block as STM32 FMC peripherals.
pub unsafe trait FmcPeripheral: Send {
/// Pointer to the register block
const REGISTERS: *const ();
/// Enables the FMC on its peripheral bus
fn enable(&mut self);
/// Enables the FMC memory controller (not always required)
fn memory_controller_enable(&mut self) {}
/// The frequency of the clock used as a source for the fmc_clk.
///
/// F4/F7/G4: hclk
/// H7: fmc_ker_ck
fn source_clock_hz(&self) -> u32;
}