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