lpc55s6x_hal/drivers/
spi.rs

1///! There are 8 "normal" SPIs and on high-speed SPI.
2///! The high-speed SPI is tied to Flexcomm8, which it does not
3///! share with any other peripherals.
4///!
5///! SPI3, SPI4, and this high-speed SPI8 have 4 possible chip selects,
6///! whereas the others have two.
7///
8///
9use core::marker::PhantomData;
10
11pub use crate::traits::wg::spi::{
12    FullDuplex,
13    Mode,
14    Phase,
15    Polarity,
16};
17use crate::typestates::pin::{
18    flexcomm::{
19        // Trait marking I2C peripherals and pins
20        Spi,
21        SpiPins,
22        ChipSelect,
23    },
24    PinId,
25};
26use crate::time::{
27    Hertz,
28};
29
30pub mod prelude {
31    pub use super::SpiMaster;
32    pub use super::Error as SpiError;
33    pub use super::Result as SpiResult;
34}
35
36/// SPI error
37/// TODO: Use the actual ones from the chip
38#[derive(Debug)]
39pub enum Error {
40    /// Overrun occurred
41    Overrun,
42    /// Mode fault occurred
43    ModeFault,
44    /// CRC error
45    Crc,
46    #[doc(hidden)]
47    _Extensible,
48}
49
50pub type Result<T> = nb::Result<T, Error>;
51
52/// SPI peripheral operating in master mode
53pub struct SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
54where
55    SCK: PinId,
56    MOSI: PinId,
57    MISO: PinId,
58    CS: PinId,
59    SPI: Spi,
60    PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
61{
62    spi: SPI,
63    pins: PINS,
64    _sck: PhantomData<SCK>,
65    _mosi: PhantomData<MOSI>,
66    _miso: PhantomData<MISO>,
67    _cs: PhantomData<CS>,
68    cs: ChipSelect,
69}
70
71impl<SCK, MOSI, MISO, CS, SPI, PINS> SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
72where
73    SCK: PinId,
74    MOSI: PinId,
75    MISO: PinId,
76    CS: PinId,
77    SPI: Spi,
78    PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
79    // CSPIN: SpiSselPin<CS, SPI>,
80{
81    pub fn new<Speed: Into<Hertz>>(spi: SPI, pins: PINS, speed: Speed, mode: Mode) -> Self {
82        let speed: Hertz = speed.into();
83        let speed: u32 = speed.0;
84
85        while spi.stat.read().mstidle().bit_is_clear() { continue; }
86
87        spi.fifocfg.modify(|_, w| w
88            .enabletx().disabled()
89            .enablerx().disabled()
90        );
91        spi.cfg.modify(|_, w| w
92            .enable().disabled()
93            .master().master_mode()
94            .lsbf().standard() // MSB first
95            .cpha().bit(mode.phase == Phase::CaptureOnSecondTransition)
96            .cpol().bit(mode.polarity == Polarity::IdleHigh)
97            .loop_().disabled()
98        );
99
100        let div: u32 = 12_000_000 / speed - 1;
101        assert!(div <= 0xFFFF);
102        spi.div.modify(|_, w| unsafe { w.divval().bits(div as u16) } );
103
104        // spi.raw.fifowr.write(|w| w
105        //     .rxignore().ignore() // otherwise transmit halts if FIFORD buffer is full
106        // );
107        // spi.raw.fifotrig.modify(|_, w| w
108        //     .enabletx().enabled()
109        //     .enablerx().enabled()
110        // );
111        spi.fifocfg.modify(|_, w| w
112            .enabletx().enabled()
113            .enablerx().enabled()
114        );
115        spi.cfg.modify(|_, w| w
116            .enable().enabled()
117        );
118        // match pins.3.CS {
119        //     0...3 => {},
120        //     _ => { panic!() },
121        // }
122
123        Self {
124            spi,
125            pins,
126            _sck: PhantomData,
127            _mosi: PhantomData,
128            _miso: PhantomData,
129            _cs: PhantomData,
130            // _cs_pin: PhantomData,
131            cs: PINS::CS,
132        }
133    }
134
135    pub fn release(self) -> (SPI, PINS) {
136        (self.spi, self.pins)
137    }
138
139    fn return_on_error(&self) -> Result<()> {
140        // TODO: error readout
141        Ok(())
142    }
143
144}
145
146impl<SCK, MOSI, MISO, CS, SPI, PINS> FullDuplex<u8> for SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
147where
148    SCK: PinId,
149    MOSI: PinId,
150    MISO: PinId,
151    CS: PinId,
152    SPI: Spi,
153    PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
154    // CSPIN: SpiSselPin<CS, SPI>,
155{
156    type Error = Error;
157
158    fn read(&mut self) -> Result<u8> {
159        // self.return_on_error()?;
160        if self.spi.fifostat.read().rxnotempty().bit_is_clear() {
161            // TODO: not sure how to turn this from u32 (or u16??) into u8
162            // Or whatever...
163            let byte = self.spi.fiford.read().rxdata().bits();
164            Ok(byte as u8)
165        } else {
166            Err(nb::Error::WouldBlock)
167        }
168    }
169
170    fn send(&mut self, byte: u8) -> Result<()> {
171
172        // NB: UM says "Do not read-modify-write the register."
173        // - writing 0 to upper-half word means: keep previous control settings
174
175        self.return_on_error()?;
176        if self.spi.fifostat.read().txempty().bit_is_set() {
177            // NB: we set 8 bits in constructor
178            // We could probably repeat this here
179            use ChipSelect::*;
180            match self.cs {
181                Chip0 =>  {
182                    self.spi.fifowr.write(|w| unsafe { w
183                        // control
184                        .len().bits(7) // 8 bits
185                        .txssel0_n().asserted()
186                        // data
187                        .txdata().bits(byte as u16)
188                    });
189                },
190                Chip1 =>  {
191                    self.spi.fifowr.write(|w| unsafe { w
192                        // control
193                        .len().bits(7) // 8 bits
194                        .txssel1_n().asserted()
195                        // data
196                        .txdata().bits(byte as u16)
197                    });
198                },
199                Chip2 =>  {
200                    self.spi.fifowr.write(|w| unsafe { w
201                        // control
202                        .len().bits(7) // 8 bits
203                        .txssel2_n().asserted()
204                        // data
205                        .txdata().bits(byte as u16)
206                    });
207                },
208                Chip3 =>  {
209                    self.spi.fifowr.write(|w| unsafe { w
210                        // control
211                        .len().bits(7) // 8 bits
212                        .txssel3_n().asserted()
213                        // data
214                        .txdata().bits(byte as u16)
215                    });
216                },
217                AllChips =>  {
218                    self.spi.fifowr.write(|w| unsafe { w
219                        // control
220                        .len().bits(7) // 8 bits
221                        .txssel0_n().asserted()
222                        .txssel1_n().asserted()
223                        .txssel2_n().asserted()
224                        .txssel3_n().asserted()
225                        // data
226                        .txdata().bits(byte as u16)
227                    });
228                },
229            }
230            Ok(())
231        } else {
232            Err(nb::Error::WouldBlock)
233        }
234    }
235}
236
237impl<SCK, MOSI, MISO, CS, SPI, PINS> crate::traits::wg::blocking::spi::transfer::Default<u8>
238for
239    SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
240where
241    SCK: PinId,
242    MOSI: PinId,
243    MISO: PinId,
244    CS: PinId,
245    SPI: Spi,
246    PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
247{}
248
249impl<SCK, MOSI, MISO, CS, SPI, PINS> crate::traits::wg::blocking::spi::write::Default<u8>
250for
251    SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
252where
253    SCK: PinId,
254    MOSI: PinId,
255    MISO: PinId,
256    CS: PinId,
257    SPI: Spi,
258    PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
259{}
260
261// impl<SPI, PINS> crate::traits::wg::blocking::spi::transfer::Default<u8> for SpiMaster<SPI, PINS>
262// where
263//     SPI: Spi
264// {}
265
266// impl<SPI, PINS> embedded_hal::blocking::spi::write::Default<u8> for SpiMaster<SPI, PINS>
267// where
268//     SPI: Deref<Target = spi1::RegisterBlock>,
269// {}
270