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