lpc55_hal/peripherals/
flexcomm.rs

1use core::ops::Deref;
2
3use crate::{
4    peripherals::syscon,
5    raw,
6    typestates::{
7        init_state,
8        pin::flexcomm::{I2c, I2s, Spi, Usart},
9        ClocksSupportFlexcommToken,
10    },
11};
12
13pub type Flexcomm = (
14    Flexcomm0,
15    Flexcomm1,
16    Flexcomm2,
17    Flexcomm3,
18    Flexcomm4,
19    Flexcomm5,
20    Flexcomm6,
21    Flexcomm7,
22    Flexcomm8,
23);
24
25macro_rules! flexcomm {
26    ($fc_hal:ident, $i2c_hal:ident, $i2s_hal:ident, $spi_hal:ident, $usart_hal:ident,
27     $fc_pac:ident, $i2c_pac:ident, $i2s_pac:ident, $spi_pac:ident, $usart_pac:ident,
28     $register_sel:ident
29    ) => {
30        pub struct $fc_hal<State = init_state::Unknown> {
31            pub(crate) raw_fc: raw::$fc_pac,
32            pub(crate) raw_i2c: raw::$i2c_pac,
33            pub(crate) raw_i2s: raw::$i2s_pac,
34            pub(crate) raw_spi: raw::$spi_pac,
35            pub(crate) raw_usart: raw::$usart_pac,
36            pub _state: State,
37        }
38
39        pub struct $i2c_hal<State = init_state::Enabled> {
40            pub(crate) _raw_fc: raw::$fc_pac,
41            #[allow(dead_code)]
42            pub(crate) raw: raw::$i2c_pac,
43            pub(crate) _raw_i2s: raw::$i2s_pac,
44            pub(crate) _raw_spi: raw::$spi_pac,
45            pub(crate) _raw_usart: raw::$usart_pac,
46            pub _state: State,
47        }
48
49        impl Deref for $i2c_hal {
50            type Target = raw::i2c0::RegisterBlock;
51            fn deref(&self) -> &Self::Target {
52                &self.raw
53            }
54        }
55
56        impl I2c for $i2c_hal {}
57
58        pub struct $i2s_hal<State = init_state::Enabled> {
59            pub(crate) _raw_fc: raw::$fc_pac,
60            pub(crate) _raw_i2c: raw::$i2c_pac,
61            #[allow(dead_code)]
62            pub(crate) raw: raw::$i2s_pac,
63            pub(crate) _raw_spi: raw::$spi_pac,
64            pub(crate) _raw_usart: raw::$usart_pac,
65            pub _state: State,
66        }
67
68        impl I2s for $i2s_hal {}
69
70        pub struct $spi_hal<State = init_state::Enabled> {
71            pub(crate) _raw_fc: raw::$fc_pac,
72            pub(crate) _raw_i2c: raw::$i2c_pac,
73            pub(crate) _raw_i2s: raw::$i2s_pac,
74            #[allow(dead_code)]
75            pub(crate) raw: raw::$spi_pac,
76            pub(crate) _raw_usart: raw::$usart_pac,
77            pub _state: State,
78        }
79
80        impl Deref for $spi_hal {
81            type Target = raw::spi0::RegisterBlock;
82            fn deref(&self) -> &Self::Target {
83                &self.raw
84            }
85        }
86
87        impl Spi for $spi_hal {}
88
89        pub struct $usart_hal<State = init_state::Enabled> {
90            pub(crate) _raw_fc: raw::$fc_pac,
91            pub(crate) _raw_i2c: raw::$i2c_pac,
92            pub(crate) _raw_i2s: raw::$i2s_pac,
93            pub(crate) _raw_spi: raw::$spi_pac,
94            #[allow(dead_code)]
95            pub(crate) raw: raw::$usart_pac,
96            pub _state: State,
97        }
98
99        impl Deref for $usart_hal {
100            type Target = raw::usart0::RegisterBlock;
101            fn deref(&self) -> &Self::Target {
102                &self.raw
103            }
104        }
105
106        impl Usart for $usart_hal {}
107
108        impl
109            core::convert::From<(
110                raw::$fc_pac,
111                raw::$i2c_pac,
112                raw::$i2s_pac,
113                raw::$spi_pac,
114                raw::$usart_pac,
115            )> for $fc_hal
116        {
117            fn from(
118                raw: (
119                    raw::$fc_pac,
120                    raw::$i2c_pac,
121                    raw::$i2s_pac,
122                    raw::$spi_pac,
123                    raw::$usart_pac,
124                ),
125            ) -> Self {
126                $fc_hal::new(raw)
127            }
128        }
129
130        impl $fc_hal {
131            fn new(
132                raw: (
133                    raw::$fc_pac,
134                    raw::$i2c_pac,
135                    raw::$i2s_pac,
136                    raw::$spi_pac,
137                    raw::$usart_pac,
138                ),
139            ) -> Self {
140                $fc_hal {
141                    raw_fc: raw.0,
142                    raw_i2c: raw.1,
143                    raw_i2s: raw.2,
144                    raw_spi: raw.3,
145                    raw_usart: raw.4,
146                    _state: init_state::Unknown,
147                }
148            }
149
150            // pub unsafe fn steal() -> Self {
151            //     // seems a little wastefule to steal the full peripherals but ok..
152            //     Self::new(raw::Peripherals::steal().$pac_name)
153            // }
154        }
155
156        impl<State> $fc_hal<State> {
157            pub fn release(
158                self,
159            ) -> (
160                raw::$fc_pac,
161                raw::$i2c_pac,
162                raw::$i2s_pac,
163                raw::$spi_pac,
164                raw::$usart_pac,
165            ) {
166                (
167                    self.raw_fc,
168                    self.raw_i2c,
169                    self.raw_i2s,
170                    self.raw_spi,
171                    self.raw_usart,
172                )
173            }
174        }
175
176        impl $fc_hal {
177            fn enabled(&mut self, syscon: &mut syscon::Syscon) {
178                syscon.reset(&mut self.raw_fc);
179                syscon.enable_clock(&mut self.raw_fc);
180            }
181
182            pub fn enabled_as_i2c(
183                mut self,
184                syscon: &mut syscon::Syscon,
185                _clocks_token: &ClocksSupportFlexcommToken,
186            ) -> $i2c_hal<init_state::Enabled> {
187                // The FRG output frequency must not be higher than 48 MHz for SPI and I2S
188                // and not higher than 44 MHz for USART and I2C.
189                //
190                // Currently, we just use the 12MHz clock
191
192                syscon.raw.$register_sel().modify(|_, w| w.sel().enum_0x2()); // Fro12MHz
193
194                self.enabled(syscon);
195
196                self.raw_fc.pselid.modify(|_, w| {
197                    w
198                        // select I2C function on corresponding FLEXCOMM
199                        .persel()
200                        .i2c()
201                        // lock it
202                        .lock()
203                        .locked()
204                });
205                assert!(self.raw_fc.pselid.read().i2cpresent().is_present());
206
207                $i2c_hal {
208                    _raw_fc: self.raw_fc,
209                    raw: self.raw_i2c,
210                    _raw_i2s: self.raw_i2s,
211                    _raw_spi: self.raw_spi,
212                    _raw_usart: self.raw_usart,
213                    _state: init_state::Enabled(()),
214                }
215            }
216
217            pub fn enabled_as_spi(
218                mut self,
219                syscon: &mut syscon::Syscon,
220                _clocks_token: &ClocksSupportFlexcommToken,
221            ) -> $spi_hal<init_state::Enabled> {
222                // The FRG output frequency must not be higher than 48 MHz for SPI and I2S
223                // and not higher than 44 MHz for USART and I2C.
224                //
225                // Currently, we just use the 12MHz clock
226
227                syscon.raw.$register_sel().modify(|_, w| w.sel().enum_0x2()); // Fro12MHz
228
229                self.enabled(syscon);
230
231                self.raw_fc.pselid.modify(|_, w| {
232                    w
233                        // select SPI function on corresponding FLEXCOMM
234                        .persel()
235                        .spi()
236                        // lock it
237                        .lock()
238                        .locked()
239                });
240                assert!(self.raw_fc.pselid.read().spipresent().is_present());
241
242                $spi_hal {
243                    _raw_fc: self.raw_fc,
244                    _raw_i2c: self.raw_i2c,
245                    _raw_i2s: self.raw_i2s,
246                    raw: self.raw_spi,
247                    _raw_usart: self.raw_usart,
248                    _state: init_state::Enabled(()),
249                }
250            }
251
252            pub fn enabled_as_usart(
253                mut self,
254                syscon: &mut syscon::Syscon,
255                _clocks_token: &ClocksSupportFlexcommToken,
256            ) -> $usart_hal<init_state::Enabled> {
257                // The FRG output frequency must not be higher than 48 MHz for SPI and I2S
258                // and not higher than 44 MHz for USART and I2C.
259                //
260                // Currently, we just use the 12MHz clock
261
262                syscon.raw.$register_sel().modify(|_, w| w.sel().enum_0x2()); // Fro12MHz
263
264                self.enabled(syscon);
265
266                self.raw_fc.pselid.modify(|_, w| {
267                    w
268                        // select USART function on corresponding FLEXCOMM
269                        .persel()
270                        .usart()
271                        // lock it
272                        .lock()
273                        .locked()
274                });
275                assert!(self.raw_fc.pselid.read().usartpresent().is_present());
276
277                $usart_hal {
278                    _raw_fc: self.raw_fc,
279                    _raw_i2c: self.raw_i2c,
280                    _raw_i2s: self.raw_i2s,
281                    _raw_spi: self.raw_spi,
282                    raw: self.raw_usart,
283                    _state: init_state::Enabled(()),
284                }
285            }
286        }
287    };
288}
289
290flexcomm!(Flexcomm0, I2c0, I2s0, Spi0, Usart0, FLEXCOMM0, I2C0, I2S0, SPI0, USART0, fcclksel0);
291flexcomm!(Flexcomm1, I2c1, I2s1, Spi1, Usart1, FLEXCOMM1, I2C1, I2S1, SPI1, USART1, fcclksel1);
292flexcomm!(Flexcomm2, I2c2, I2s2, Spi2, Usart2, FLEXCOMM2, I2C2, I2S2, SPI2, USART2, fcclksel2);
293flexcomm!(Flexcomm3, I2c3, I2s3, Spi3, Usart3, FLEXCOMM3, I2C3, I2S3, SPI3, USART3, fcclksel3);
294flexcomm!(Flexcomm4, I2c4, I2s4, Spi4, Usart4, FLEXCOMM4, I2C4, I2S4, SPI4, USART4, fcclksel4);
295flexcomm!(Flexcomm5, I2c5, I2s5, Spi5, Usart5, FLEXCOMM5, I2C5, I2S5, SPI5, USART5, fcclksel5);
296flexcomm!(Flexcomm6, I2c6, I2s6, Spi6, Usart6, FLEXCOMM6, I2C6, I2S6, SPI6, USART6, fcclksel6);
297flexcomm!(Flexcomm7, I2c7, I2s7, Spi7, Usart7, FLEXCOMM7, I2C7, I2S7, SPI7, USART7, fcclksel7);
298
299pub struct Flexcomm8<State = init_state::Unknown> {
300    pub(crate) raw_fc: raw::FLEXCOMM8,
301    pub(crate) raw_spi: raw::SPI8,
302    pub _state: State,
303}
304
305pub struct Spi8<State = init_state::Enabled> {
306    pub(crate) _raw_fc: raw::FLEXCOMM8,
307    #[allow(dead_code)]
308    pub(crate) raw: raw::SPI8,
309    pub _state: State,
310}
311
312impl Deref for Spi8 {
313    type Target = raw::spi0::RegisterBlock;
314    fn deref(&self) -> &Self::Target {
315        &self.raw
316    }
317}
318
319impl Spi for Spi8 {}
320
321impl core::convert::From<(raw::FLEXCOMM8, raw::SPI8)> for Flexcomm8 {
322    fn from(raw: (raw::FLEXCOMM8, raw::SPI8)) -> Self {
323        Flexcomm8::new(raw)
324    }
325}
326
327impl Flexcomm8 {
328    fn new(raw: (raw::FLEXCOMM8, raw::SPI8)) -> Self {
329        Flexcomm8 {
330            raw_fc: raw.0,
331            raw_spi: raw.1,
332            _state: init_state::Unknown,
333        }
334    }
335}
336
337impl<State> Flexcomm8<State> {
338    pub fn release(self) -> (raw::FLEXCOMM8, raw::SPI8) {
339        (self.raw_fc, self.raw_spi)
340    }
341}
342
343impl Flexcomm8 {
344    fn enabled(&mut self, syscon: &mut syscon::Syscon) {
345        syscon.reset(&mut self.raw_fc);
346        syscon.enable_clock(&mut self.raw_fc);
347    }
348
349    pub fn enabled_as_spi(
350        mut self,
351        syscon: &mut syscon::Syscon,
352        _clocks_token: &ClocksSupportFlexcommToken,
353    ) -> Spi8<init_state::Enabled> {
354        // NB: This is the high-speed SPI
355
356        // The FRG output frequency must not be higher than 48 MHz for SPI and I2S
357        // and not higher than 44 MHz for USART and I2C.
358        //
359        // Currently, we just use the 12MHz clock
360
361        syscon.raw.hslspiclksel.modify(|_, w| w.sel().enum_0x2()); // Fro12MHz
362
363        self.enabled(syscon);
364
365        self.raw_fc.pselid.modify(|_, w| {
366            w
367                // select SPI function on corresponding FLEXCOMM
368                .persel()
369                .spi()
370                // lock it
371                .lock()
372                .locked()
373        });
374        assert!(self.raw_fc.pselid.read().spipresent().is_present());
375
376        Spi8 {
377            _raw_fc: self.raw_fc,
378            raw: self.raw_spi,
379            _state: init_state::Enabled(()),
380        }
381    }
382}