stm32l1xx_hal/
spi.rs

1use crate::gpio::gpioa::{PA11, PA12, PA5, PA6, PA7};
2use crate::gpio::gpiob::{PB13, PB14, PB15, PB3, PB4, PB5};
3use crate::gpio::gpioc::{PC10, PC11, PC12};
4use crate::gpio::{Floating, Input};
5use crate::rcc::Rcc;
6use crate::stm32::{SPI1, SPI2, SPI3};
7use crate::time::Hertz;
8use core::ptr;
9use hal;
10use nb;
11
12pub use hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
13
14/// SPI error
15#[derive(Debug)]
16pub enum Error {
17    /// Overrun occurred
18    Overrun,
19    /// Mode fault occurred
20    ModeFault,
21    /// CRC error
22    Crc,
23    #[doc(hidden)]
24    _Extensible,
25}
26
27pub trait Pins<SPI> {}
28pub trait PinSck<SPI> {}
29pub trait PinMiso<SPI> {}
30pub trait PinMosi<SPI> {}
31
32impl<SPI, SCK, MISO, MOSI> Pins<SPI> for (SCK, MISO, MOSI)
33where
34    SCK: PinSck<SPI>,
35    MISO: PinMiso<SPI>,
36    MOSI: PinMosi<SPI>,
37{
38}
39
40/// A filler type for when the SCK pin is unnecessary
41pub struct NoSck;
42/// A filler type for when the Miso pin is unnecessary
43pub struct NoMiso;
44/// A filler type for when the Mosi pin is unnecessary
45pub struct NoMosi;
46
47macro_rules! pins {
48    ($($SPIX:ty: SCK: [$($SCK:ty),*] MISO: [$($MISO:ty),*] MOSI: [$($MOSI:ty),*])+) => {
49        $(
50            $(
51                impl PinSck<$SPIX> for $SCK {}
52            )*
53            $(
54                impl PinMiso<$SPIX> for $MISO {}
55            )*
56            $(
57                impl PinMosi<$SPIX> for $MOSI {}
58            )*
59        )+
60    }
61}
62
63pins! {
64    SPI1:
65        SCK: [
66            NoSck,
67            PA5<Input<Floating>>,
68            PB3<Input<Floating>>
69        ]
70        MISO: [
71            NoMiso,
72            PA6<Input<Floating>>,
73            PA11<Input<Floating>>,
74            PB4<Input<Floating>>
75        ]
76        MOSI: [
77            NoMosi,
78            PA7<Input<Floating>>,
79            PA12<Input<Floating>>,
80            PB5<Input<Floating>>
81        ]
82
83    SPI2:
84        SCK: [
85            NoSck,
86            PB13<Input<Floating>>
87        ]
88        MISO: [
89            NoMiso,
90            PB14<Input<Floating>>
91        ]
92        MOSI: [
93            NoMosi,
94            PB15<Input<Floating>>
95        ]
96
97    SPI3:
98        SCK: [
99            NoSck,
100            PB3<Input<Floating>>,
101            PC10<Input<Floating>>
102        ]
103        MISO: [
104            NoMiso,
105            PB4<Input<Floating>>,
106            PC11<Input<Floating>>
107        ]
108        MOSI: [
109            NoMosi,
110            PB5<Input<Floating>>,
111            PC12<Input<Floating>>
112        ]
113}
114
115#[derive(Debug)]
116pub struct Spi<SPI, PINS> {
117    spi: SPI,
118    pins: PINS,
119}
120
121pub trait SpiExt<SPI>: Sized {
122    fn spi<PINS, T>(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<SPI, PINS>
123    where
124        PINS: Pins<SPI>,
125        T: Into<Hertz>;
126}
127
128macro_rules! spi {
129    ($($SPIX:ident: ($spiX:ident, $apbXenr:ident, $spiXen:ident, $pclkX:ident),)+) => {
130        $(
131            impl<PINS> Spi<$SPIX, PINS> {
132                pub fn $spiX<T>(
133                    spi: $SPIX,
134                    pins: PINS,
135                    mode: Mode,
136                    freq: T,
137                    rcc: &mut Rcc
138                ) -> Self
139                where
140                PINS: Pins<$SPIX>,
141                T: Into<Hertz>
142                {
143                    // Enable clock for SPI
144                    rcc.rb.$apbXenr.modify(|_, w| w.$spiXen().set_bit());
145
146                    // disable SS output
147                    spi.cr2.write(|w| w.ssoe().clear_bit());
148
149                    let spi_freq = freq.into().0;
150                    let apb_freq = rcc.clocks.$pclkX().0;
151                    let br = match apb_freq / spi_freq {
152                        0 => unreachable!(),
153                        1..=2 => 0b000,
154                        3..=5 => 0b001,
155                        6..=11 => 0b010,
156                        12..=23 => 0b011,
157                        24..=47 => 0b100,
158                        48..=95 => 0b101,
159                        96..=191 => 0b110,
160                        _ => 0b111,
161                    };
162
163                    // mstr: master configuration
164                    // lsbfirst: MSB first
165                    // ssm: enable software slave management (NSS pin free for other uses)
166                    // ssi: set nss high = master mode
167                    // dff: 8 bit frames
168                    // bidimode: 2-line unidirectional
169                    // spe: enable the SPI bus
170                    #[allow(unused)]
171                    spi.cr1.write(|w| unsafe {
172                        w.cpha()
173                            .bit(mode.phase == Phase::CaptureOnSecondTransition)
174                            .cpol()
175                            .bit(mode.polarity == Polarity::IdleHigh)
176                            .mstr()
177                            .set_bit()
178                            .br()
179                            .bits(br)
180                            .lsbfirst()
181                            .clear_bit()
182                            .ssm()
183                            .set_bit()
184                            .ssi()
185                            .set_bit()
186                            .rxonly()
187                            .clear_bit()
188                            .dff()
189                            .clear_bit()
190                            .bidimode()
191                            .clear_bit()
192                            .spe()
193                            .set_bit()
194                    });
195
196                    Spi { spi, pins }
197                }
198
199                pub fn free(self) -> ($SPIX, PINS) {
200                    (self.spi, self.pins)
201                }
202            }
203
204            impl SpiExt<$SPIX> for $SPIX {
205                fn spi<PINS, T>(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<$SPIX, PINS>
206                where
207                    PINS: Pins<$SPIX>,
208                    T: Into<Hertz>
209                    {
210                        Spi::$spiX(self, pins, mode, freq, rcc)
211                    }
212            }
213
214            impl<PINS> hal::spi::FullDuplex<u8> for Spi<$SPIX, PINS> {
215                type Error = Error;
216
217                fn read(&mut self) -> nb::Result<u8, Error> {
218                    let sr = self.spi.sr.read();
219
220                    Err(if sr.ovr().bit_is_set() {
221                        nb::Error::Other(Error::Overrun)
222                    } else if sr.modf().bit_is_set() {
223                        nb::Error::Other(Error::ModeFault)
224                    } else if sr.crcerr().bit_is_set() {
225                        nb::Error::Other(Error::Crc)
226                    } else if sr.rxne().bit_is_set() {
227                        // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
228                        // reading a half-word)
229                        return Ok(unsafe {
230                            ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
231                        });
232                    } else {
233                        nb::Error::WouldBlock
234                    })
235                }
236
237                fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
238                    let sr = self.spi.sr.read();
239
240                    Err(if sr.ovr().bit_is_set() {
241                        nb::Error::Other(Error::Overrun)
242                    } else if sr.modf().bit_is_set() {
243                        nb::Error::Other(Error::ModeFault)
244                    } else if sr.crcerr().bit_is_set() {
245                        nb::Error::Other(Error::Crc)
246                    } else if sr.txe().bit_is_set() {
247                        // NOTE(write_volatile) see note above
248                        unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
249                        return Ok(());
250                    } else {
251                        nb::Error::WouldBlock
252                    })
253                }
254
255            }
256
257            impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
258
259            impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
260        )+
261    }
262}
263
264spi! {
265    SPI1: (spi1, apb2enr, spi1en, apb2_clk),
266    SPI2: (spi2, apb1enr, spi2en, apb1_clk),
267    SPI3: (spi3, apb1enr, spi3en, apb1_clk),
268}