1use crate::peripherals::{Spi0, Spi1};
8use core::marker::PhantomData;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum SpiMode {
12 Mode0,
13 Mode1,
14 Mode2,
15 Mode3,
16}
17
18#[derive(Debug, Clone, Copy)]
19pub struct Config {
20 pub frequency: u32,
21 pub mode: SpiMode,
22 pub data_bits: u8,
23}
24
25impl Default for Config {
26 fn default() -> Self {
27 Self { frequency: 1_000_000, mode: SpiMode::Mode0, data_bits: 8 }
28 }
29}
30
31pub struct Spi<'d, T> {
32 idx: u8,
33 _peripheral: PhantomData<&'d T>,
34}
35
36fn spi_regs(idx: u8) -> &'static ws63_pac::spi0::RegisterBlock {
37 unsafe {
38 match idx {
39 0 => &*Spi0::ptr(),
40 1 => &*Spi1::ptr(),
41 _ => unreachable!(),
42 }
43 }
44}
45
46fn sckdv(pclk: u32, freq: u32) -> u32 {
53 let freq = if freq == 0 { 1 } else { freq };
54 let div = (pclk / freq).clamp(2, 0xFFFF);
55 div & !1 }
57
58const SPI_WAIT_LOOPS: u32 = 1_000_000;
62
63#[inline]
64fn wait_until(mut ready: impl FnMut() -> bool) -> Result<(), SpiError> {
65 let mut n = SPI_WAIT_LOOPS;
66 while !ready() {
67 n -= 1;
68 if n == 0 {
69 return Err(SpiError::Timeout);
70 }
71 }
72 Ok(())
73}
74
75impl<'d> Spi<'d, Spi0<'d>> {
76 pub fn new_spi0(_spi: Spi0<'d>, config: Config) -> Self {
77 configure_spi(0, &config);
78 Self { idx: 0, _peripheral: PhantomData }
79 }
80}
81impl<'d> Spi<'d, Spi1<'d>> {
82 pub fn new_spi1(_spi: Spi1<'d>, config: Config) -> Self {
83 configure_spi(1, &config);
84 Self { idx: 1, _peripheral: PhantomData }
85 }
86}
87
88const CLDO_CRG_DIV_CTL3: usize = 0x4400_1114; const CLDO_CRG_CLK_SEL: usize = 0x4400_1134; const CLDO_SUB_CRG_CKEN_CTL1: usize = 0x4400_1104; const SPI_PLL_ROOT_MHZ: u32 = 480; fn configure_spi_source_clock() {
107 let ssi_mhz = (crate::soc::ws63::SPI_CLOCK_HZ / 1_000_000).max(1);
109 let div = (SPI_PLL_ROOT_MHZ / ssi_mhz).clamp(1, 0x1F);
110 unsafe {
113 let div_ctl3 = CLDO_CRG_DIV_CTL3 as *mut u32;
114 let v = core::ptr::read_volatile(div_ctl3) & !(1 << 10);
116 core::ptr::write_volatile(div_ctl3, v);
117 let v = (core::ptr::read_volatile(div_ctl3) & !(0x1F << 5) & !0x1F) | ((div & 0x1F) << 5) | 0x1;
118 core::ptr::write_volatile(div_ctl3, v);
119 core::ptr::write_volatile(div_ctl3, core::ptr::read_volatile(div_ctl3) | (1 << 10));
120
121 let cken1 = CLDO_SUB_CRG_CKEN_CTL1 as *mut u32;
123 let clk_sel = CLDO_CRG_CLK_SEL as *mut u32;
124 core::ptr::write_volatile(cken1, core::ptr::read_volatile(cken1) & !(1 << 25));
125 core::ptr::write_volatile(clk_sel, core::ptr::read_volatile(clk_sel) | (1 << 6));
126 core::ptr::write_volatile(cken1, core::ptr::read_volatile(cken1) | (1 << 25));
127 }
128}
129
130fn configure_spi(idx: u8, config: &Config) {
131 configure_spi_source_clock();
132 let r = spi_regs(idx);
133 r.spi_er().write(|w| unsafe { w.bits(0) });
134 let pclk = crate::soc::ws63::SPI_CLOCK_HZ;
135 r.spi_brs().write(|w| unsafe { w.bits(sckdv(pclk, config.frequency)) });
136
137 let mut ctra = 0u32;
138 match config.mode {
139 SpiMode::Mode0 => {}
140 SpiMode::Mode1 => ctra |= 1 << 3,
141 SpiMode::Mode2 => ctra |= 1 << 4,
142 SpiMode::Mode3 => ctra |= (1 << 3) | (1 << 4),
143 }
144 ctra |= ((config.data_bits.saturating_sub(1)) as u32) << 13;
145 r.spi_ctra().write(|w| unsafe { w.bits(ctra) });
148 r.spi_slenr().write(|w| unsafe { w.bits(0x1) });
149 r.spi_er().write(|w| unsafe { w.bits(0x1) });
150}
151
152impl<T> Spi<'_, T> {
153 pub fn transfer(&mut self, write: &[u8], read: &mut [u8]) -> Result<(), SpiError> {
154 let r = spi_regs(self.idx);
155 let len = write.len().max(read.len());
156 for i in 0..len {
157 let tx = if i < write.len() { write[i] as u32 } else { 0 };
158 wait_until(|| r.spi_wsr().read().txfnf().bit_is_set())?;
159 unsafe { r.spi_dr().write(|w| w.bits(tx)) };
160 wait_until(|| r.spi_wsr().read().rxfne().bit_is_set())?;
161 let rx = r.spi_dr().read().bits();
162 if i < read.len() {
163 read[i] = rx as u8;
164 }
165 }
166 Ok(())
167 }
168
169 pub fn write(&mut self, data: &[u8]) -> Result<(), SpiError> {
170 let r = spi_regs(self.idx);
171 for &byte in data {
172 wait_until(|| r.spi_wsr().read().txfnf().bit_is_set())?;
173 unsafe { r.spi_dr().write(|w| w.bits(byte as u32)) };
174 }
175 Ok(())
176 }
177
178 pub fn register_block(&self) -> &'static ws63_pac::spi0::RegisterBlock {
179 spi_regs(self.idx)
180 }
181
182 pub fn wait_idle(&self) -> Result<(), SpiError> {
184 let r = spi_regs(self.idx);
185 wait_until(|| r.spi_wsr().read().txfe().bit_is_set())?;
187 wait_until(|| !r.spi_wsr().read().busy().bit_is_set())?;
188 Ok(())
189 }
190}
191
192fn transfer_in_place_on(idx: u8, buf: &mut [u8]) -> Result<(), SpiError> {
193 let r = spi_regs(idx);
194 for byte in buf.iter_mut() {
195 let tx = *byte as u32;
196 wait_until(|| r.spi_wsr().read().txfnf().bit_is_set())?;
197 unsafe { r.spi_dr().write(|w| w.bits(tx)) };
198 wait_until(|| r.spi_wsr().read().rxfne().bit_is_set())?;
199 *byte = r.spi_dr().read().bits() as u8;
200 }
201 Ok(())
202}
203
204#[derive(Debug)]
205pub enum SpiError {
206 Overflow,
207 Timeout,
208}
209
210impl embedded_hal::spi::Error for SpiError {
211 fn kind(&self) -> embedded_hal::spi::ErrorKind {
212 embedded_hal::spi::ErrorKind::Other
213 }
214}
215impl embedded_hal::spi::ErrorType for Spi<'_, Spi0<'_>> {
216 type Error = SpiError;
217}
218impl embedded_hal::spi::SpiBus for Spi<'_, Spi0<'_>> {
219 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
220 self.transfer(write, read)
221 }
222 fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
223 self.transfer(&[], buf)
224 }
225 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
226 Spi::write(self, buf)
227 }
228 fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
229 transfer_in_place_on(self.idx, buf)
230 }
231 fn flush(&mut self) -> Result<(), Self::Error> {
232 self.wait_idle()
233 }
234}
235
236impl embedded_hal::spi::ErrorType for Spi<'_, Spi1<'_>> {
238 type Error = SpiError;
239}
240impl embedded_hal::spi::SpiBus for Spi<'_, Spi1<'_>> {
241 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
242 self.transfer(write, read)
243 }
244 fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
245 self.transfer(&[], buf)
246 }
247 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
248 Spi::write(self, buf)
249 }
250 fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
251 transfer_in_place_on(self.idx, buf)
252 }
253 fn flush(&mut self) -> Result<(), Self::Error> {
254 self.wait_idle()
255 }
256}
257
258#[cfg(test)]
261mod tests {
262 use super::sckdv;
263 use crate::soc::ws63::SPI_CLOCK_HZ;
264
265 #[test]
266 fn test_sckdv_basic() {
267 assert_eq!(sckdv(SPI_CLOCK_HZ, 1_000_000), 160);
269 }
270
271 #[test]
272 fn test_sckdv_is_even_and_min_two() {
273 assert_eq!(sckdv(SPI_CLOCK_HZ, 1_000_000) & 1, 0);
275 assert_eq!(sckdv(SPI_CLOCK_HZ, SPI_CLOCK_HZ), 2);
277 assert_eq!(sckdv(SPI_CLOCK_HZ, u32::MAX), 2);
278 }
279
280 #[test]
281 fn test_sckdv_zero_freq_guard() {
282 assert_eq!(sckdv(SPI_CLOCK_HZ, 0), 0xFFFE);
284 }
285
286 #[test]
287 fn test_sckdv_clamps_at_max() {
288 assert_eq!(sckdv(SPI_CLOCK_HZ, 1000), 0xFFFE);
289 }
290}
291
292#[cfg(test)]
295mod proptests {
296 use super::sckdv;
297 use proptest::prelude::*;
298
299 proptest! {
300 #[test]
302 fn sckdv_in_valid_range(freq in any::<u32>()) {
303 let d = sckdv(crate::soc::ws63::SPI_CLOCK_HZ, freq);
304 prop_assert!((2..=0xFFFE).contains(&d), "divisor {} out of range for freq={}", d, freq);
305 prop_assert_eq!(d & 1, 0, "divisor {} not even for freq={}", d, freq);
306 }
307
308 #[test]
310 fn sckdv_monotonic(freq1 in 1u32.., freq2 in 1u32..) {
311 let pclk = crate::soc::ws63::SPI_CLOCK_HZ;
312 let d1 = sckdv(pclk, freq1);
313 let d2 = sckdv(pclk, freq2);
314 if freq1 > freq2 {
315 prop_assert!(d1 <= d2, "freq1={}(d={}) freq2={}(d={})", freq1, d1, freq2, d2);
316 }
317 }
318 }
319}
320
321#[cfg(feature = "async")]
328mod asynch_impl {
329 use super::{Spi, Spi0, Spi1};
330
331 macro_rules! async_spi {
332 ($inst:ty) => {
333 impl embedded_hal_async::spi::SpiBus<u8> for Spi<'_, $inst> {
334 async fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
335 embedded_hal::spi::SpiBus::read(self, buf)
336 }
337 async fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
338 embedded_hal::spi::SpiBus::write(self, buf)
339 }
340 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
341 embedded_hal::spi::SpiBus::transfer(self, read, write)
342 }
343 async fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
344 embedded_hal::spi::SpiBus::transfer_in_place(self, buf)
345 }
346 async fn flush(&mut self) -> Result<(), Self::Error> {
347 embedded_hal::spi::SpiBus::flush(self)
348 }
349 }
350 };
351 }
352 async_spi!(Spi0<'_>);
353 async_spi!(Spi1<'_>);
354}