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