atsamd_hal/sercom/spi/
reg.rs

1use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
2
3use crate::ehal;
4
5#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
6use crate::pac::sercom0::Spi;
7#[hal_cfg("sercom0-d5x")]
8use crate::pac::sercom0::Spim;
9
10#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
11use crate::pac::sercom0::spi::ctrla::Modeselect;
12#[hal_cfg("sercom0-d5x")]
13use crate::pac::sercom0::spim::ctrla::Modeselect;
14
15use crate::sercom::Sercom;
16use crate::time::Hertz;
17
18use super::{BitOrder, DataWidth, Error, Flags, Phase, Polarity, Status};
19
20//==============================================================================
21// Registers
22//==============================================================================
23
24/// Define a task-focused register interface for SPI peripherals
25///
26/// This struct acts to define a task-focused, rather than register-focused, API
27/// for a SERCOM configured as an SPI peripheral. It also serves to erase the
28/// inherent interior mutability of the PAC [`Sercom`] type, which allows it to
29/// implement [`Sync`].
30pub(super) struct Registers<S: Sercom> {
31    pub sercom: S,
32}
33
34// Safety: The [`Registers`] struct erases interior mutability, so this is now
35// safe.
36unsafe impl<S: Sercom> Sync for Registers<S> {}
37
38impl<S: Sercom> Registers<S> {
39    #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
40    #[inline]
41    pub fn spi(&self) -> &Spi {
42        self.sercom.spi()
43    }
44
45    #[hal_cfg("sercom0-d5x")]
46    #[inline]
47    pub fn spi(&self) -> &Spim {
48        self.sercom.spim()
49    }
50
51    /// Reset the SERCOM peripheral
52    #[inline]
53    pub fn reset(&mut self) {
54        self.spi().ctrla().write(|w| w.swrst().set_bit());
55        while self.spi().syncbusy().read().swrst().bit_is_set() {}
56    }
57
58    /// Configure the DIPO and DOPO values
59    #[inline]
60    pub fn set_dipo_dopo(&mut self, dipo_dopo: (u8, u8)) {
61        let (dipo, dopo) = dipo_dopo;
62        self.spi().ctrla().modify(|_, w| unsafe {
63            w.dipo().bits(dipo);
64            w.dopo().bits(dopo)
65        });
66    }
67
68    /// Configure the SPI operating mode
69    ///
70    /// For maximum flexibility, this module chooses to always operate in 32-bit
71    /// extension mode. The LENGTH counter is used to control the number of byes
72    /// in each SPI transaction. Due to a hardware bug, ICSPACE must be at least
73    /// one. See the silicon errata for more details.
74    #[inline]
75    #[hal_macro_helper]
76    pub fn set_op_mode(&mut self, mode: Modeselect, mssen: bool) {
77        self.spi().ctrla().modify(|_, w| w.mode().variant(mode));
78        self.spi().ctrlb().modify(|_, w| w.mssen().bit(mssen));
79        #[hal_cfg("sercom0-d5x")]
80        self.spi().ctrlc().write(|w| unsafe {
81            w.data32b().data_trans_32bit();
82            w.icspace().bits(1)
83        });
84        while self.spi().syncbusy().read().ctrlb().bit_is_set() {}
85    }
86
87    /// Return the current transaction length
88    #[hal_cfg("sercom0-d5x")]
89    #[inline]
90    pub fn get_length(&self) -> u8 {
91        self.spi().length().read().len().bits()
92    }
93
94    /// Set the transaction length
95    #[hal_cfg("sercom0-d5x")]
96    #[inline]
97    pub fn set_length(&mut self, length: u8) {
98        let length = if length == 0 { 1 } else { length };
99        self.spi().length().write(|w| unsafe {
100            w.len().bits(length);
101            w.lenen().set_bit()
102        });
103        while self.spi().syncbusy().read().length().bit_is_set() {}
104    }
105
106    /// Set the character size
107    #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
108    #[inline]
109    pub fn set_char_size(&mut self, bits: u8) {
110        self.spi()
111            .ctrlb()
112            .modify(|_, w| unsafe { w.chsize().bits(bits) });
113    }
114
115    /// Get the clock polarity
116    #[inline]
117    pub fn get_cpol(&self) -> Polarity {
118        let cpol = self.spi().ctrla().read().cpol().bit();
119        match cpol {
120            false => Polarity::IdleLow,
121            true => Polarity::IdleHigh,
122        }
123    }
124
125    /// Set the clock polarity
126    #[inline]
127    pub fn set_cpol(&mut self, cpol: Polarity) {
128        let cpol = match cpol {
129            Polarity::IdleLow => false,
130            Polarity::IdleHigh => true,
131        };
132        self.spi().ctrla().modify(|_, w| w.cpol().bit(cpol));
133    }
134
135    /// Get the clock phase
136    #[inline]
137    pub fn get_cpha(&self) -> Phase {
138        let cpha = self.spi().ctrla().read().cpha().bit();
139        match cpha {
140            false => Phase::CaptureOnFirstTransition,
141            true => Phase::CaptureOnSecondTransition,
142        }
143    }
144
145    /// Set the clock phase
146    #[inline]
147    pub fn set_cpha(&mut self, cpha: Phase) {
148        let cpha = match cpha {
149            Phase::CaptureOnFirstTransition => false,
150            Phase::CaptureOnSecondTransition => true,
151        };
152        self.spi().ctrla().modify(|_, w| w.cpha().bit(cpha));
153    }
154
155    /// Get the SPI mode (clock polarity & phase)
156    #[inline]
157    pub fn get_spi_mode(&self) -> ehal::spi::Mode {
158        let reg = self.spi().ctrla().read();
159        let cpol = reg.cpol().bit();
160        let cpha = reg.cpha().bit();
161        let polarity = match cpol {
162            false => Polarity::IdleLow,
163            true => Polarity::IdleHigh,
164        };
165        let phase = match cpha {
166            false => Phase::CaptureOnFirstTransition,
167            true => Phase::CaptureOnSecondTransition,
168        };
169        ehal::spi::Mode { polarity, phase }
170    }
171
172    /// Set the SPI mode (clock polarity & phase)
173    #[inline]
174    pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) {
175        let cpol = match mode.polarity {
176            Polarity::IdleLow => false,
177            Polarity::IdleHigh => true,
178        };
179        let cpha = match mode.phase {
180            Phase::CaptureOnFirstTransition => false,
181            Phase::CaptureOnSecondTransition => true,
182        };
183        self.spi().ctrla().modify(|_, w| {
184            w.cpol().bit(cpol);
185            w.cpha().bit(cpha)
186        });
187    }
188
189    /// Get the bit order of transmission (MSB/LSB first)
190    #[inline]
191    pub fn get_bit_order(&self) -> BitOrder {
192        let order = self.spi().ctrla().read().dord().bit();
193        match order {
194            false => BitOrder::MsbFirst,
195            true => BitOrder::LsbFirst,
196        }
197    }
198
199    /// Set the bit order of transmission (MSB/LSB first)
200    #[inline]
201    pub fn set_bit_order(&mut self, order: BitOrder) {
202        let order = match order {
203            BitOrder::MsbFirst => false,
204            BitOrder::LsbFirst => true,
205        };
206        self.spi().ctrla().modify(|_, w| w.dord().bit(order));
207    }
208
209    /// Get the baud rate
210    #[inline]
211    pub fn get_baud(&mut self, freq: Hertz) -> Hertz {
212        let baud = self.spi().baud().read().baud().bits() as u32 + 1;
213        freq / 2 / baud
214    }
215
216    /// Set the baud rate
217    #[inline]
218    pub fn set_baud(&mut self, freq: Hertz, baud: Hertz) {
219        let baud = baud.to_Hz().max(1);
220        let bits = (freq.to_Hz() / 2 / baud).saturating_sub(1);
221        let bits = bits.try_into().unwrap_or(u8::MAX);
222        self.spi()
223            .baud()
224            .modify(|_, w| unsafe { w.baud().bits(bits) });
225    }
226
227    /// Get the enable state of the immediate buffer overflow notification
228    #[inline]
229    pub fn get_ibon(&self) -> bool {
230        self.spi().ctrla().read().ibon().bit()
231    }
232
233    /// Set the enable state of the immediate buffer overflow notification
234    #[inline]
235    pub fn set_ibon(&mut self, enabled: bool) {
236        self.spi().ctrla().modify(|_, w| w.ibon().bit(enabled));
237    }
238
239    /// Get run in standby mode
240    #[inline]
241    pub fn get_run_in_standby(&self) -> bool {
242        self.spi().ctrla().read().runstdby().bit()
243    }
244
245    /// Set run in standby mode
246    #[inline]
247    pub fn set_run_in_standby(&mut self, set: bool) {
248        self.spi().ctrla().modify(|_, w| w.runstdby().bit(set));
249    }
250
251    /// Enable interrupts for the specified flags
252    #[inline]
253    pub fn enable_interrupts(&mut self, flags: Flags) {
254        self.spi()
255            .intenset()
256            .write(|w| unsafe { w.bits(flags.bits()) });
257    }
258
259    /// Disable interrupts for the specified flags
260    #[inline]
261    pub fn disable_interrupts(&mut self, flags: Flags) {
262        self.spi()
263            .intenclr()
264            .write(|w| unsafe { w.bits(flags.bits()) });
265    }
266
267    /// Enable the receiver
268    #[inline]
269    pub fn rx_enable(&mut self) {
270        self.spi().ctrlb().modify(|_, w| w.rxen().set_bit());
271        while self.spi().syncbusy().read().ctrlb().bit_is_set() {}
272    }
273
274    /// Disable the receiver
275    #[inline]
276    pub fn rx_disable(&mut self) {
277        self.spi().ctrlb().modify(|_, w| w.rxen().clear_bit());
278        while self.spi().syncbusy().read().ctrlb().bit_is_set() {}
279    }
280
281    /// Enable the peripheral
282    #[inline]
283    pub fn enable(&mut self) {
284        self.spi().ctrla().modify(|_, w| w.enable().set_bit());
285        while self.spi().syncbusy().read().enable().bit_is_set() {}
286    }
287
288    /// Disable the peripheral
289    #[inline]
290    pub fn disable(&mut self) {
291        self.spi().ctrla().modify(|_, w| w.enable().clear_bit());
292        while self.spi().syncbusy().read().enable().bit_is_set() {}
293    }
294
295    /// Read from the `DATA` register
296    #[inline]
297    pub fn read_data(&mut self) -> DataWidth {
298        self.spi().data().read().data().bits()
299    }
300
301    /// Write to the `DATA` register
302    #[inline]
303    pub fn write_data(&mut self, data: DataWidth) {
304        // Safety: All bit patterns are memory safe
305        self.spi().data().write(|w| unsafe { w.data().bits(data) })
306    }
307
308    /// Read the interrupt flags
309    #[inline]
310    pub fn read_flags(&self) -> Flags {
311        let bits = self.spi().intflag().read().bits();
312        Flags::from_bits_truncate(bits)
313    }
314
315    /// Clear interrupt flags
316    #[inline]
317    pub fn clear_flags(&mut self, flags: Flags) {
318        unsafe { self.spi().intflag().write(|w| w.bits(flags.bits())) };
319    }
320
321    /// Read the error status flags
322    #[inline]
323    pub fn read_status(&self) -> Status {
324        let bits = self.spi().status().read().bits();
325        Status::from_bits_truncate(bits)
326    }
327
328    /// Clear error status flags
329    #[inline]
330    pub fn clear_status(&mut self, status: Status) {
331        unsafe { self.spi().status().write(|w| w.bits(status.bits())) };
332    }
333
334    /// Try to read the interrupt flags, but first check the error status flags.
335    #[inline]
336    pub fn read_flags_errors(&self) -> Result<Flags, Error> {
337        self.read_status().check_bus_error()?;
338        Ok(self.read_flags())
339    }
340}