1use crate::peripherals::{Spi0, Spi1};
5use core::marker::PhantomData;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum SpiMode {
9 Mode0,
10 Mode1,
11 Mode2,
12 Mode3,
13}
14
15#[derive(Debug, Clone, Copy)]
16pub struct Config {
17 pub frequency: u32,
18 pub mode: SpiMode,
19 pub data_bits: u8,
20}
21
22impl Default for Config {
23 fn default() -> Self {
24 Self { frequency: 1_000_000, mode: SpiMode::Mode0, data_bits: 8 }
25 }
26}
27
28pub struct Spi<'d, T> {
29 idx: u8,
30 _peripheral: PhantomData<&'d T>,
31}
32
33fn spi_regs(idx: u8) -> &'static ws63_pac::spi0::RegisterBlock {
34 unsafe {
35 match idx {
36 0 => &*Spi0::ptr(),
37 1 => &*Spi1::ptr(),
38 _ => unreachable!(),
39 }
40 }
41}
42
43fn sckdv(pclk: u32, freq: u32) -> u32 {
50 let freq = if freq == 0 { 1 } else { freq };
51 let div = (pclk / freq).clamp(2, 0xFFFF);
52 div & !1 }
54
55const SPI_WAIT_LOOPS: u32 = 1_000_000;
59
60#[inline]
61fn wait_until(mut ready: impl FnMut() -> bool) -> Result<(), SpiError> {
62 let mut n = SPI_WAIT_LOOPS;
63 while !ready() {
64 n -= 1;
65 if n == 0 {
66 return Err(SpiError::Timeout);
67 }
68 }
69 Ok(())
70}
71
72impl<'d> Spi<'d, Spi0<'d>> {
73 pub fn new_spi0(_spi: Spi0<'d>, config: Config) -> Self {
74 configure_spi(0, &config);
75 Self { idx: 0, _peripheral: PhantomData }
76 }
77}
78impl<'d> Spi<'d, Spi1<'d>> {
79 pub fn new_spi1(_spi: Spi1<'d>, config: Config) -> Self {
80 configure_spi(1, &config);
81 Self { idx: 1, _peripheral: PhantomData }
82 }
83}
84
85fn configure_spi(idx: u8, config: &Config) {
86 let r = spi_regs(idx);
87 r.spi_er().write(|w| unsafe { w.bits(0) });
88 let pclk = crate::soc::ws63::SYSTEM_CLOCK_HZ;
89 r.spi_brs().write(|w| unsafe { w.bits(sckdv(pclk, config.frequency)) });
90
91 let mut ctra = 0u32;
92 match config.mode {
93 SpiMode::Mode0 => {}
94 SpiMode::Mode1 => ctra |= 1 << 3,
95 SpiMode::Mode2 => ctra |= 1 << 4,
96 SpiMode::Mode3 => ctra |= (1 << 3) | (1 << 4),
97 }
98 ctra |= ((config.data_bits.saturating_sub(1)) as u32) << 13;
99 r.spi_ctra().write(|w| unsafe { w.bits(ctra) });
102 r.spi_slenr().write(|w| unsafe { w.bits(0x1) });
103 r.spi_er().write(|w| unsafe { w.bits(0x1) });
104}
105
106impl<T> Spi<'_, T> {
107 pub fn transfer(&mut self, write: &[u8], read: &mut [u8]) -> Result<(), SpiError> {
108 let r = spi_regs(self.idx);
109 let len = write.len().max(read.len());
110 for i in 0..len {
111 let tx = if i < write.len() { write[i] as u32 } else { 0 };
112 wait_until(|| r.spi_wsr().read().txfnf().bit_is_set())?;
113 unsafe { r.spi_dr().write(|w| w.bits(tx)) };
114 wait_until(|| r.spi_wsr().read().rxfne().bit_is_set())?;
115 let rx = r.spi_dr().read().bits();
116 if i < read.len() {
117 read[i] = rx as u8;
118 }
119 }
120 Ok(())
121 }
122
123 pub fn write(&mut self, data: &[u8]) -> Result<(), SpiError> {
124 let r = spi_regs(self.idx);
125 for &byte in data {
126 wait_until(|| r.spi_wsr().read().txfnf().bit_is_set())?;
127 unsafe { r.spi_dr().write(|w| w.bits(byte as u32)) };
128 }
129 Ok(())
130 }
131
132 pub fn register_block(&self) -> &'static ws63_pac::spi0::RegisterBlock {
133 spi_regs(self.idx)
134 }
135
136 pub fn wait_idle(&self) -> Result<(), SpiError> {
138 let r = spi_regs(self.idx);
139 wait_until(|| r.spi_wsr().read().txfe().bit_is_set())?;
141 wait_until(|| !r.spi_wsr().read().busy().bit_is_set())?;
142 Ok(())
143 }
144}
145
146fn transfer_in_place_on(idx: u8, buf: &mut [u8]) -> Result<(), SpiError> {
147 let r = spi_regs(idx);
148 for byte in buf.iter_mut() {
149 let tx = *byte as u32;
150 wait_until(|| r.spi_wsr().read().txfnf().bit_is_set())?;
151 unsafe { r.spi_dr().write(|w| w.bits(tx)) };
152 wait_until(|| r.spi_wsr().read().rxfne().bit_is_set())?;
153 *byte = r.spi_dr().read().bits() as u8;
154 }
155 Ok(())
156}
157
158#[derive(Debug)]
159pub enum SpiError {
160 Overflow,
161 Timeout,
162}
163
164impl embedded_hal::spi::Error for SpiError {
165 fn kind(&self) -> embedded_hal::spi::ErrorKind {
166 embedded_hal::spi::ErrorKind::Other
167 }
168}
169impl embedded_hal::spi::ErrorType for Spi<'_, Spi0<'_>> {
170 type Error = SpiError;
171}
172impl embedded_hal::spi::SpiBus for Spi<'_, Spi0<'_>> {
173 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
174 self.transfer(write, read)
175 }
176 fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
177 self.transfer(&[], buf)
178 }
179 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
180 Spi::write(self, buf)
181 }
182 fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
183 transfer_in_place_on(self.idx, buf)
184 }
185 fn flush(&mut self) -> Result<(), Self::Error> {
186 self.wait_idle()
187 }
188}
189
190impl embedded_hal::spi::ErrorType for Spi<'_, Spi1<'_>> {
192 type Error = SpiError;
193}
194impl embedded_hal::spi::SpiBus for Spi<'_, Spi1<'_>> {
195 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
196 self.transfer(write, read)
197 }
198 fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
199 self.transfer(&[], buf)
200 }
201 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
202 Spi::write(self, buf)
203 }
204 fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
205 transfer_in_place_on(self.idx, buf)
206 }
207 fn flush(&mut self) -> Result<(), Self::Error> {
208 self.wait_idle()
209 }
210}
211
212#[cfg(test)]
215mod tests {
216 use super::sckdv;
217 use crate::soc::ws63::SYSTEM_CLOCK_HZ;
218
219 #[test]
220 fn test_sckdv_basic() {
221 assert_eq!(sckdv(SYSTEM_CLOCK_HZ, 1_000_000), 240);
223 }
224
225 #[test]
226 fn test_sckdv_is_even_and_min_two() {
227 assert_eq!(sckdv(SYSTEM_CLOCK_HZ, 1_000_000) & 1, 0);
229 assert_eq!(sckdv(SYSTEM_CLOCK_HZ, SYSTEM_CLOCK_HZ), 2);
231 assert_eq!(sckdv(SYSTEM_CLOCK_HZ, u32::MAX), 2);
232 }
233
234 #[test]
235 fn test_sckdv_zero_freq_guard() {
236 assert_eq!(sckdv(SYSTEM_CLOCK_HZ, 0), 0xFFFE);
238 }
239
240 #[test]
241 fn test_sckdv_clamps_at_max() {
242 assert_eq!(sckdv(SYSTEM_CLOCK_HZ, 1000), 0xFFFE);
243 }
244}
245
246#[cfg(test)]
249mod proptests {
250 use super::sckdv;
251 use proptest::prelude::*;
252
253 proptest! {
254 #[test]
256 fn sckdv_in_valid_range(freq in any::<u32>()) {
257 let d = sckdv(crate::soc::ws63::SYSTEM_CLOCK_HZ, freq);
258 prop_assert!((2..=0xFFFE).contains(&d), "divisor {} out of range for freq={}", d, freq);
259 prop_assert_eq!(d & 1, 0, "divisor {} not even for freq={}", d, freq);
260 }
261
262 #[test]
264 fn sckdv_monotonic(freq1 in 1u32.., freq2 in 1u32..) {
265 let pclk = crate::soc::ws63::SYSTEM_CLOCK_HZ;
266 let d1 = sckdv(pclk, freq1);
267 let d2 = sckdv(pclk, freq2);
268 if freq1 > freq2 {
269 prop_assert!(d1 <= d2, "freq1={}(d={}) freq2={}(d={})", freq1, d1, freq2, d2);
270 }
271 }
272 }
273}