1use core::marker::PhantomData;
41use core::{ops::Deref, ptr};
42
43pub use embedded_hal::spi::{Mode, Phase, Polarity};
44
45use crate::pac::SPI1;
48#[cfg(any(
49 feature = "stm32f030x8",
50 feature = "stm32f030xc",
51 feature = "stm32f042",
52 feature = "stm32f048",
53 feature = "stm32f051",
54 feature = "stm32f058",
55 feature = "stm32f070xb",
56 feature = "stm32f071",
57 feature = "stm32f072",
58 feature = "stm32f078",
59 feature = "stm32f091",
60 feature = "stm32f098",
61))]
62use crate::pac::SPI2;
63
64use crate::gpio::*;
65
66use crate::rcc::{Clocks, Rcc};
67
68use crate::time::Hertz;
69
70pub struct EightBit;
72
73pub struct SixteenBit;
75
76#[non_exhaustive]
78#[derive(Debug)]
79pub enum Error {
80 Overrun,
82 ModeFault,
84 Crc,
86}
87
88pub struct Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, WIDTH> {
90 spi: SPI,
91 pins: (SCKPIN, MISOPIN, MOSIPIN),
92 _width: PhantomData<WIDTH>,
93}
94
95pub trait SckPin<SPI> {}
96pub trait MisoPin<SPI> {}
97pub trait MosiPin<SPI> {}
98
99macro_rules! spi_pins {
100 ($($SPI:ident => {
101 sck => [$($sck:ty),+ $(,)*],
102 miso => [$($miso:ty),+ $(,)*],
103 mosi => [$($mosi:ty),+ $(,)*],
104 })+) => {
105 $(
106 $(
107 impl SckPin<crate::pac::$SPI> for $sck {}
108 )+
109 $(
110 impl MisoPin<crate::pac::$SPI> for $miso {}
111 )+
112 $(
113 impl MosiPin<crate::pac::$SPI> for $mosi {}
114 )+
115 )+
116 }
117}
118
119spi_pins! {
120 SPI1 => {
121 sck => [gpioa::PA5<Alternate<AF0>>, gpiob::PB3<Alternate<AF0>>],
122 miso => [gpioa::PA6<Alternate<AF0>>, gpiob::PB4<Alternate<AF0>>],
123 mosi => [gpioa::PA7<Alternate<AF0>>, gpiob::PB5<Alternate<AF0>>],
124 }
125}
126#[cfg(any(
127 feature = "stm32f030x4",
128 feature = "stm32f030x6",
129 feature = "stm32f031",
130 feature = "stm32f038",
131))]
132spi_pins! {
133 SPI1 => {
134 sck => [gpiob::PB13<Alternate<AF0>>],
135 miso => [gpiob::PB14<Alternate<AF0>>],
136 mosi => [gpiob::PB15<Alternate<AF0>>],
137 }
138}
139#[cfg(any(
158 feature = "stm32f030x8",
159 feature = "stm32f030xc",
160 feature = "stm32f042",
161 feature = "stm32f048",
162 feature = "stm32f051",
163 feature = "stm32f058",
164 feature = "stm32f070xb",
165 feature = "stm32f071",
166 feature = "stm32f072",
167 feature = "stm32f078",
168 feature = "stm32f091",
169 feature = "stm32f098",
170))]
171spi_pins! {
172 SPI2 => {
173 sck => [gpiob::PB13<Alternate<AF0>>],
174 miso => [gpiob::PB14<Alternate<AF0>>],
175 mosi => [gpiob::PB15<Alternate<AF0>>],
176 }
177}
178#[cfg(any(
179 feature = "stm32f030xc",
180 feature = "stm32f070xb",
181 feature = "stm32f071",
182 feature = "stm32f072",
183 feature = "stm32f078",
184 feature = "stm32f091",
185 feature = "stm32f098",
186))]
187spi_pins! {
188 SPI2 => {
189 sck => [gpiob::PB10<Alternate<AF5>>],
190 miso => [gpioc::PC2<Alternate<AF1>>],
191 mosi => [gpioc::PC3<Alternate<AF1>>],
192 }
193}
194#[cfg(any(
195 feature = "stm32f071",
196 feature = "stm32f072",
197 feature = "stm32f078",
198 feature = "stm32f091",
199 feature = "stm32f098",
200))]
201spi_pins! {
202 SPI2 => {
203 sck => [gpiod::PD1<Alternate<AF1>>],
204 miso => [gpiod::PD3<Alternate<AF1>>],
205 mosi => [gpiod::PD4<Alternate<AF1>>],
206 }
207}
208
209macro_rules! spi {
210 ($($SPI:ident: ($spi:ident, $spiXen:ident, $spiXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
211 $(
212 impl<SCKPIN, MISOPIN, MOSIPIN> Spi<$SPI, SCKPIN, MISOPIN, MOSIPIN, EightBit> {
213 pub fn $spi<F>(
215 spi: $SPI,
216 pins: (SCKPIN, MISOPIN, MOSIPIN),
217 mode: Mode,
218 speed: F,
219 rcc: &mut Rcc,
220 ) -> Self
221 where
222 SCKPIN: SckPin<$SPI>,
223 MISOPIN: MisoPin<$SPI>,
224 MOSIPIN: MosiPin<$SPI>,
225 F: Into<Hertz>,
226 {
227 rcc.regs.$apbenr.modify(|_, w| w.$spiXen().set_bit());
229
230 rcc.regs.$apbrstr.modify(|_, w| w.$spiXrst().set_bit());
232 rcc.regs.$apbrstr.modify(|_, w| w.$spiXrst().clear_bit());
233
234 Spi::<$SPI, SCKPIN, MISOPIN, MOSIPIN, EightBit> { spi, pins, _width: PhantomData }.spi_init(mode, speed, rcc.clocks).into_8bit_width()
235 }
236 }
237 )+
238 }
239}
240
241spi! {
242 SPI1: (spi1, spi1en, spi1rst, apb2enr, apb2rstr),
243}
244#[cfg(any(
245 feature = "stm32f030x8",
246 feature = "stm32f030xc",
247 feature = "stm32f042",
248 feature = "stm32f048",
249 feature = "stm32f051",
250 feature = "stm32f058",
251 feature = "stm32f070xb",
252 feature = "stm32f071",
253 feature = "stm32f072",
254 feature = "stm32f078",
255 feature = "stm32f091",
256 feature = "stm32f098",
257))]
258spi! {
259 SPI2: (spi2, spi2en, spi2rst, apb1enr, apb1rstr),
260}
261
262#[allow(dead_code)]
264type SpiRegisterBlock = crate::pac::spi1::RegisterBlock;
265
266impl<SPI, SCKPIN, MISOPIN, MOSIPIN, WIDTH> Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, WIDTH>
267where
268 SPI: Deref<Target = SpiRegisterBlock>,
269{
270 fn spi_init<F>(self, mode: Mode, speed: F, clocks: Clocks) -> Self
271 where
272 F: Into<Hertz>,
273 {
274 self.spi.cr1.modify(|_, w| w.spe().clear_bit());
276
277 let br = match clocks.pclk().0 / speed.into().0 {
278 0 => unreachable!(),
279 1..=2 => 0b000,
280 3..=5 => 0b001,
281 6..=11 => 0b010,
282 12..=23 => 0b011,
283 24..=47 => 0b100,
284 48..=95 => 0b101,
285 96..=191 => 0b110,
286 _ => 0b111,
287 };
288
289 self.spi.cr1.write(|w| {
297 w.cpha()
298 .bit(mode.phase == Phase::CaptureOnSecondTransition)
299 .cpol()
300 .bit(mode.polarity == Polarity::IdleHigh)
301 .mstr()
302 .set_bit()
303 .br()
304 .bits(br)
305 .lsbfirst()
306 .clear_bit()
307 .ssm()
308 .set_bit()
309 .ssi()
310 .set_bit()
311 .rxonly()
312 .clear_bit()
313 .bidimode()
314 .clear_bit()
315 .spe()
316 .set_bit()
317 });
318
319 self
320 }
321
322 pub fn into_8bit_width(self) -> Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, EightBit> {
323 self.spi
327 .cr2
328 .write(|w| w.frxth().set_bit().ds().eight_bit().ssoe().clear_bit());
329
330 Spi {
331 spi: self.spi,
332 pins: self.pins,
333 _width: PhantomData,
334 }
335 }
336
337 pub fn into_16bit_width(self) -> Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, SixteenBit> {
338 self.spi
342 .cr2
343 .write(|w| w.frxth().set_bit().ds().sixteen_bit().ssoe().clear_bit());
344
345 Spi {
346 spi: self.spi,
347 pins: self.pins,
348 _width: PhantomData,
349 }
350 }
351
352 fn set_send_only(&mut self) {
353 self.spi
354 .cr1
355 .modify(|_, w| w.bidimode().set_bit().bidioe().set_bit());
356 }
357
358 fn set_bidi(&mut self) {
359 self.spi
360 .cr1
361 .modify(|_, w| w.bidimode().clear_bit().bidioe().clear_bit());
362 }
363
364 fn check_read(&mut self) -> nb::Result<(), Error> {
365 let sr = self.spi.sr.read();
366
367 Err(if sr.ovr().bit_is_set() {
368 nb::Error::Other(Error::Overrun)
369 } else if sr.modf().bit_is_set() {
370 nb::Error::Other(Error::ModeFault)
371 } else if sr.crcerr().bit_is_set() {
372 nb::Error::Other(Error::Crc)
373 } else if sr.rxne().bit_is_set() {
374 return Ok(());
375 } else {
376 nb::Error::WouldBlock
377 })
378 }
379
380 fn send_buffer_size(&mut self) -> u8 {
381 match self.spi.sr.read().ftlvl().bits() {
382 0 => 4,
384 1 => 3,
386 2 => 2,
388 _ => 0,
390 }
391 }
392
393 fn check_send(&mut self) -> nb::Result<(), Error> {
394 let sr = self.spi.sr.read();
395
396 Err(if sr.ovr().bit_is_set() {
397 nb::Error::Other(Error::Overrun)
398 } else if sr.modf().bit_is_set() {
399 nb::Error::Other(Error::ModeFault)
400 } else if sr.crcerr().bit_is_set() {
401 nb::Error::Other(Error::Crc)
402 } else if sr.txe().bit_is_set() && sr.bsy().bit_is_clear() {
403 return Ok(());
404 } else {
405 nb::Error::WouldBlock
406 })
407 }
408
409 fn read_u8(&mut self) -> u8 {
410 unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) }
412 }
413
414 fn send_u8(&mut self, byte: u8) {
415 unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
417 }
418
419 fn read_u16(&mut self) -> u16 {
420 unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u16) }
422 }
423
424 fn send_u16(&mut self, byte: u16) {
425 unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u16, byte) }
427 }
428
429 pub fn release(self) -> (SPI, (SCKPIN, MISOPIN, MOSIPIN)) {
430 (self.spi, self.pins)
431 }
432}
433
434impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::blocking::spi::Transfer<u8>
435 for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, EightBit>
436where
437 SPI: Deref<Target = SpiRegisterBlock>,
438{
439 type Error = Error;
440
441 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
442 self.set_bidi();
444
445 for word in words.iter_mut() {
446 nb::block!(self.check_send())?;
447 self.send_u8(*word);
448 nb::block!(self.check_read())?;
449 *word = self.read_u8();
450 }
451
452 Ok(words)
453 }
454}
455
456impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::blocking::spi::Write<u8>
457 for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, EightBit>
458where
459 SPI: Deref<Target = SpiRegisterBlock>,
460{
461 type Error = Error;
462
463 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
464 let mut bufcap: u8 = 0;
465
466 self.set_send_only();
468
469 nb::block!(self.check_send())?;
471
472 for word in words {
474 while bufcap == 0 {
476 bufcap = self.send_buffer_size();
477 }
478
479 self.send_u8(*word);
480 bufcap -= 1;
481 }
482
483 nb::block!(self.check_send()).ok();
485 Ok(())
486 }
487}
488
489impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::blocking::spi::Transfer<u16>
490 for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, SixteenBit>
491where
492 SPI: Deref<Target = SpiRegisterBlock>,
493{
494 type Error = Error;
495
496 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
497 self.set_bidi();
499
500 for word in words.iter_mut() {
501 nb::block!(self.check_send())?;
502 self.send_u16(*word);
503 nb::block!(self.check_read())?;
504 *word = self.read_u16();
505 }
506
507 Ok(words)
508 }
509}
510
511impl<SPI, SCKPIN, MISOPIN, MOSIPIN> ::embedded_hal::blocking::spi::Write<u16>
512 for Spi<SPI, SCKPIN, MISOPIN, MOSIPIN, SixteenBit>
513where
514 SPI: Deref<Target = SpiRegisterBlock>,
515{
516 type Error = Error;
517
518 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
519 self.set_send_only();
521
522 for word in words {
523 nb::block!(self.check_send())?;
524 self.send_u16(*word);
525 }
526
527 nb::block!(self.check_send()).ok();
529 Ok(())
530 }
531}