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
//! 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` (todo), ..) 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,
};

/// 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;
}