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}