stm32f4xx_hal/fsmc_lcd/
pins.rs

1//! Pin definitions for the Flexible Static Memory Controller / Flexible Memory Controller
2//!
3//! Note: This file only includes pins for these functions:
4//! * NOE (read enable)
5//! * NWE (write enable)
6//! * NEx (chip select)
7//! * Ax (address)
8//! * Dx (data 0 through 15)
9//!
10//! # Naming conventions
11//!
12//! For signal names, this module uses:
13//! * Chip select instead of enable
14//! * Address instead of data/command
15//! * Read enable instead of output enable
16//! * Write enable
17
18use core::marker::PhantomData;
19
20use crate::gpio::alt::fmc as alt;
21
22use super::sealed;
23use super::{Lcd, SubBank1, Word};
24use crate::fsmc_lcd::{SubBank2, SubBank3, SubBank4};
25
26/// One, two, three, or four address pins
27pub trait AddressPins: sealed::Sealed {}
28
29// Implement AddressPins for one address pin and tuples of two, three, and four
30impl AddressPins for alt::Address {}
31impl AddressPins for (alt::Address, alt::Address) {}
32impl sealed::Sealed for (alt::Address, alt::Address) {}
33impl AddressPins for (alt::Address, alt::Address, alt::Address) {}
34impl sealed::Sealed for (alt::Address, alt::Address, alt::Address) {}
35impl AddressPins for (alt::Address, alt::Address, alt::Address, alt::Address) {}
36impl sealed::Sealed for (alt::Address, alt::Address, alt::Address, alt::Address) {}
37
38macro_rules! conjure {
39    ($($($sb:ident),+;)+) => {
40        $(
41            #[allow(unused_parens)]
42            impl<WORD: Word> sealed::Conjure for ($(Lcd<$sb, WORD>),+) {
43                fn conjure() -> Self {
44                    ($(Lcd::<$sb, WORD>::new()),+)
45                }
46            }
47        )+
48    };
49}
50
51// Implement Conjure for all non-empty subsets of Lcds
52conjure! {
53    SubBank1;
54    SubBank2;
55    SubBank3;
56    SubBank4;
57    SubBank1, SubBank2;
58    SubBank1, SubBank3;
59    SubBank1, SubBank4;
60    SubBank2, SubBank3;
61    SubBank2, SubBank4;
62    SubBank3, SubBank4;
63    SubBank1, SubBank2, SubBank3;
64    SubBank1, SubBank2, SubBank4;
65    SubBank1, SubBank3, SubBank4;
66    SubBank2, SubBank3, SubBank4;
67    SubBank1, SubBank2, SubBank3, SubBank4;
68}
69
70/// One, two, three, or four chip select pins
71///
72/// Due to trait system limitations, this trait is only implemented for pins wrapped in the
73/// `ChipSelect1`, `ChipSelect2`, `ChipSelect3`, and `ChipSelect4` wrappers.
74///
75/// This trait is implemented for all non-empty subsets of the 4 possible chip select signals.
76/// The pins must be in order.
77///
78/// # Example types that implement `ChipSelectPins`
79///
80/// Wrapped single pins:
81/// * `ChipSelect1<PD7<Alternate<12>>>`
82/// * `ChipSelect2<PG9<Alternate<12>>>`
83/// * `ChipSelect3<PG10<Alternate<12>>>`
84/// * `ChipSelect4<PG12<Alternate<12>>>`
85///
86/// Tuples of wrapped pins:
87/// * `(ChipSelect1<PD7<Alternate<12>>>, ChipSelect2<PG9<Alternate<12>>>)`
88/// * `(ChipSelect1<PD7<Alternate<12>>>, ChipSelect4<PG4<Alternate<12>>>)`
89/// * `(ChipSelect1<PD7<Alternate<12>>>, ChipSelect2<PG9<Alternate<12>>>, ChipSelect3<PG10<Alternate<12>>>, ChipSelect4<PG12<Alternate<12>>>)`
90pub trait ChipSelectPins: sealed::Sealed {
91    /// One, two, three, or four `Lcd<_>` objects associated with the sub-bank(s) that these pin(s)
92    /// control
93    type Lcds<WORD: Word>: sealed::Conjure;
94}
95
96// The set of 4 chip selects has 15 subsets (excluding the empty set):
97// 1
98// 2
99// 3
100// 4
101// 1, 2
102// 1, 3
103// 1, 4
104// 2, 3
105// 2, 4
106// 3, 4
107// 1, 2, 3
108// 1, 2, 4
109// 1, 3, 4
110// 2, 3, 4
111// 1, 2, 3, 4
112
113macro_rules! chipselect {
114    ($($([$sb:ident, $Ne:ident, $i:tt]),+;)+) => {
115        $(
116            impl ChipSelectPins for ($(alt::$Ne),+) {
117                type Lcds<WORD: Word> = ($(Lcd<$sb, WORD>),+);
118            }
119            impl sealed::Sealed for ($(alt::$Ne),+) {}
120        )+
121    };
122}
123
124impl ChipSelectPins for alt::Ne1 {
125    type Lcds<WORD: Word> = Lcd<SubBank1, WORD>;
126}
127impl ChipSelectPins for alt::Ne2 {
128    type Lcds<WORD: Word> = Lcd<SubBank2, WORD>;
129}
130impl ChipSelectPins for alt::Ne3 {
131    type Lcds<WORD: Word> = Lcd<SubBank3, WORD>;
132}
133impl ChipSelectPins for alt::Ne4 {
134    type Lcds<WORD: Word> = Lcd<SubBank4, WORD>;
135}
136chipselect! {
137    [SubBank1, Ne1, 0], [SubBank2, Ne2, 1];
138    [SubBank1, Ne1, 0], [SubBank3, Ne3, 1];
139    [SubBank1, Ne1, 0], [SubBank4, Ne4, 1];
140    [SubBank2, Ne2, 0], [SubBank3, Ne3, 1];
141    [SubBank2, Ne2, 0], [SubBank4, Ne4, 1];
142    [SubBank3, Ne3, 0], [SubBank4, Ne4, 1];
143    [SubBank1, Ne1, 0], [SubBank2, Ne2, 1], [SubBank3, Ne3, 2];
144    [SubBank1, Ne1, 0], [SubBank2, Ne2, 1], [SubBank4, Ne4, 2];
145    [SubBank1, Ne1, 0], [SubBank3, Ne3, 1], [SubBank4, Ne4, 2];
146    [SubBank2, Ne2, 0], [SubBank3, Ne3, 1], [SubBank4, Ne4, 2];
147    [SubBank1, Ne1, 0], [SubBank2, Ne2, 1], [SubBank3, Ne3, 2], [SubBank4, Ne4, 3];
148}
149
150/// A set of data pins
151///
152/// `WORD` is `u8` or `u16`
153pub trait DataPins<WORD: Word>: sealed::Sealed {}
154
155#[allow(unused)]
156pub struct DataPins16 {
157    pub d0: alt::D0,
158    pub d1: alt::D1,
159    pub d2: alt::D2,
160    pub d3: alt::D3,
161    pub d4: alt::D4,
162    pub d5: alt::D5,
163    pub d6: alt::D6,
164    pub d7: alt::D7,
165    pub d8: alt::D8,
166    pub d9: alt::D9,
167    pub d10: alt::D10,
168    pub d11: alt::D11,
169    pub d12: alt::D12,
170    pub d13: alt::D13,
171    pub d14: alt::D14,
172    pub d15: alt::D15,
173}
174
175impl DataPins<u16> for DataPins16 {}
176
177impl DataPins16 {
178    #[allow(clippy::too_many_arguments)]
179    #[inline(always)]
180    pub fn new(
181        d0: impl Into<alt::D0>,
182        d1: impl Into<alt::D1>,
183        d2: impl Into<alt::D2>,
184        d3: impl Into<alt::D3>,
185        d4: impl Into<alt::D4>,
186        d5: impl Into<alt::D5>,
187        d6: impl Into<alt::D6>,
188        d7: impl Into<alt::D7>,
189        d8: impl Into<alt::D8>,
190        d9: impl Into<alt::D9>,
191        d10: impl Into<alt::D10>,
192        d11: impl Into<alt::D11>,
193        d12: impl Into<alt::D12>,
194        d13: impl Into<alt::D13>,
195        d14: impl Into<alt::D14>,
196        d15: impl Into<alt::D15>,
197    ) -> Self {
198        Self {
199            d0: d0.into(),
200            d1: d1.into(),
201            d2: d2.into(),
202            d3: d3.into(),
203            d4: d4.into(),
204            d5: d5.into(),
205            d6: d6.into(),
206            d7: d7.into(),
207            d8: d8.into(),
208            d9: d9.into(),
209            d10: d10.into(),
210            d11: d11.into(),
211            d12: d12.into(),
212            d13: d13.into(),
213            d14: d14.into(),
214            d15: d15.into(),
215        }
216    }
217}
218impl sealed::Sealed for DataPins16 {}
219
220#[allow(unused)]
221pub struct DataPins8 {
222    pub d0: alt::D0,
223    pub d1: alt::D1,
224    pub d2: alt::D2,
225    pub d3: alt::D3,
226    pub d4: alt::D4,
227    pub d5: alt::D5,
228    pub d6: alt::D6,
229    pub d7: alt::D7,
230}
231
232impl DataPins<u8> for DataPins8 {}
233
234impl DataPins8 {
235    #[allow(clippy::too_many_arguments)]
236    #[inline(always)]
237    pub fn new(
238        d0: impl Into<alt::D0>,
239        d1: impl Into<alt::D1>,
240        d2: impl Into<alt::D2>,
241        d3: impl Into<alt::D3>,
242        d4: impl Into<alt::D4>,
243        d5: impl Into<alt::D5>,
244        d6: impl Into<alt::D6>,
245        d7: impl Into<alt::D7>,
246    ) -> Self {
247        Self {
248            d0: d0.into(),
249            d1: d1.into(),
250            d2: d2.into(),
251            d3: d3.into(),
252            d4: d4.into(),
253            d5: d5.into(),
254            d6: d6.into(),
255            d7: d7.into(),
256        }
257    }
258
259    pub fn split(
260        self,
261    ) -> (
262        alt::D0,
263        alt::D1,
264        alt::D2,
265        alt::D3,
266        alt::D4,
267        alt::D5,
268        alt::D6,
269        alt::D7,
270    ) {
271        (
272            self.d0, self.d1, self.d2, self.d3, self.d4, self.d5, self.d6, self.d7,
273        )
274    }
275}
276impl sealed::Sealed for DataPins8 {}
277
278/// A set of pins used to interface with an LCD
279///
280/// The `address` and `enable` fields can be individual pins, or tuples of 2, 3, or 4 pins.
281#[allow(unused)]
282pub struct LcdPins<D, AD, NE, WORD> {
283    /// The 16-bit data bus
284    pub data: D,
285    /// Address pin(s) (data/command)
286    pub address: AD,
287    /// Output enable (read enable)
288    pub read_enable: alt::Noe,
289    /// Write enable
290    pub write_enable: alt::Nwe,
291    /// Chip select / bank enable pin(s)
292    pub chip_select: NE,
293    _word: PhantomData<WORD>,
294}
295
296impl<D, AD, NE, WORD> LcdPins<D, AD, NE, WORD>
297where
298    D: DataPins<WORD>,
299    AD: AddressPins,
300    NE: ChipSelectPins,
301    WORD: Word,
302{
303    pub fn new(
304        data: D,
305        address: AD,
306        read_enable: impl Into<alt::Noe>,
307        write_enable: impl Into<alt::Nwe>,
308        chip_select: NE,
309    ) -> Self {
310        Self {
311            data,
312            address,
313            read_enable: read_enable.into(),
314            write_enable: write_enable.into(),
315            chip_select,
316            _word: PhantomData,
317        }
318    }
319    pub fn split(self) -> (D, AD, alt::Noe, alt::Nwe, NE) {
320        (
321            self.data,
322            self.address,
323            self.read_enable,
324            self.write_enable,
325            self.chip_select,
326        )
327    }
328}
329
330/// A set of pins that can be used with the FSMC
331///
332/// This trait is implemented for the `LcdPins` struct that contains 16 data pins, 1 through 4
333/// address pins, 1 through 4 chip select / bank enable pins, an output enable pin, and a write
334/// enable pin.
335pub trait Pins<WORD: Word>: sealed::Sealed {
336    /// One, two, three, or four `Lcd<_>` objects associated with the sub-bank(s) that the chip
337    /// select pin pin(s) control
338    type Lcds: sealed::Conjure;
339}
340
341impl<D, AD, NE, WORD> Pins<WORD> for LcdPins<D, AD, NE, WORD>
342where
343    D: DataPins<WORD>,
344    AD: AddressPins,
345    NE: ChipSelectPins,
346    WORD: Word,
347{
348    type Lcds = NE::Lcds<WORD>;
349}
350
351impl<D, AD, NE, WORD> sealed::Sealed for LcdPins<D, AD, NE, WORD>
352where
353    D: DataPins<WORD>,
354    AD: AddressPins,
355    NE: ChipSelectPins,
356    WORD: Word,
357{
358}