stm32f0xx_hal/
spi.rs

1//! API for the integrate SPI peripherals
2//!
3//! The spi bus acts as the master (generating the clock) and you need to handle the CS separately.
4//!
5//! The most significant bit is transmitted first & only 8-bit transfers are supported
6//!
7//! # Example
8//! Echo incoming data in the next transfer
9//! ``` no_run
10//! use stm32f0xx_hal as hal;
11//!
12//! use crate::hal::pac;
13//! use crate::hal::prelude::*;
14//! use crate::hal::spi::{Spi, Mode, Phase, Polarity};
15//!
16//! cortex_m::interrupt::free(|cs| {
17//!     let mut p = pac::Peripherals::take().unwrap();
18//!     let mut rcc = p.RCC.constrain().freeze(&mut p.FLASH);
19//!
20//!     let gpioa = p.GPIOA.split(&mut rcc);
21//!
22//!     // Configure pins for SPI
23//!     let sck = gpioa.pa5.into_alternate_af0(cs);
24//!     let miso = gpioa.pa6.into_alternate_af0(cs);
25//!     let mosi = gpioa.pa7.into_alternate_af0(cs);
26//!
27//!     // Configure SPI with 1MHz rate
28//!     let mut spi = Spi::spi1(p.SPI1, (sck, miso, mosi), Mode {
29//!         polarity: Polarity::IdleHigh,
30//!         phase: Phase::CaptureOnSecondTransition,
31//!     }, 1.mhz(), &mut rcc);
32//!
33//!     let mut data = [0];
34//!     loop {
35//!         spi.transfer(&mut data).unwrap();
36//!     }
37//! });
38//! ```
39
40use core::marker::PhantomData;
41use core::{ops::Deref, ptr};
42
43pub use embedded_hal::spi::{Mode, Phase, Polarity};
44
45// TODO Put this inside the macro
46// Currently that causes a compiler panic
47use 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
70/// Typestate for 8-bit transfer size
71pub struct EightBit;
72
73/// Typestate for 16-bit transfer size
74pub struct SixteenBit;
75
76/// SPI error
77#[non_exhaustive]
78#[derive(Debug)]
79pub enum Error {
80    /// Overrun occurred
81    Overrun,
82    /// Mode fault occurred
83    ModeFault,
84    /// CRC error
85    Crc,
86}
87
88/// SPI abstraction
89pub 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// TODO: The ST SVD files are missing the entire PE enable register.
140//       So those pins do not exist in the register definitions.
141//       Re-enable as soon as this gets fixed.
142// #[cfg(any(
143//     feature = "stm32f071",
144//     feature = "stm32f072",
145//     feature = "stm32f078",
146//     feature = "stm32f091",
147//     feature = "stm32f098",
148// ))]
149// spi_pins! {
150//     SPI1 => {
151//         sck => [gpioe::PE13<Alternate<AF1>>],
152//         miso => [gpioe::PE14<Alternate<AF1>>],
153//         mosi => [gpioe::PE15<Alternate<AF1>>],
154//     }
155// }
156
157#[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                /// Creates a new spi instance
214                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                    /* Enable clock for SPI */
228                    rcc.regs.$apbenr.modify(|_, w| w.$spiXen().set_bit());
229
230                    /* Reset SPI */
231                    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// It's s needed for the impls, but rustc doesn't recognize that
263#[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        /* Make sure the SPI unit is disabled so we can configure it */
275        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        // mstr: master configuration
290        // lsbfirst: MSB first
291        // ssm: enable software slave management (NSS pin free for other uses)
292        // ssi: set nss high = master mode
293        // dff: 8 bit frames
294        // bidimode: 2-line unidirectional
295        // spe: enable the SPI bus
296        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        // FRXTH: 8-bit threshold on RX FIFO
324        // DS: 8-bit data size
325        // SSOE: cleared to disable SS output
326        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        // FRXTH: 16-bit threshold on RX FIFO
339        // DS: 8-bit data size
340        // SSOE: cleared to disable SS output
341        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            // FIFO empty
383            0 => 4,
384            // FIFO 1/4 full
385            1 => 3,
386            // FIFO 1/2 full
387            2 => 2,
388            // FIFO full
389            _ => 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        // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows reading a half-word)
411        unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) }
412    }
413
414    fn send_u8(&mut self, byte: u8) {
415        // NOTE(write_volatile) see note above
416        unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
417    }
418
419    fn read_u16(&mut self) -> u16 {
420        // NOTE(read_volatile) read only 2 bytes (the svd2rust API only allows reading a half-word)
421        unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u16) }
422    }
423
424    fn send_u16(&mut self, byte: u16) {
425        // NOTE(write_volatile) see note above
426        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        // We want to transfer bidirectionally, make sure we're in the correct mode
443        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        // We only want to send, so we don't need to worry about the receive buffer overflowing
467        self.set_send_only();
468
469        // Make sure we don't continue with an error condition
470        nb::block!(self.check_send())?;
471
472        // We have a 32 bit buffer to work with, so let's fill it before checking the status
473        for word in words {
474            // Loop as long as our send buffer is full
475            while bufcap == 0 {
476                bufcap = self.send_buffer_size();
477            }
478
479            self.send_u8(*word);
480            bufcap -= 1;
481        }
482
483        // Do one last status register check before continuing
484        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        // We want to transfer bidirectionally, make sure we're in the correct mode
498        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        // We only want to send, so we don't need to worry about the receive buffer overflowing
520        self.set_send_only();
521
522        for word in words {
523            nb::block!(self.check_send())?;
524            self.send_u16(*word);
525        }
526
527        // Do one last status register check before continuing
528        nb::block!(self.check_send()).ok();
529        Ok(())
530    }
531}