stm32l4_hal/
spi.rs

1//! Serial Peripheral Interface (SPI) bus
2
3use core::ptr;
4
5use crate::hal::spi::{FullDuplex, Mode, Phase, Polarity};
6use nb;
7use crate::stm32::{SPI1, /* TODO SPI2, */ SPI3};
8
9use crate::gpio::gpioa::{PA5, PA6, PA7};
10use crate::gpio::{AF5, Input, Floating, Alternate};
11use crate::rcc::{APB1R1, APB2, Clocks};
12use crate::time::Hertz;
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> {
28    const REMAP: bool;
29}
30
31impl Pins<SPI1>
32    for (
33        PA5<Alternate<AF5, Input<Floating>>>,
34        PA6<Alternate<AF5, Input<Floating>>>,
35        PA7<Alternate<AF5, Input<Floating>>>,
36    )
37{
38    const REMAP: bool = false; // TODO REMAP
39}
40
41/// SPI peripheral operating in full duplex master mode
42pub struct Spi<SPI, PINS> {
43    spi: SPI,
44    pins: PINS,
45}
46
47macro_rules! hal {
48    ($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
49        $(
50            impl<PINS> Spi<$SPIX, PINS> {
51                /// Configures the SPI peripheral to operate in full duplex master mode
52                pub fn $spiX<F>(
53                    spi: $SPIX,
54                    pins: PINS,
55                    mode: Mode,
56                    freq: F,
57                    clocks: Clocks,
58                    apb2: &mut $APBX,
59                ) -> Self
60                where
61                    F: Into<Hertz>,
62                    PINS: Pins<$SPIX>
63                {
64                    // enable or reset $SPIX
65                    apb2.enr().modify(|_, w| w.$spiXen().set_bit());
66                    apb2.rstr().modify(|_, w| w.$spiXrst().set_bit());
67                    apb2.rstr().modify(|_, w| w.$spiXrst().clear_bit());
68
69                    // FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
70                    //        8-bit
71                    // DS: 8-bit data size
72                    // SSOE: Slave Select output disabled
73                    spi.cr2
74                        .write(|w| unsafe {
75                            w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit()
76                        });
77
78                    let br = match clocks.$pclkX().0 / freq.into().0 {
79                        0 => unreachable!(),
80                        1...2 => 0b000,
81                        3...5 => 0b001,
82                        6...11 => 0b010,
83                        12...23 => 0b011,
84                        24...39 => 0b100,
85                        40...95 => 0b101,
86                        96...191 => 0b110,
87                        _ => 0b111,
88                    };
89
90                    // CPHA: phase
91                    // CPOL: polarity
92                    // MSTR: master mode
93                    // BR: 1 MHz
94                    // SPE: SPI disabled
95                    // LSBFIRST: MSB first
96                    // SSM: enable software slave management (NSS pin free for other uses)
97                    // SSI: set nss high = master mode
98                    // CRCEN: hardware CRC calculation disabled
99                    // BIDIMODE: 2 line unidirectional (full duplex)
100                    spi.cr1.write(|w| unsafe {
101                        w.cpha()
102                            .bit(mode.phase == Phase::CaptureOnSecondTransition)
103                            .cpol()
104                            .bit(mode.polarity == Polarity::IdleHigh)
105                            .mstr()
106                            .set_bit()
107                            .br()
108                            .bits(br)
109                            .spe()
110                            .set_bit()
111                            .lsbfirst()
112                            .clear_bit()
113                            .ssi()
114                            .set_bit()
115                            .ssm()
116                            .set_bit()
117                            .crcen()
118                            .clear_bit()
119                            .bidimode()
120                            .clear_bit()
121                    });
122
123                    Spi { spi, pins }
124                }
125
126                /// Releases the SPI peripheral and associated pins
127                pub fn free(self) -> ($SPIX, PINS) {
128                    (self.spi, self.pins)
129                }
130            }
131
132            impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
133                type Error = Error;
134
135                fn read(&mut self) -> nb::Result<u8, Error> {
136                    let sr = self.spi.sr.read();
137
138                    Err(if sr.ovr().bit_is_set() {
139                        nb::Error::Other(Error::Overrun)
140                    } else if sr.modf().bit_is_set() {
141                        nb::Error::Other(Error::ModeFault)
142                    } else if sr.crcerr().bit_is_set() {
143                        nb::Error::Other(Error::Crc)
144                    } else if sr.rxne().bit_is_set() {
145                        // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
146                        // reading a half-word)
147                        return Ok(unsafe {
148                            ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
149                        });
150                    } else {
151                        nb::Error::WouldBlock
152                    })
153                }
154
155                fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
156                    let sr = self.spi.sr.read();
157
158                    Err(if sr.ovr().bit_is_set() {
159                        nb::Error::Other(Error::Overrun)
160                    } else if sr.modf().bit_is_set() {
161                        nb::Error::Other(Error::ModeFault)
162                    } else if sr.crcerr().bit_is_set() {
163                        nb::Error::Other(Error::Crc)
164                    } else if sr.txe().bit_is_set() {
165                        // NOTE(write_volatile) see note above
166                        unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
167                        return Ok(());
168                    } else {
169                        nb::Error::WouldBlock
170                    })
171                }
172            }
173
174            impl<PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
175
176            impl<PINS> crate::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
177        )+
178    }
179}
180
181hal! {
182    SPI1: (spi1, APB2, spi1en, spi1rst, pclk2),
183    // SPI2: (spi2, APB1R1, spi2en, spi2rst, pclk1), // NOT Avail on 32k(b|c)
184    SPI3: (spi3, APB1R1, spi3en, spi3rst, pclk1),
185}