stm32f30x_hal/spi.rs
1//! Serial Peripheral Interface (SPI) bus
2
3use core::ptr;
4
5use hal::spi::{FullDuplex, Mode, Phase, Polarity};
6use nb;
7use stm32f30x::{SPI1, SPI2, SPI3};
8
9use gpio::gpioa::{PA5, PA6, PA7};
10use gpio::gpiob::{PB13, PB14, PB15, PB5};
11use gpio::gpioc::{PC10, PC11, PC12};
12use gpio::{AF5, AF6};
13use rcc::{APB1, APB2, Clocks};
14use time::Hertz;
15
16/// SPI error
17#[derive(Debug)]
18pub enum Error {
19 /// Overrun occurred
20 Overrun,
21 /// Mode fault occurred
22 ModeFault,
23 /// CRC error
24 Crc,
25 #[doc(hidden)]
26 _Extensible,
27}
28
29// FIXME these should be "closed" traits
30/// SCK pin -- DO NOT IMPLEMENT THIS TRAIT
31pub unsafe trait SckPin<SPI> {}
32
33/// MISO pin -- DO NOT IMPLEMENT THIS TRAIT
34pub unsafe trait MisoPin<SPI> {}
35
36/// MOSI pin -- DO NOT IMPLEMENT THIS TRAIT
37pub unsafe trait MosiPin<SPI> {}
38
39unsafe impl SckPin<SPI1> for PA5<AF5> {}
40// unsafe impl SckPin<SPI1> for PB3<AF5> {}
41
42unsafe impl SckPin<SPI2> for PB13<AF5> {}
43
44// unsafe impl SckPin<SPI3> for PB3<AF6> {}
45unsafe impl SckPin<SPI3> for PC10<AF6> {}
46
47unsafe impl MisoPin<SPI1> for PA6<AF5> {}
48// unsafe impl MisoPin<SPI1> for PB4<AF5> {}
49
50unsafe impl MisoPin<SPI2> for PB14<AF5> {}
51
52// unsafe impl MisoPin<SPI3> for PB4<AF6> {}
53unsafe impl MisoPin<SPI3> for PC11<AF6> {}
54
55unsafe impl MosiPin<SPI1> for PA7<AF5> {}
56unsafe impl MosiPin<SPI1> for PB5<AF5> {}
57
58unsafe impl MosiPin<SPI2> for PB15<AF5> {}
59
60unsafe impl MosiPin<SPI3> for PB5<AF6> {}
61unsafe impl MosiPin<SPI3> for PC12<AF6> {}
62
63/// SPI peripheral operating in full duplex master mode
64pub struct Spi<SPI, PINS> {
65 spi: SPI,
66 pins: PINS,
67}
68
69macro_rules! hal {
70 ($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
71 $(
72 impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
73 /// Configures the SPI peripheral to operate in full duplex master mode
74 pub fn $spiX<F>(
75 spi: $SPIX,
76 pins: (SCK, MISO, MOSI),
77 mode: Mode,
78 freq: F,
79 clocks: Clocks,
80 apb2: &mut $APBX,
81 ) -> Self
82 where
83 F: Into<Hertz>,
84 SCK: SckPin<$SPIX>,
85 MISO: MisoPin<$SPIX>,
86 MOSI: MosiPin<$SPIX>,
87 {
88 // enable or reset $SPIX
89 apb2.enr().modify(|_, w| w.$spiXen().enabled());
90 apb2.rstr().modify(|_, w| w.$spiXrst().set_bit());
91 apb2.rstr().modify(|_, w| w.$spiXrst().clear_bit());
92
93 // FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
94 // 8-bit
95 // DS: 8-bit data size
96 // SSOE: Slave Select output disabled
97 spi.cr2
98 .write(|w| unsafe {
99 w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit()
100 });
101
102 let br = match clocks.$pclkX().0 / freq.into().0 {
103 0 => unreachable!(),
104 1...2 => 0b000,
105 3...5 => 0b001,
106 6...11 => 0b010,
107 12...23 => 0b011,
108 24...39 => 0b100,
109 40...95 => 0b101,
110 96...191 => 0b110,
111 _ => 0b111,
112 };
113
114 // CPHA: phase
115 // CPOL: polarity
116 // MSTR: master mode
117 // BR: 1 MHz
118 // SPE: SPI disabled
119 // LSBFIRST: MSB first
120 // SSM: enable software slave management (NSS pin free for other uses)
121 // SSI: set nss high = master mode
122 // CRCEN: hardware CRC calculation disabled
123 // BIDIMODE: 2 line unidirectional (full duplex)
124 spi.cr1.write(|w| unsafe {
125 w.cpha()
126 .bit(mode.phase == Phase::CaptureOnSecondTransition)
127 .cpol()
128 .bit(mode.polarity == Polarity::IdleHigh)
129 .mstr()
130 .set_bit()
131 .br()
132 .bits(br)
133 .spe()
134 .set_bit()
135 .lsbfirst()
136 .clear_bit()
137 .ssi()
138 .set_bit()
139 .ssm()
140 .set_bit()
141 .crcen()
142 .clear_bit()
143 .bidimode()
144 .clear_bit()
145 });
146
147 Spi { spi, pins }
148 }
149
150 /// Releases the SPI peripheral and associated pins
151 pub fn free(self) -> ($SPIX, (SCK, MISO, MOSI)) {
152 (self.spi, self.pins)
153 }
154 }
155
156 impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
157 type Error = Error;
158
159 fn read(&mut self) -> nb::Result<u8, Error> {
160 let sr = self.spi.sr.read();
161
162 Err(if sr.ovr().bit_is_set() {
163 nb::Error::Other(Error::Overrun)
164 } else if sr.modf().bit_is_set() {
165 nb::Error::Other(Error::ModeFault)
166 } else if sr.crcerr().bit_is_set() {
167 nb::Error::Other(Error::Crc)
168 } else if sr.rxne().bit_is_set() {
169 // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
170 // reading a half-word)
171 return Ok(unsafe {
172 ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
173 });
174 } else {
175 nb::Error::WouldBlock
176 })
177 }
178
179 fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
180 let sr = self.spi.sr.read();
181
182 Err(if sr.ovr().bit_is_set() {
183 nb::Error::Other(Error::Overrun)
184 } else if sr.modf().bit_is_set() {
185 nb::Error::Other(Error::ModeFault)
186 } else if sr.crcerr().bit_is_set() {
187 nb::Error::Other(Error::Crc)
188 } else if sr.txe().bit_is_set() {
189 // NOTE(write_volatile) see note above
190 unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
191 return Ok(());
192 } else {
193 nb::Error::WouldBlock
194 })
195 }
196 }
197
198 impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
199
200 impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
201 )+
202 }
203}
204
205hal! {
206 SPI1: (spi1, APB2, spi1en, spi1rst, pclk2),
207 SPI2: (spi2, APB1, spi2en, spi2rst, pclk1),
208 SPI3: (spi3, APB1, spi3en, spi3rst, pclk1),
209}
210
211// FIXME not working
212// TODO measure if this actually faster than the default implementation
213// impl ::hal::blocking::spi::Write<u8> for Spi {
214// type Error = Error;
215
216// fn write(&mut self, bytes: &[u8]) -> Result<(), Error> {
217// for byte in bytes {
218// 'l: loop {
219// let sr = self.spi.sr.read();
220
221// // ignore overruns because we don't care about the incoming data
222// // if sr.ovr().bit_is_set() {
223// // Err(nb::Error::Other(Error::Overrun))
224// // } else
225// if sr.modf().bit_is_set() {
226// return Err(Error::ModeFault);
227// } else if sr.crcerr().bit_is_set() {
228// return Err(Error::Crc);
229// } else if sr.txe().bit_is_set() {
230// // NOTE(write_volatile) see note above
231// unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *byte) }
232// break 'l;
233// } else {
234// // try again
235// }
236// }
237// }
238
239// // wait until the transmission of the last byte is done
240// while self.spi.sr.read().bsy().bit_is_set() {}
241
242// // clear OVR flag
243// unsafe {
244// ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
245// }
246// self.spi.sr.read();
247
248// Ok(())
249// }
250// }