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 | |