stm32f30x_hal/
spi.rs

1//! Serial Peripheral Interface (SPI) bus
2
3use core::ptr;
4
5use hal::spi::{FullDuplex, Mode, Phase, Polarity};
6use nb;
7use stm32f30x::{SPI1, SPI2, SPI3};
8
9use gpio::gpioa::{PA5, PA6, PA7};
10use gpio::gpiob::{PB13, PB14, PB15, PB5};
11use gpio::gpioc::{PC10, PC11, PC12};
12use gpio::{AF5, AF6};
13use rcc::{APB1, APB2, Clocks};
14use time::Hertz;
15
16/// SPI error
17#[derive(Debug)]
18pub enum Error {
19    /// Overrun occurred
20    Overrun,
21    /// Mode fault occurred
22    ModeFault,
23    /// CRC error
24    Crc,
25    #[doc(hidden)]
26    _Extensible,
27}
28
29// FIXME these should be "closed" traits
30/// SCK pin -- DO NOT IMPLEMENT THIS TRAIT
31pub unsafe trait SckPin<SPI> {}
32
33/// MISO pin -- DO NOT IMPLEMENT THIS TRAIT
34pub unsafe trait MisoPin<SPI> {}
35
36/// MOSI pin -- DO NOT IMPLEMENT THIS TRAIT
37pub unsafe trait MosiPin<SPI> {}
38
39unsafe impl SckPin<SPI1> for PA5<AF5> {}
40// unsafe impl SckPin<SPI1> for PB3<AF5> {}
41
42unsafe impl SckPin<SPI2> for PB13<AF5> {}
43
44// unsafe impl SckPin<SPI3> for PB3<AF6> {}
45unsafe impl SckPin<SPI3> for PC10<AF6> {}
46
47unsafe impl MisoPin<SPI1> for PA6<AF5> {}
48// unsafe impl MisoPin<SPI1> for PB4<AF5> {}
49
50unsafe impl MisoPin<SPI2> for PB14<AF5> {}
51
52// unsafe impl MisoPin<SPI3> for PB4<AF6> {}
53unsafe impl MisoPin<SPI3> for PC11<AF6> {}
54
55unsafe impl MosiPin<SPI1> for PA7<AF5> {}
56unsafe impl MosiPin<SPI1> for PB5<AF5> {}
57
58unsafe impl MosiPin<SPI2> for PB15<AF5> {}
59
60unsafe impl MosiPin<SPI3> for PB5<AF6> {}
61unsafe impl MosiPin<SPI3> for PC12<AF6> {}
62
63/// SPI peripheral operating in full duplex master mode
64pub struct Spi<SPI, PINS> {
65    spi: SPI,
66    pins: PINS,
67}
68
69macro_rules! hal {
70    ($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
71        $(
72            impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
73                /// Configures the SPI peripheral to operate in full duplex master mode
74                pub fn $spiX<F>(
75                    spi: $SPIX,
76                    pins: (SCK, MISO, MOSI),
77                    mode: Mode,
78                    freq: F,
79                    clocks: Clocks,
80                    apb2: &mut $APBX,
81                ) -> Self
82                where
83                    F: Into<Hertz>,
84                    SCK: SckPin<$SPIX>,
85                    MISO: MisoPin<$SPIX>,
86                    MOSI: MosiPin<$SPIX>,
87                {
88                    // enable or reset $SPIX
89                    apb2.enr().modify(|_, w| w.$spiXen().enabled());
90                    apb2.rstr().modify(|_, w| w.$spiXrst().set_bit());
91                    apb2.rstr().modify(|_, w| w.$spiXrst().clear_bit());
92
93                    // FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
94                    //        8-bit
95                    // DS: 8-bit data size
96                    // SSOE: Slave Select output disabled
97                    spi.cr2
98                        .write(|w| unsafe {
99                            w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit()
100                        });
101
102                    let br = match clocks.$pclkX().0 / freq.into().0 {
103                        0 => unreachable!(),
104                        1...2 => 0b000,
105                        3...5 => 0b001,
106                        6...11 => 0b010,
107                        12...23 => 0b011,
108                        24...39 => 0b100,
109                        40...95 => 0b101,
110                        96...191 => 0b110,
111                        _ => 0b111,
112                    };
113
114                    // CPHA: phase
115                    // CPOL: polarity
116                    // MSTR: master mode
117                    // BR: 1 MHz
118                    // SPE: SPI disabled
119                    // LSBFIRST: MSB first
120                    // SSM: enable software slave management (NSS pin free for other uses)
121                    // SSI: set nss high = master mode
122                    // CRCEN: hardware CRC calculation disabled
123                    // BIDIMODE: 2 line unidirectional (full duplex)
124                    spi.cr1.write(|w| unsafe {
125                        w.cpha()
126                            .bit(mode.phase == Phase::CaptureOnSecondTransition)
127                            .cpol()
128                            .bit(mode.polarity == Polarity::IdleHigh)
129                            .mstr()
130                            .set_bit()
131                            .br()
132                            .bits(br)
133                            .spe()
134                            .set_bit()
135                            .lsbfirst()
136                            .clear_bit()
137                            .ssi()
138                            .set_bit()
139                            .ssm()
140                            .set_bit()
141                            .crcen()
142                            .clear_bit()
143                            .bidimode()
144                            .clear_bit()
145                    });
146
147                    Spi { spi, pins }
148                }
149
150                /// Releases the SPI peripheral and associated pins
151                pub fn free(self) -> ($SPIX, (SCK, MISO, MOSI)) {
152                    (self.spi, self.pins)
153                }
154            }
155
156            impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
157                type Error = Error;
158
159                fn read(&mut self) -> nb::Result<u8, Error> {
160                    let sr = self.spi.sr.read();
161
162                    Err(if sr.ovr().bit_is_set() {
163                        nb::Error::Other(Error::Overrun)
164                    } else if sr.modf().bit_is_set() {
165                        nb::Error::Other(Error::ModeFault)
166                    } else if sr.crcerr().bit_is_set() {
167                        nb::Error::Other(Error::Crc)
168                    } else if sr.rxne().bit_is_set() {
169                        // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
170                        // reading a half-word)
171                        return Ok(unsafe {
172                            ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
173                        });
174                    } else {
175                        nb::Error::WouldBlock
176                    })
177                }
178
179                fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
180                    let sr = self.spi.sr.read();
181
182                    Err(if sr.ovr().bit_is_set() {
183                        nb::Error::Other(Error::Overrun)
184                    } else if sr.modf().bit_is_set() {
185                        nb::Error::Other(Error::ModeFault)
186                    } else if sr.crcerr().bit_is_set() {
187                        nb::Error::Other(Error::Crc)
188                    } else if sr.txe().bit_is_set() {
189                        // NOTE(write_volatile) see note above
190                        unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
191                        return Ok(());
192                    } else {
193                        nb::Error::WouldBlock
194                    })
195                }
196            }
197
198            impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
199
200            impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
201        )+
202    }
203}
204
205hal! {
206    SPI1: (spi1, APB2, spi1en, spi1rst, pclk2),
207    SPI2: (spi2, APB1, spi2en, spi2rst, pclk1),
208    SPI3: (spi3, APB1, spi3en, spi3rst, pclk1),
209}
210
211// FIXME not working
212// TODO measure if this actually faster than the default implementation
213// impl ::hal::blocking::spi::Write<u8> for Spi {
214//     type Error = Error;
215
216//     fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
217//         for byte in bytes {
218//             'l: loop {
219//                 let sr = self.spi.sr.read();
220
221//                 // ignore overruns because we don't care about the incoming data
222//                 // if sr.ovr().bit_is_set() {
223//                 // Err(nb::Error::Other(Error::Overrun))
224//                 // } else
225//                 if sr.modf().bit_is_set() {
226//                     return Err(Error::ModeFault);
227//                 } else if sr.crcerr().bit_is_set() {
228//                     return Err(Error::Crc);
229//                 } else if sr.txe().bit_is_set() {
230//                     // NOTE(write_volatile) see note above
231//                     unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *byte) }
232//                     break 'l;
233//                 } else {
234//                     // try again
235//                 }
236//             }
237//         }
238
239//         // wait until the transmission of the last byte is done
240//         while self.spi.sr.read().bsy().bit_is_set() {}
241
242//         // clear OVR flag
243//         unsafe {
244//             ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
245//         }
246//         self.spi.sr.read();
247
248//         Ok(())
249//     }
250// }