stm32f429_hal/
spi.rs

1//! Serial Peripheral Interface (SPI) bus
2
3use core::ptr;
4
5use hal::spi::{FullDuplex, Mode, Phase, Polarity};
6use nb;
7use stm32f429::{SPI1, SPI2, SPI3/*, SPI4, SPI5, SPI6*/};
8
9use gpio::gpioa::{PA5, PA6, PA7};
10use gpio::gpiob::{PB13, PB14, PB15, PB5};
11use gpio::gpioc::{PC2, PC10, PC11, PC12};
12use gpio::gpiod::{PD3};
13use gpio::{AF5, AF6};
14use rcc::{APB1, APB2, Clocks};
15use time::Hertz;
16use dma::{DmaChannel, DmaStreamTransfer, Transfer,
17          C0, C3, dma1, dma2};
18
19/// SPI error
20#[derive(Debug)]
21pub enum Error {
22    /// Overrun occurred
23    Overrun,
24    /// Mode fault occurred
25    ModeFault,
26    /// CRC error
27    Crc,
28    #[doc(hidden)] _Extensible,
29}
30
31// FIXME these should be "closed" traits
32/// SCK pin -- DO NOT IMPLEMENT THIS TRAIT
33pub unsafe trait SckPin<SPI> {}
34
35/// MISO pin -- DO NOT IMPLEMENT THIS TRAIT
36pub unsafe trait MisoPin<SPI> {}
37
38/// MOSI pin -- DO NOT IMPLEMENT THIS TRAIT
39pub unsafe trait MosiPin<SPI> {}
40
41unsafe impl SckPin<SPI1> for PA5<AF5> {}
42// unsafe impl SckPin<SPI1> for PB3<AF5> {}
43
44unsafe impl SckPin<SPI2> for PB13<AF5> {}
45unsafe impl SckPin<SPI2> for PD3<AF5> {}
46
47// unsafe impl SckPin<SPI3> for PB3<AF6> {}
48unsafe impl SckPin<SPI3> for PC10<AF6> {}
49
50unsafe impl MisoPin<SPI1> for PA6<AF5> {}
51// unsafe impl MisoPin<SPI1> for PB4<AF5> {}
52
53unsafe impl MisoPin<SPI2> for PB14<AF5> {}
54unsafe impl MisoPin<SPI2> for PC2<AF5> {}
55
56// unsafe impl MisoPin<SPI3> for PB4<AF6> {}
57unsafe impl MisoPin<SPI3> for PC11<AF6> {}
58
59unsafe impl MosiPin<SPI1> for PA7<AF5> {}
60unsafe impl MosiPin<SPI1> for PB5<AF5> {}
61
62unsafe impl MosiPin<SPI2> for PB15<AF5> {}
63
64unsafe impl MosiPin<SPI3> for PB5<AF6> {}
65unsafe impl MosiPin<SPI3> for PC12<AF6> {}
66
67/// Rx direction
68pub struct DmaRx;
69/// Tx direction
70pub struct DmaTx;
71
72/// Possible DMA configuration for an SPI device
73pub unsafe trait SpiDmaStream<STREAM, CHANNEL, DIRECTION> {}
74unsafe impl SpiDmaStream<SPI3, C0, DmaRx> for dma1::S0 {}
75unsafe impl SpiDmaStream<SPI3, C0, DmaRx> for dma1::S2 {}
76unsafe impl SpiDmaStream<SPI2, C0, DmaRx> for dma1::S3 {}
77unsafe impl SpiDmaStream<SPI2, C0, DmaTx> for dma1::S4 {}
78unsafe impl SpiDmaStream<SPI3, C0, DmaTx> for dma1::S5 {}
79unsafe impl SpiDmaStream<SPI3, C0, DmaTx> for dma1::S7 {}
80unsafe impl SpiDmaStream<SPI1, C3, DmaRx> for dma2::S0 {}
81unsafe impl SpiDmaStream<SPI1, C3, DmaRx> for dma2::S2 {}
82unsafe impl SpiDmaStream<SPI1, C3, DmaTx> for dma2::S3 {}
83unsafe impl SpiDmaStream<SPI1, C3, DmaTx> for dma2::S5 {}
84
85/// Allows to write with DMA
86pub trait DmaWrite {
87    /// Start writing DMA transfer
88    fn dma_write<S, T, SPI, STREAM, CHANNEL, X>(&mut self, dma: STREAM, data: S) -> X
89    where
90        S: AsRef<[T]>,
91        STREAM: DmaStreamTransfer<S, T, X> + SpiDmaStream<SPI, CHANNEL, DmaTx>,
92        CHANNEL: DmaChannel,
93        X: Transfer<STREAM>;
94}
95
96/// SPI peripheral operating in full duplex master mode
97pub struct Spi<SPI, PINS> {
98    spi: SPI,
99    pins: PINS,
100}
101
102macro_rules! hal {
103    ($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
104        $(
105            impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
106                /// Configures the SPI peripheral to operate in full duplex master mode
107                pub fn $spiX<F>(
108                    spi: $SPIX,
109                    pins: (SCK, MISO, MOSI),
110                    mode: Mode,
111                    freq: F,
112                    clocks: Clocks,
113                    apb: &mut $APBX,
114                ) -> Self
115                where
116                    F: Into<Hertz>,
117                    SCK: SckPin<$SPIX>,
118                    MISO: MisoPin<$SPIX>,
119                    MOSI: MosiPin<$SPIX>,
120                {
121                    // enable or reset $SPIX
122                    apb.enr().modify(|_, w| w.$spiXen().set_bit());
123                    apb.rstr().modify(|_, w| w.$spiXrst().set_bit());
124                    apb.rstr().modify(|_, w| w.$spiXrst().clear_bit());
125
126                    spi.cr2.write(|w| w
127                                  // Tx buffer empty interrupt disable
128                                  .txeie().clear_bit()
129                                  // SS output enable
130                                  .ssoe().set_bit()
131                    );
132
133                    let br = match clocks.$pclkX().0 / freq.into().0 {
134                        0 => unreachable!(),
135                        1...2 => 0b000,
136                        3...5 => 0b001,
137                        6...11 => 0b010,
138                        12...23 => 0b011,
139                        24...39 => 0b100,
140                        40...95 => 0b101,
141                        96...191 => 0b110,
142                        _ => 0b111,
143                    };
144
145                    spi.cr1.write(|w| unsafe {
146                        w
147                            // 8-bit data frame format
148                            .dff().clear_bit()
149                            // Clock phase
150                            .cpha().bit(mode.phase == Phase::CaptureOnSecondTransition)
151                            // Clock polariy
152                            .cpol().bit(mode.polarity == Polarity::IdleHigh)
153                            // Master mode
154                            .mstr().set_bit()
155                            // 1 MHz
156                            .br().bits(br)
157                            // Enable SPI
158                            .spe().set_bit()
159                            // MSB transmitted first
160                            .lsbfirst().clear_bit()
161                            // Set NSS high
162                            .ssi().set_bit()
163                            // Software slave management
164                            .ssm().set_bit()
165                            // Disable CRC calculation
166                            .crcen().clear_bit()
167                            // 2-line unidirectional data mode
168                            .bidimode().clear_bit()
169                            // Full duplex
170                            .rxonly().clear_bit()
171                    });
172
173                    Spi { spi, pins }
174                }
175
176                /// Enable transmit interrupt
177                pub fn enable_send_interrupt(&mut self) {
178                    self.spi.cr2.modify(|_, w| w.txeie().set_bit());
179                }
180
181                /// Disable transmit interrupt
182                pub fn disable_send_interrupt(&mut self) {
183                    self.spi.cr2.modify(|_, w| w.txeie().clear_bit());
184                }
185
186                /// Releases the SPI peripheral and associated pins
187                pub fn free(self) -> ($SPIX, (SCK, MISO, MOSI)) {
188                    (self.spi, self.pins)
189                }
190            }
191
192
193            impl<SCK, MISO, MOSI> DmaWrite for Spi<$SPIX, (SCK, MISO, MOSI)> {
194                /// Start a one-shot DMA transfer
195                fn dma_write<S, T, $SPIX, STREAM, CHANNEL, X>(&mut self, dma: STREAM, data: S) -> X
196                where
197                    S: AsRef<[T]>,
198                    STREAM: DmaStreamTransfer<S, T, X> + SpiDmaStream<$SPIX, CHANNEL, DmaTx>,
199                    CHANNEL: DmaChannel,
200                    X: Transfer<STREAM>,
201                {
202                    self.spi.cr2.modify(|_, w| w.txdmaen().set_bit());
203
204                    let dr: &mut T = unsafe {
205                        &mut *(&self.spi.dr as *const _ as *mut T)
206                    };
207                    dma.start_transfer::<CHANNEL>(data, dr)
208                }
209            }
210
211            impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
212                type Error = Error;
213
214                fn read(&mut self) -> nb::Result<u8, Error> {
215                    let sr = self.spi.sr.read();
216
217                    Err(if sr.ovr().bit_is_set() {
218                        nb::Error::Other(Error::Overrun)
219                    } else if sr.modf().bit_is_set() {
220                        nb::Error::Other(Error::ModeFault)
221                    } else if sr.crcerr().bit_is_set() {
222                        nb::Error::Other(Error::Crc)
223                    } else if sr.rxne().bit_is_set() {
224                        // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
225                        // reading a half-word)
226                        return Ok(unsafe {
227                            ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
228                        });
229                    } else {
230                        nb::Error::WouldBlock
231                    })
232                }
233
234                fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
235                    let sr = self.spi.sr.read();
236
237                    Err(/*if sr.ovr().bit_is_set() {
238                        // Clear the flag:
239                        unsafe {
240                            ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
241                        };
242                        nb::Error::Other(Error::Overrun)
243                    } else*/ if sr.modf().bit_is_set() {
244                        nb::Error::Other(Error::ModeFault)
245                    } else if sr.crcerr().bit_is_set() {
246                        nb::Error::Other(Error::Crc)
247                    } else if sr.txe().bit_is_set() {
248                        // NOTE(write_volatile) see note above
249                        unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
250                        return Ok(());
251                    } else {
252                        nb::Error::WouldBlock
253                    })
254                }
255            }
256
257            impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
258            // impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
259
260            impl<PINS> ::hal::blocking::spi::Write<u8> for Spi<$SPIX, PINS> {
261                type Error = Error;
262
263                fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
264                    for byte in bytes {
265                        'l: loop {
266                            let sr = self.spi.sr.read();
267
268                            // ignore overruns because we don't care about the incoming data
269                            // if sr.ovr().bit_is_set() {
270                            // Err(nb::Error::Other(Error::Overrun))
271                            // } else
272                            if sr.modf().bit_is_set() {
273                                return Err(Error::ModeFault);
274                            } else if sr.crcerr().bit_is_set() {
275                                return Err(Error::Crc);
276                            } else if sr.txe().bit_is_set() {
277                                // NOTE(write_volatile) see note above
278                                unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *byte) }
279                                break 'l;
280                            } else {
281                                // try again
282                            }
283                        }
284                    }
285
286                    // wait until the transmission of the last byte is done
287                    while self.spi.sr.read().bsy().bit_is_set() {}
288
289                    // clear OVR flag
290                    unsafe {
291                        ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
292                    }
293                    self.spi.sr.read();
294
295                    Ok(())
296                }
297            }
298        )+
299    }
300}
301
302hal! {
303    SPI1: (spi1, APB2, spi1en, spi1rst, pclk2),
304    SPI2: (spi2, APB1, spi2en, spi2rst, pclk1),
305    SPI3: (spi3, APB1, spi3en, spi3rst, pclk1),
306    /* Available in the datasheet but not in the .svd:
307    SPI4: (spi4, APB2, spi4en, spi4rst, pclk2),
308    SPI5: (spi5, APB2, spi5en, spi5rst, pclk2),
309    SPI6: (spi6, APB2, spi6en, spi6rst, pclk2),
310     */
311}
312
313// FIXME not working
314// TODO measure if this actually faster than the default implementation
315// impl ::hal::blocking::spi::Write<u8> for Spi {
316//     type Error = Error;
317
318//     fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
319//         for byte in bytes {
320//             'l: loop {
321//                 let sr = self.spi.sr.read();
322
323//                 // ignore overruns because we don't care about the incoming data
324//                 // if sr.ovr().bit_is_set() {
325//                 // Err(nb::Error::Other(Error::Overrun))
326//                 // } else
327//                 if sr.modf().bit_is_set() {
328//                     return Err(Error::ModeFault);
329//                 } else if sr.crcerr().bit_is_set() {
330//                     return Err(Error::Crc);
331//                 } else if sr.txe().bit_is_set() {
332//                     // NOTE(write_volatile) see note above
333//                     unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *byte) }
334//                     break 'l;
335//                 } else {
336//                     // try again
337//                 }
338//             }
339//         }
340
341//         // wait until the transmission of the last byte is done
342//         while self.spi.sr.read().bsy().bit_is_set() {}
343
344//         // clear OVR flag
345//         unsafe {
346//             ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
347//         }
348//         self.spi.sr.read();
349
350//         Ok(())
351//     }
352// }