alt_stm32f30x_hal/
spi.rs

1//! Serial Peripheral Interface (SPI) bus
2
3use core::ptr;
4
5use crate::pac::{RCC, SPI1, SPI2, SPI3};
6use hal::spi::{FullDuplex, Mode, Phase, Polarity};
7use nb;
8
9use crate::gpio::{AltFn, PullType, AF5, AF6};
10use crate::gpio::{HighSpeed, PinMode, PushPull};
11use crate::gpio::{PA5, PA6, PA7};
12use crate::gpio::{PB13, PB14, PB15, PB3, PB4, PB5};
13use crate::gpio::{PC10, PC11, PC12};
14use crate::rcc::Clocks;
15use crate::time::Hertz;
16
17/// SPI error
18#[derive(Debug)]
19pub enum Error {
20    /// Overrun occurred
21    Overrun,
22    /// Mode fault occurred
23    ModeFault,
24    /// CRC error
25    Crc,
26    #[doc(hidden)]
27    _Extensible,
28}
29
30/// SPI peripheral operating in full duplex master mode
31pub struct Spi<SPI, PINS> {
32    spi: SPI,
33    pins: PINS,
34}
35
36/// SPI extension for SPI
37pub trait SpiExt<SPI, ISCK, IMISO, IMOSI, SCK, MISO, MOSI> {
38    /// Configures the SPI peripheral to operate in full duplex master mode.
39    /// Consumes SPI peripheral and triple of (SCK, MISO, MOSI) pins.
40    /// Returns [`Spi`].
41    ///
42    /// [`Spi`]: ./struct.Spi.html
43    fn spi<F>(self,
44              pins: (ISCK, IMISO, IMOSI),
45              mode: Mode,
46              freq: F,
47              clocks: Clocks)
48              -> Spi<SPI, (SCK, MISO, MOSI)>
49        where F: Into<Hertz<u32>>;
50}
51
52#[cfg_attr(rustfmt, rustfmt_skip)]
53macro_rules! spi {
54    ($SPIX:ident,
55     $apbenr:ident,
56     $apbrstr:ident,
57     $spiXen:ident,
58     $spiXrst:ident,
59     $pclkX:ident,
60     $afn:ident,
61     $speed:ident,
62     sck: [$($sck: ident, )+],
63     miso: $miso: tt,
64     mosi: $mosi: tt
65    ) => {
66        spi!{
67            $SPIX,
68            $apbenr,
69            $apbrstr,
70            $spiXen,
71            $spiXrst,
72            $pclkX,
73            $afn,
74            $speed,
75            [$(
76                ($sck, $miso, ),
77            )+],
78            $mosi
79        }
80    };
81    ($SPIX:ident,
82     $apbenr:ident,
83     $apbrstr:ident,
84     $spiXen:ident,
85     $spiXrst:ident,
86     $pclkX:ident,
87     $afn:ident,
88     $speed:ident,
89     [$(($sck: ident,
90         [$($miso: ident, )+], ),
91     )+],
92     $mosi: tt
93    ) => {
94        spi!{
95            $SPIX,
96            $apbenr,
97            $apbrstr,
98            $spiXen,
99            $spiXrst,
100            $pclkX,
101            $afn,
102            $speed,
103            [$(
104                ($sck,
105                 [$(
106                     ($miso, $mosi),
107                 )+]),
108            )+]
109        }
110    };
111    ($SPIX:ident,
112     $apbenr:ident,
113     $apbrstr:ident,
114     $spiXen:ident,
115     $spiXrst:ident,
116     $pclkX:ident,
117     $afn:ident,
118     $speed:ident,
119     [$(($sck: ident,
120         [$(($miso: ident, [$($mosi: ident,)+]), )+]
121     ), )+]
122    ) => {
123        $(
124            $(
125                $(
126                    impl<PT: PullType, PM: PinMode>
127                        SpiExt<$SPIX,
128                    $sck<PT, PM>,
129                    $miso<PT, PM>,
130                    $mosi<PT, PM>,
131                    $sck<PT, AltFn<$afn, PushPull, $speed>>,
132                    $miso<PT, AltFn<$afn, PushPull, $speed>>,
133                    $mosi<PT, AltFn<$afn, PushPull, $speed>>> for $SPIX
134                    {
135                        fn spi<F>(
136                            self,
137                            pins: ($sck<PT, PM>, $miso<PT, PM>, $mosi<PT, PM>),
138                            mode: Mode,
139                            freq: F,
140                            clocks: Clocks)
141                            -> Spi<$SPIX,
142                        ($sck<PT, AltFn<$afn, PushPull, $speed>>,
143                         $miso<PT, AltFn<$afn, PushPull, $speed>>,
144                         $mosi<PT, AltFn<$afn, PushPull, $speed>>)>
145                        where F: Into<Hertz<u32>>
146                        {
147                            let outpins = (pins.0.alternating($afn).output_speed($speed),
148                                           pins.1.alternating($afn).output_speed($speed),
149                                           pins.2.alternating($afn).output_speed($speed));
150                            let apbenr = unsafe { &(*RCC::ptr()).$apbenr };
151                            let apbrstr = unsafe { &(*RCC::ptr()).$apbrstr };
152                            // enable or reset $SPIX
153                            apbenr.modify(|_, w| w.$spiXen().enabled());
154                            apbrstr.modify(|_, w| w.$spiXrst().set_bit());
155                            apbrstr.modify(|_, w| w.$spiXrst().clear_bit());
156
157                            // FRXTH: RXNE event is generated if the FIFO level is greater
158                            // than or equal to        8-bit
159                            // DS: 8-bit data size
160                            // SSOE: Slave Select output disabled
161                            self.cr2.write(|w| unsafe {
162                                w.frxth()
163                                    .set_bit()
164                                    .ds()
165                                    .bits(0b111)
166                                    .ssoe()
167                                    .clear_bit()
168                            });
169
170                            let br = match clocks.$pclkX().0 / freq.into().0 {
171                                0 => unreachable!(),
172                                1..=2 => 0b000,
173                                3..=5 => 0b001,
174                                6..=11 => 0b010,
175                                12..=23 => 0b011,
176                                24..=39 => 0b100,
177                                40..=95 => 0b101,
178                                96..=191 => 0b110,
179                                _ => 0b111,
180                            };
181
182                            // CPHA: phase
183                            // CPOL: polarity
184                            // MSTR: master mode
185                            // BR: 1 MHz
186                            // SPE: SPI disabled
187                            // LSBFIRST: MSB first
188                            // SSM: enable software slave management (NSS pin free for
189                            // other uses) SSI: set nss high = master mode
190                            // CRCEN: hardware CRC calculation disabled
191                            // BIDIMODE: 2 line unidirectional (full duplex)
192                            self.cr1.write(|w|
193                                w.cpha()
194                                    .bit(mode.phase
195                                         == Phase::CaptureOnSecondTransition)
196                                    .cpol()
197                                    .bit(mode.polarity == Polarity::IdleHigh)
198                                    .mstr()
199                                    .set_bit()
200                                    .br()
201                                    .bits(br)
202                                    .spe()
203                                    .set_bit()
204                                    .lsbfirst()
205                                    .clear_bit()
206                                    .ssi()
207                                    .set_bit()
208                                    .ssm()
209                                    .set_bit()
210                                    .crcen()
211                                    .clear_bit()
212                                    .bidimode()
213                                    .clear_bit()
214                            );
215
216                            Spi { spi: self,
217                                  pins: outpins, }
218                        }
219                    }
220                )+
221            )+
222        )+
223
224        impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
225            /// Releases the SPI peripheral and associated pins
226            pub fn free(self) -> ($SPIX, (SCK, MISO, MOSI)) {
227                (self.spi, self.pins)
228            }
229        }
230
231        impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
232            type Error = Error;
233
234            fn read(&mut self) -> nb::Result<u8, Error> {
235                let sr = self.spi.sr.read();
236
237                Err(if sr.ovr().bit_is_set() {
238                    nb::Error::Other(Error::Overrun)
239                } else if sr.modf().bit_is_set() {
240                    nb::Error::Other(Error::ModeFault)
241                } else if sr.crcerr().bit_is_set() {
242                    nb::Error::Other(Error::Crc)
243                } else if sr.rxne().bit_is_set() {
244                    // NOTE(read_volatile) read only 1 byte (the svd2rust API
245                    // only allows reading a half-word)
246                    return Ok(unsafe {
247                        ptr::read_volatile(&self.spi.dr as *const _
248                                           as *const u8)
249                    });
250                } else {
251                    nb::Error::WouldBlock
252                })
253            }
254
255            fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
256                let sr = self.spi.sr.read();
257
258                Err(if sr.ovr().bit_is_set() {
259                    nb::Error::Other(Error::Overrun)
260                } else if sr.modf().bit_is_set() {
261                    nb::Error::Other(Error::ModeFault)
262                } else if sr.crcerr().bit_is_set() {
263                    nb::Error::Other(Error::Crc)
264                } else if sr.txe().bit_is_set() {
265                    // NOTE(write_volatile) see note above
266                    unsafe {
267                        ptr::write_volatile(&self.spi.dr as *const _ as *mut u8,
268                                            byte)
269                    }
270                    return Ok(());
271                } else {
272                    nb::Error::WouldBlock
273                })
274            }
275        }
276
277        impl<PINS> ::hal::blocking::spi::transfer::Default<u8>
278            for Spi<$SPIX, PINS>
279        {}
280
281        impl<PINS> ::hal::blocking::spi::write::Default<u8>
282            for Spi<$SPIX, PINS>
283        {}
284    };
285}
286
287//// DEFINE traits for Spi1Sck, Spi1Miso or, even better Sck<dev = SPI1>
288
289spi!(SPI1,
290     apb2enr,
291     apb2rstr,
292     spi1en,
293     spi1rst,
294     pclk2,
295     AF5,
296     HighSpeed,
297     sck: [PA5, PB3,],
298     miso: [PA6, PB4,],
299     mosi: [PA7, PB5,]);
300
301spi!(SPI2,
302     apb1enr,
303     apb1rstr,
304     spi2en,
305     spi2rst,
306     pclk1,
307     AF5,
308     HighSpeed,
309     sck: [PB13,],
310     miso: [PB14,],
311     mosi: [PB15,]);
312spi!(SPI3,
313     apb1enr,
314     apb1rstr,
315     spi3en,
316     spi3rst,
317     pclk1,
318     AF6,
319     HighSpeed,
320     sck: [PB3, PC10,],
321     miso: [PB4, PC11,],
322     mosi: [PB5, PC12,]);