stm32f042_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};
9
10use gpio::gpioa::{PA5, PA6, PA7};
11use gpio::gpiob::{PB3, PB4, PB5};
12use gpio::{Alternate, AF0};
13use time::Hertz;
14
15/// SPI error
16#[derive(Debug)]
17pub enum Error {
18    /// Overrun occurred
19    Overrun,
20    /// Mode fault occurred
21    ModeFault,
22    /// CRC error
23    Crc,
24    #[doc(hidden)]
25    _Extensible,
26}
27
28/// SPI abstraction
29pub struct Spi<SPI, PINS> {
30    spi: SPI,
31    pins: PINS,
32}
33
34pub trait Pins<Spi> {}
35
36impl Pins<SPI1>
37    for (
38        PA5<Alternate<AF0>>,
39        PA6<Alternate<AF0>>,
40        PA7<Alternate<AF0>>,
41    )
42{}
43impl Pins<SPI1>
44    for (
45        PB3<Alternate<AF0>>,
46        PB4<Alternate<AF0>>,
47        PB5<Alternate<AF0>>,
48    )
49{}
50
51impl<PINS> Spi<SPI1, PINS> {
52    pub fn spi1<F>(spi: SPI1, pins: PINS, mode: Mode, speed: F, clocks: Clocks) -> Self
53    where
54        PINS: Pins<SPI1>,
55        F: Into<Hertz>,
56    {
57        // NOTE(unsafe) This executes only during initialisation
58        let rcc = unsafe { &(*RCC::ptr()) };
59
60        /* Enable clock for SPI1 */
61        rcc.apb2enr.modify(|_, w| w.spi1en().set_bit());
62
63        /* Reset SPI1 */
64        rcc.apb2rstr.modify(|_, w| w.spi1rst().set_bit());
65        rcc.apb2rstr.modify(|_, w| w.spi1rst().clear_bit());
66
67        /* Make sure the SPI unit is disabled so we can configure it */
68        spi.cr1.modify(|_, w| w.spe().clear_bit());
69
70        // FRXTH: 8-bit threshold on RX FIFO
71        // DS: 8-bit data size
72        // SSOE: cleared to disable SS output
73        //
74        // NOTE(unsafe): DS reserved bit patterns are 0b0000, 0b0001, and 0b0010. 0b0111 is valid
75        // (reference manual, pp 804)
76        spi.cr2
77            .write(|w| unsafe { w.frxth().set_bit().ds().bits(0b0111).ssoe().clear_bit() });
78
79        let br = match clocks.pclk().0 / speed.into().0 {
80            0 => unreachable!(),
81            1...2 => 0b000,
82            3...5 => 0b001,
83            6...11 => 0b010,
84            12...23 => 0b011,
85            24...47 => 0b100,
86            48...95 => 0b101,
87            96...191 => 0b110,
88            _ => 0b111,
89        };
90
91        // mstr: master configuration
92        // lsbfirst: MSB first
93        // ssm: enable software slave management (NSS pin free for other uses)
94        // ssi: set nss high = master mode
95        // dff: 8 bit frames
96        // bidimode: 2-line unidirectional
97        // spe: enable the SPI bus
98        spi.cr1.write(|w| unsafe {
99            w.cpha()
100                .bit(mode.phase == Phase::CaptureOnSecondTransition)
101                .cpol()
102                .bit(mode.polarity == Polarity::IdleHigh)
103                .mstr()
104                .set_bit()
105                .br()
106                .bits(br)
107                .lsbfirst()
108                .clear_bit()
109                .ssm()
110                .set_bit()
111                .ssi()
112                .set_bit()
113                .rxonly()
114                .clear_bit()
115                .bidimode()
116                .clear_bit()
117                .spe()
118                .set_bit()
119        });
120
121        Spi { spi, pins }
122    }
123
124    pub fn release(self) -> (SPI1, PINS) {
125        (self.spi, self.pins)
126    }
127}
128
129impl<PINS> ::hal::spi::FullDuplex<u8> for Spi<SPI1, PINS> {
130    type Error = Error;
131
132    fn read(&mut self) -> nb::Result<u8, Error> {
133        let sr = self.spi.sr.read();
134
135        Err(if sr.ovr().bit_is_set() {
136            nb::Error::Other(Error::Overrun)
137        } else if sr.modf().bit_is_set() {
138            nb::Error::Other(Error::ModeFault)
139        } else if sr.crcerr().bit_is_set() {
140            nb::Error::Other(Error::Crc)
141        } else if sr.rxne().bit_is_set() {
142            // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
143            // reading a half-word)
144            return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
145        } else {
146            nb::Error::WouldBlock
147        })
148    }
149
150    fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
151        let sr = self.spi.sr.read();
152
153        Err(if sr.ovr().bit_is_set() {
154            nb::Error::Other(Error::Overrun)
155        } else if sr.modf().bit_is_set() {
156            nb::Error::Other(Error::ModeFault)
157        } else if sr.crcerr().bit_is_set() {
158            nb::Error::Other(Error::Crc)
159        } else if sr.txe().bit_is_set() {
160            // NOTE(write_volatile) see note above
161            unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
162            return Ok(());
163        } else {
164            nb::Error::WouldBlock
165        })
166    }
167}
168
169impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<SPI1, PINS> {}
170impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<SPI1, PINS> {}