stm32f072_hal/
spi.rs

1use core::ptr;
2
3use nb;
4
5pub use hal::spi::{Mode, Phase, Polarity};
6use rcc::Clocks;
7
8use stm32::{RCC, SPI1, SPI2};
9
10use gpio::gpioa::{PA5, PA6, PA7};
11use gpio::gpiob::{PB3, PB4, PB5, PB10, PB13, PB14, PB15};
12use gpio::gpioc::{PC2, PC3};
13use gpio::{Alternate, AF0, AF1, AF5};
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/// SPI abstraction
30pub struct Spi<SPI, PINS> {
31    spi: SPI,
32    pins: PINS,
33}
34
35pub trait Pins<Spi> {}
36
37impl Pins<SPI1>
38    for (
39        PA5<Alternate<AF0>>,
40        PA6<Alternate<AF0>>,
41        PA7<Alternate<AF0>>,
42    )
43{}
44impl Pins<SPI1>
45    for (
46        PB3<Alternate<AF0>>,
47        PB4<Alternate<AF0>>,
48        PB5<Alternate<AF0>>,
49    )
50{}
51
52impl Pins<SPI2>
53    for (
54        PB13<Alternate<AF0>>,
55        PB14<Alternate<AF0>>,
56        PB15<Alternate<AF0>>,
57    )
58{}
59
60impl Pins<SPI2>
61    for (
62        PB10<Alternate<AF5>>,
63        PC2<Alternate<AF1>>,
64        PC3<Alternate<AF1>>,
65    )
66{}
67
68impl<PINS> Spi<SPI1, PINS> {
69    pub fn spi1<F>(spi: SPI1, pins: PINS, mode: Mode, speed: F, clocks: Clocks) -> Self
70    where
71        PINS: Pins<SPI1>,
72        F: Into<Hertz>,
73    {
74        // NOTE(unsafe) This executes only during initialisation
75        let rcc = unsafe { &(*RCC::ptr()) };
76
77        /* Enable clock for SPI1 */
78        rcc.apb2enr.modify(|_, w| w.spi1en().set_bit());
79
80        /* Reset SPI1 */
81        rcc.apb2rstr.modify(|_, w| w.spi1rst().set_bit());
82        rcc.apb2rstr.modify(|_, w| w.spi1rst().clear_bit());
83
84        /* Make sure the SPI unit is disabled so we can configure it */
85        spi.cr1.modify(|_, w| w.spe().clear_bit());
86
87        // FRXTH: 8-bit threshold on RX FIFO
88        // DS: 8-bit data size
89        // SSOE: cleared to disable SS output
90        //
91        // NOTE(unsafe): DS reserved bit patterns are 0b0000, 0b0001, and 0b0010. 0b0111 is valid
92        // (reference manual, pp 804)
93        spi.cr2
94            .write(|w| unsafe { w.frxth().set_bit().ds().bits(0b0111).ssoe().clear_bit() });
95
96        let br = match clocks.pclk().0 / speed.into().0 {
97            0 => unreachable!(),
98            1...2 => 0b000,
99            3...5 => 0b001,
100            6...11 => 0b010,
101            12...23 => 0b011,
102            24...47 => 0b100,
103            48...95 => 0b101,
104            96...191 => 0b110,
105            _ => 0b111,
106        };
107
108        // mstr: master configuration
109        // lsbfirst: MSB first
110        // ssm: enable software slave management (NSS pin free for other uses)
111        // ssi: set nss high = master mode
112        // dff: 8 bit frames
113        // bidimode: 2-line unidirectional
114        // spe: enable the SPI bus
115        spi.cr1.write(|w| unsafe {
116            w.cpha()
117                .bit(mode.phase == Phase::CaptureOnSecondTransition)
118                .cpol()
119                .bit(mode.polarity == Polarity::IdleHigh)
120                .mstr()
121                .set_bit()
122                .br()
123                .bits(br)
124                .lsbfirst()
125                .clear_bit()
126                .ssm()
127                .set_bit()
128                .ssi()
129                .set_bit()
130                .rxonly()
131                .clear_bit()
132                .bidimode()
133                .clear_bit()
134                .spe()
135                .set_bit()
136        });
137
138        Spi { spi, pins }
139    }
140
141    pub fn release(self) -> (SPI1, PINS) {
142        (self.spi, self.pins)
143    }
144}
145
146impl<PINS> ::hal::spi::FullDuplex<u8> for Spi<SPI1, PINS> {
147    type Error = Error;
148
149    fn read(&mut self) -> nb::Result<u8, Error> {
150        let sr = self.spi.sr.read();
151
152        Err(if sr.ovr().bit_is_set() {
153            nb::Error::Other(Error::Overrun)
154        } else if sr.modf().bit_is_set() {
155            nb::Error::Other(Error::ModeFault)
156        } else if sr.crcerr().bit_is_set() {
157            nb::Error::Other(Error::Crc)
158        } else if sr.rxne().bit_is_set() {
159            // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
160            // reading a half-word)
161            return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
162        } else {
163            nb::Error::WouldBlock
164        })
165    }
166
167    fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
168        let sr = self.spi.sr.read();
169
170        Err(if sr.ovr().bit_is_set() {
171            nb::Error::Other(Error::Overrun)
172        } else if sr.modf().bit_is_set() {
173            nb::Error::Other(Error::ModeFault)
174        } else if sr.crcerr().bit_is_set() {
175            nb::Error::Other(Error::Crc)
176        } else if sr.txe().bit_is_set() {
177            // NOTE(write_volatile) see note above
178            unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
179            return Ok(());
180        } else {
181            nb::Error::WouldBlock
182        })
183    }
184}
185
186impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<SPI1, PINS> {}
187impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<SPI1, PINS> {}
188
189impl<PINS> Spi<SPI2, PINS> {
190    pub fn spi2<F>(spi: SPI2, pins: PINS, mode: Mode, speed: F, clocks: Clocks) -> Self
191    where
192        PINS: Pins<SPI2>,
193        F: Into<Hertz>,
194    {
195        // NOTE(unsafe) This executes only during initialisation
196        let rcc = unsafe { &(*RCC::ptr()) };
197
198        /* Enable clock for SPI2 */
199        rcc.apb1enr.modify(|_, w| w.spi2en().set_bit());
200
201        /* Reset SPI2 */
202        rcc.apb1rstr.modify(|_, w| w.spi2rst().set_bit());
203        rcc.apb1rstr.modify(|_, w| w.spi2rst().clear_bit());
204
205        /* Make sure the SPI unit is disabled so we can configure it */
206        spi.cr1.modify(|_, w| w.spe().clear_bit());
207
208        // FRXTH: 8-bit threshold on RX FIFO
209        // DS: 8-bit data size
210        // SSOE: cleared to disable SS output
211        //
212        // NOTE(unsafe): DS reserved bit patterns are 0b0000, 0b0001, and 0b0010. 0b0111 is valid
213        // (reference manual, pp 804)
214        spi.cr2
215            .write(|w| unsafe { w.frxth().set_bit().ds().bits(0b0111).ssoe().clear_bit() });
216
217        let br = match clocks.pclk().0 / speed.into().0 {
218            0 => unreachable!(),
219            1...2 => 0b000,
220            3...5 => 0b001,
221            6...11 => 0b010,
222            12...23 => 0b011,
223            24...47 => 0b100,
224            48...95 => 0b101,
225            96...191 => 0b110,
226            _ => 0b111,
227        };
228
229        // mstr: master configuration
230        // lsbfirst: MSB first
231        // ssm: enable software slave management (NSS pin free for other uses)
232        // ssi: set nss high = master mode
233        // dff: 8 bit frames
234        // bidimode: 2-line unidirectional
235        // spe: enable the SPI bus
236        spi.cr1.write(|w| unsafe {
237            w.cpha()
238                .bit(mode.phase == Phase::CaptureOnSecondTransition)
239                .cpol()
240                .bit(mode.polarity == Polarity::IdleHigh)
241                .mstr()
242                .set_bit()
243                .br()
244                .bits(br)
245                .lsbfirst()
246                .clear_bit()
247                .ssm()
248                .set_bit()
249                .ssi()
250                .set_bit()
251                .rxonly()
252                .clear_bit()
253                .bidimode()
254                .clear_bit()
255                .spe()
256                .set_bit()
257        });
258
259        Spi { spi, pins }
260    }
261
262    pub fn release(self) -> (SPI2, PINS) {
263        (self.spi, self.pins)
264    }
265}
266
267impl<PINS> ::hal::spi::FullDuplex<u8> for Spi<SPI2, PINS> {
268    type Error = Error;
269
270    fn read(&mut self) -> nb::Result<u8, Error> {
271        let sr = self.spi.sr.read();
272
273        Err(if sr.ovr().bit_is_set() {
274            nb::Error::Other(Error::Overrun)
275        } else if sr.modf().bit_is_set() {
276            nb::Error::Other(Error::ModeFault)
277        } else if sr.crcerr().bit_is_set() {
278            nb::Error::Other(Error::Crc)
279        } else if sr.rxne().bit_is_set() {
280            // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
281            // reading a half-word)
282            return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
283        } else {
284            nb::Error::WouldBlock
285        })
286    }
287
288    fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
289        let sr = self.spi.sr.read();
290
291        Err(if sr.ovr().bit_is_set() {
292            nb::Error::Other(Error::Overrun)
293        } else if sr.modf().bit_is_set() {
294            nb::Error::Other(Error::ModeFault)
295        } else if sr.crcerr().bit_is_set() {
296            nb::Error::Other(Error::Crc)
297        } else if sr.txe().bit_is_set() {
298            // NOTE(write_volatile) see note above
299            unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
300            return Ok(());
301        } else {
302            nb::Error::WouldBlock
303        })
304    }
305}
306
307impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<SPI2, PINS> {}
308impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<SPI2, PINS> {}