1use 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 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#[derive(Debug)]
31#[non_exhaustive]
32pub enum Error {
33 Overrun,
35 ModeFault,
37 Crc,
39}
40
41pub type Result<T> = nb::Result<T, Error>;
42
43pub 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 {
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() .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.fifocfg
110 .modify(|_, w| w.enabletx().enabled().enablerx().enabled());
111 spi.cfg.modify(|_, w| w.enable().enabled());
112 Self {
118 spi,
119 pins,
120 _sck: PhantomData,
121 _mosi: PhantomData,
122 _miso: PhantomData,
123 _cs: PhantomData,
124 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 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 {
149 type Error = Error;
150
151 fn read(&mut self) -> Result<u8> {
152 if self.spi.fifostat.read().rxnotempty().bit_is_set() {
154 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 self.return_on_error()?;
168 if self.spi.fifostat.read().txnotfull().bit_is_set() {
169 use ChipSelect::*;
172 match self.cs {
173 Chip0 => {
174 self.spi.fifowr.write(|w| unsafe {
175 w
176 .len()
178 .bits(7) .txssel0_n()
180 .asserted()
181 .txdata()
183 .bits(byte as u16)
184 });
185 }
186 Chip1 => {
187 self.spi.fifowr.write(|w| unsafe {
188 w
189 .len()
191 .bits(7) .txssel1_n()
193 .asserted()
194 .txdata()
196 .bits(byte as u16)
197 });
198 }
199 Chip2 => {
200 self.spi.fifowr.write(|w| unsafe {
201 w
202 .len()
204 .bits(7) .txssel2_n()
206 .asserted()
207 .txdata()
209 .bits(byte as u16)
210 });
211 }
212 Chip3 => {
213 self.spi.fifowr.write(|w| unsafe {
214 w
215 .len()
217 .bits(7) .txssel3_n()
219 .asserted()
220 .txdata()
222 .bits(byte as u16)
223 });
224 }
225 NoChips => {
226 self.spi.fifowr.write(|w| unsafe {
227 w
228 .len()
230 .bits(7) .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