stm32f429_hal/spi.rs
1//! Serial Peripheral Interface (SPI) bus
2
3use core::ptr;
4
5use hal::spi::{FullDuplex, Mode, Phase, Polarity};
6use nb;
7use stm32f429::{SPI1, SPI2, SPI3/*, SPI4, SPI5, SPI6*/};
8
9use gpio::gpioa::{PA5, PA6, PA7};
10use gpio::gpiob::{PB13, PB14, PB15, PB5};
11use gpio::gpioc::{PC2, PC10, PC11, PC12};
12use gpio::gpiod::{PD3};
13use gpio::{AF5, AF6};
14use rcc::{APB1, APB2, Clocks};
15use time::Hertz;
16use dma::{DmaChannel, DmaStreamTransfer, Transfer,
17 C0, C3, dma1, dma2};
18
19/// SPI error
20#[derive(Debug)]
21pub enum Error {
22 /// Overrun occurred
23 Overrun,
24 /// Mode fault occurred
25 ModeFault,
26 /// CRC error
27 Crc,
28 #[doc(hidden)] _Extensible,
29}
30
31// FIXME these should be "closed" traits
32/// SCK pin -- DO NOT IMPLEMENT THIS TRAIT
33pub unsafe trait SckPin<SPI> {}
34
35/// MISO pin -- DO NOT IMPLEMENT THIS TRAIT
36pub unsafe trait MisoPin<SPI> {}
37
38/// MOSI pin -- DO NOT IMPLEMENT THIS TRAIT
39pub unsafe trait MosiPin<SPI> {}
40
41unsafe impl SckPin<SPI1> for PA5<AF5> {}
42// unsafe impl SckPin<SPI1> for PB3<AF5> {}
43
44unsafe impl SckPin<SPI2> for PB13<AF5> {}
45unsafe impl SckPin<SPI2> for PD3<AF5> {}
46
47// unsafe impl SckPin<SPI3> for PB3<AF6> {}
48unsafe impl SckPin<SPI3> for PC10<AF6> {}
49
50unsafe impl MisoPin<SPI1> for PA6<AF5> {}
51// unsafe impl MisoPin<SPI1> for PB4<AF5> {}
52
53unsafe impl MisoPin<SPI2> for PB14<AF5> {}
54unsafe impl MisoPin<SPI2> for PC2<AF5> {}
55
56// unsafe impl MisoPin<SPI3> for PB4<AF6> {}
57unsafe impl MisoPin<SPI3> for PC11<AF6> {}
58
59unsafe impl MosiPin<SPI1> for PA7<AF5> {}
60unsafe impl MosiPin<SPI1> for PB5<AF5> {}
61
62unsafe impl MosiPin<SPI2> for PB15<AF5> {}
63
64unsafe impl MosiPin<SPI3> for PB5<AF6> {}
65unsafe impl MosiPin<SPI3> for PC12<AF6> {}
66
67/// Rx direction
68pub struct DmaRx;
69/// Tx direction
70pub struct DmaTx;
71
72/// Possible DMA configuration for an SPI device
73pub unsafe trait SpiDmaStream<STREAM, CHANNEL, DIRECTION> {}
74unsafe impl SpiDmaStream<SPI3, C0, DmaRx> for dma1::S0 {}
75unsafe impl SpiDmaStream<SPI3, C0, DmaRx> for dma1::S2 {}
76unsafe impl SpiDmaStream<SPI2, C0, DmaRx> for dma1::S3 {}
77unsafe impl SpiDmaStream<SPI2, C0, DmaTx> for dma1::S4 {}
78unsafe impl SpiDmaStream<SPI3, C0, DmaTx> for dma1::S5 {}
79unsafe impl SpiDmaStream<SPI3, C0, DmaTx> for dma1::S7 {}
80unsafe impl SpiDmaStream<SPI1, C3, DmaRx> for dma2::S0 {}
81unsafe impl SpiDmaStream<SPI1, C3, DmaRx> for dma2::S2 {}
82unsafe impl SpiDmaStream<SPI1, C3, DmaTx> for dma2::S3 {}
83unsafe impl SpiDmaStream<SPI1, C3, DmaTx> for dma2::S5 {}
84
85/// Allows to write with DMA
86pub trait DmaWrite {
87 /// Start writing DMA transfer
88 fn dma_write<S, T, SPI, STREAM, CHANNEL, X>(&mut self, dma: STREAM, data: S) -> X
89 where
90 S: AsRef<[T]>,
91 STREAM: DmaStreamTransfer<S, T, X> + SpiDmaStream<SPI, CHANNEL, DmaTx>,
92 CHANNEL: DmaChannel,
93 X: Transfer<STREAM>;
94}
95
96/// SPI peripheral operating in full duplex master mode
97pub struct Spi<SPI, PINS> {
98 spi: SPI,
99 pins: PINS,
100}
101
102macro_rules! hal {
103 ($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
104 $(
105 impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
106 /// Configures the SPI peripheral to operate in full duplex master mode
107 pub fn $spiX<F>(
108 spi: $SPIX,
109 pins: (SCK, MISO, MOSI),
110 mode: Mode,
111 freq: F,
112 clocks: Clocks,
113 apb: &mut $APBX,
114 ) -> Self
115 where
116 F: Into<Hertz>,
117 SCK: SckPin<$SPIX>,
118 MISO: MisoPin<$SPIX>,
119 MOSI: MosiPin<$SPIX>,
120 {
121 // enable or reset $SPIX
122 apb.enr().modify(|_, w| w.$spiXen().set_bit());
123 apb.rstr().modify(|_, w| w.$spiXrst().set_bit());
124 apb.rstr().modify(|_, w| w.$spiXrst().clear_bit());
125
126 spi.cr2.write(|w| w
127 // Tx buffer empty interrupt disable
128 .txeie().clear_bit()
129 // SS output enable
130 .ssoe().set_bit()
131 );
132
133 let br = match clocks.$pclkX().0 / freq.into().0 {
134 0 => unreachable!(),
135 1...2 => 0b000,
136 3...5 => 0b001,
137 6...11 => 0b010,
138 12...23 => 0b011,
139 24...39 => 0b100,
140 40...95 => 0b101,
141 96...191 => 0b110,
142 _ => 0b111,
143 };
144
145 spi.cr1.write(|w| unsafe {
146 w
147 // 8-bit data frame format
148 .dff().clear_bit()
149 // Clock phase
150 .cpha().bit(mode.phase == Phase::CaptureOnSecondTransition)
151 // Clock polariy
152 .cpol().bit(mode.polarity == Polarity::IdleHigh)
153 // Master mode
154 .mstr().set_bit()
155 // 1 MHz
156 .br().bits(br)
157 // Enable SPI
158 .spe().set_bit()
159 // MSB transmitted first
160 .lsbfirst().clear_bit()
161 // Set NSS high
162 .ssi().set_bit()
163 // Software slave management
164 .ssm().set_bit()
165 // Disable CRC calculation
166 .crcen().clear_bit()
167 // 2-line unidirectional data mode
168 .bidimode().clear_bit()
169 // Full duplex
170 .rxonly().clear_bit()
171 });
172
173 Spi { spi, pins }
174 }
175
176 /// Enable transmit interrupt
177 pub fn enable_send_interrupt(&mut self) {
178 self.spi.cr2.modify(|_, w| w.txeie().set_bit());
179 }
180
181 /// Disable transmit interrupt
182 pub fn disable_send_interrupt(&mut self) {
183 self.spi.cr2.modify(|_, w| w.txeie().clear_bit());
184 }
185
186 /// Releases the SPI peripheral and associated pins
187 pub fn free(self) -> ($SPIX, (SCK, MISO, MOSI)) {
188 (self.spi, self.pins)
189 }
190 }
191
192
193 impl<SCK, MISO, MOSI> DmaWrite for Spi<$SPIX, (SCK, MISO, MOSI)> {
194 /// Start a one-shot DMA transfer
195 fn dma_write<S, T, $SPIX, STREAM, CHANNEL, X>(&mut self, dma: STREAM, data: S) -> X
196 where
197 S: AsRef<[T]>,
198 STREAM: DmaStreamTransfer<S, T, X> + SpiDmaStream<$SPIX, CHANNEL, DmaTx>,
199 CHANNEL: DmaChannel,
200 X: Transfer<STREAM>,
201 {
202 self.spi.cr2.modify(|_, w| w.txdmaen().set_bit());
203
204 let dr: &mut T = unsafe {
205 &mut *(&self.spi.dr as *const _ as *mut T)
206 };
207 dma.start_transfer::<CHANNEL>(data, dr)
208 }
209 }
210
211 impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
212 type Error = Error;
213
214 fn read(&mut self) -> nb::Result<u8, Error> {
215 let sr = self.spi.sr.read();
216
217 Err(if sr.ovr().bit_is_set() {
218 nb::Error::Other(Error::Overrun)
219 } else if sr.modf().bit_is_set() {
220 nb::Error::Other(Error::ModeFault)
221 } else if sr.crcerr().bit_is_set() {
222 nb::Error::Other(Error::Crc)
223 } else if sr.rxne().bit_is_set() {
224 // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
225 // reading a half-word)
226 return Ok(unsafe {
227 ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
228 });
229 } else {
230 nb::Error::WouldBlock
231 })
232 }
233
234 fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
235 let sr = self.spi.sr.read();
236
237 Err(/*if sr.ovr().bit_is_set() {
238 // Clear the flag:
239 unsafe {
240 ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
241 };
242 nb::Error::Other(Error::Overrun)
243 } else*/ if sr.modf().bit_is_set() {
244 nb::Error::Other(Error::ModeFault)
245 } else if sr.crcerr().bit_is_set() {
246 nb::Error::Other(Error::Crc)
247 } else if sr.txe().bit_is_set() {
248 // NOTE(write_volatile) see note above
249 unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
250 return Ok(());
251 } else {
252 nb::Error::WouldBlock
253 })
254 }
255 }
256
257 impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
258 // impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
259
260 impl<PINS> ::hal::blocking::spi::Write<u8> for Spi<$SPIX, PINS> {
261 type Error = Error;
262
263 fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
264 for byte in bytes {
265 'l: loop {
266 let sr = self.spi.sr.read();
267
268 // ignore overruns because we don't care about the incoming data
269 // if sr.ovr().bit_is_set() {
270 // Err(nb::Error::Other(Error::Overrun))
271 // } else
272 if sr.modf().bit_is_set() {
273 return Err(Error::ModeFault);
274 } else if sr.crcerr().bit_is_set() {
275 return Err(Error::Crc);
276 } else if sr.txe().bit_is_set() {
277 // NOTE(write_volatile) see note above
278 unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *byte) }
279 break 'l;
280 } else {
281 // try again
282 }
283 }
284 }
285
286 // wait until the transmission of the last byte is done
287 while self.spi.sr.read().bsy().bit_is_set() {}
288
289 // clear OVR flag
290 unsafe {
291 ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
292 }
293 self.spi.sr.read();
294
295 Ok(())
296 }
297 }
298 )+
299 }
300}
301
302hal! {
303 SPI1: (spi1, APB2, spi1en, spi1rst, pclk2),
304 SPI2: (spi2, APB1, spi2en, spi2rst, pclk1),
305 SPI3: (spi3, APB1, spi3en, spi3rst, pclk1),
306 /* Available in the datasheet but not in the .svd:
307 SPI4: (spi4, APB2, spi4en, spi4rst, pclk2),
308 SPI5: (spi5, APB2, spi5en, spi5rst, pclk2),
309 SPI6: (spi6, APB2, spi6en, spi6rst, pclk2),
310 */
311}
312
313// FIXME not working
314// TODO measure if this actually faster than the default implementation
315// impl ::hal::blocking::spi::Write<u8> for Spi {
316// type Error = Error;
317
318// fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
319// for byte in bytes {
320// 'l: loop {
321// let sr = self.spi.sr.read();
322
323// // ignore overruns because we don't care about the incoming data
324// // if sr.ovr().bit_is_set() {
325// // Err(nb::Error::Other(Error::Overrun))
326// // } else
327// if sr.modf().bit_is_set() {
328// return Err(Error::ModeFault);
329// } else if sr.crcerr().bit_is_set() {
330// return Err(Error::Crc);
331// } else if sr.txe().bit_is_set() {
332// // NOTE(write_volatile) see note above
333// unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *byte) }
334// break 'l;
335// } else {
336// // try again
337// }
338// }
339// }
340
341// // wait until the transmission of the last byte is done
342// while self.spi.sr.read().bsy().bit_is_set() {}
343
344// // clear OVR flag
345// unsafe {
346// ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
347// }
348// self.spi.sr.read();
349
350// Ok(())
351// }
352// }