atsamd_hal/sercom/spi/impl_ehal/thumbv6m.rs
1//! Implement Embedded HAL ([v0.2](crate::ehal_02) and [nb](ehal_nb)) traits for
2//! [`Spi`] structs
3//!
4//! As noted in the [spi module](super) documentation, the embedded-hal trait
5//! implementations vary by both [`Size`] and [`Capability`]. Each
6//! implementation is optimized to take advantage of all information known at
7//! compile-time, so it is importatnt to carefully read the documentation in
8//! this module.
9//!
10//! # Variations by [`Size`]
11//!
12//! SAMD11 and SAMD21 chips do not have 32-bit extension mode, so their
13//! transaction `Size` can only vary by the [`CharSize`]. Both options,
14//! [`EightBit`] and [`NineBit`], are [`AtomicSize`]s, because each can be
15//! completed with a single read/write of the `DATA` register. Consequently,
16//! each can implement both the blocking and non-blocking embedded HAL traits.
17//! These traits are implemented for the [`Word`] type of the corresponding
18//! `CharSize`. For example, an [`Spi`] struct with a `NineBit` `CharSize` would
19//! implement `spi::FullDuplex<u16>`.
20//!
21//! Note that embedded HAL does not offer a way to transmit slices in a
22//! non-blocking fashion, but this can be done using
23#")]
24#![cfg_attr(not(feature = "dma"), doc = "`DMA`")]
25//! or using interrupts and the [`spi_future`](crate::sercom::spi_future) module.
26//!
27//! # Variations by [`Capability`]
28//!
29//! The implementations in this module also seek to optimize as much as possible
30//! based on the `Capability` of the `Spi` struct. They follow a few general
31//! rules:
32//! - [`Tx`] structs can never receive data, so their corresponding trait
33//! implementations never read the `DATA` register and can never return an
34//! [`Error::Overflow`].
35//! - [`Rx`] structs in a [`MasterMode`](super::MasterMode) must initiate all
36//! transactions, so their implementations of non-blocking traits must track
37//! the state of on-going transactions.
38//! - [`Duplex`] structs must always read as many bytes as they send, even when
39//! implementing `Write`-only traits, to ensure they never introduce an
40//! [`Error::Overflow`].
41//!
42//! # Notes on individual embedded HAL traits
43//!
44//! ## `spi::FullDuplex`
45//!
46//! `spi::FullDuplex` is only implemented for structs with `Duplex`
47//! `Capability`. Although the embedded HAL documentation assumes a
48//! `MasterMode`, this module also implements it for the [`Slave`] [`OpMode`].
49//!
50//! ## `serial::Read`
51//!
52//! `serial::Read` is only implemented for structs with `Rx` `Capability`. When
53//! in a `MasterMode`, it initiates and tracks the state of the on-going
54//! transactions. But this is not required when acting as a `Slave`.
55//!
56//! ## `serial::Write`
57//!
58//! `serial::Write` is only implemented for structs with `Tx` `Capability`.
59//! These implementations never read the `DATA` register and ignore all
60//! instances of [`Error::Overflow`].
61//!
62//! ## `blocking::serial::Write`
63//!
64//! This trait uses the `blocking::serial::write::Default` implementation for
65//! implementers of `serial::Write`.
66//!
67//! ## `blocking::spi` traits
68//!
69//! These traits are implemented following all of the rules outlined above for
70//! the different [`Size`] and [`Capability`] options.
71
72use super::*;
73use crate::ehal_nb;
74use nb::Error::WouldBlock;
75use num_traits::{AsPrimitive, PrimInt};
76
77//=============================================================================
78// serial::Read
79//=============================================================================
80
81/// Implement [`Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`]
82///
83/// [`Read`] is only implemented for `Spi` structs with `Rx`
84/// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so
85/// it keeps track of the transaction state. If a transaction is in progress,
86/// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`.
87///
88/// [`Read`]: ehal_nb::serial::Read
89impl<P, M, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, M, C>, Rx>
90where
91 Config<P, M, C>: ValidConfig,
92 P: ValidPads,
93 M: MasterMode,
94 C: CharSize,
95 C::Word: PrimInt,
96 DataWidth: AsPrimitive<C::Word>,
97{
98 #[inline]
99 fn read(&mut self) -> nb::Result<C::Word, Error> {
100 let in_progress = self.capability.in_progress;
101 let flags = self.read_flags_errors()?;
102 if !in_progress && flags.contains(Flags::DRE) {
103 unsafe { self.write_data(0) };
104 self.capability.in_progress = true;
105 Err(WouldBlock)
106 } else if in_progress && flags.contains(Flags::RXC) {
107 self.capability.in_progress = false;
108 unsafe { Ok(self.read_data().as_()) }
109 } else {
110 Err(WouldBlock)
111 }
112 }
113}
114
115/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`]
116///
117/// [`Read`] is only implemented for `Spi` structs with `Rx`
118/// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so
119/// it keeps track of the transaction state. If a transaction is in progress,
120/// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`.
121///
122/// [`Read`]: crate::ehal_02::serial::Read
123impl<P, M, C> serial::Read<C::Word> for Spi<Config<P, M, C>, Rx>
124where
125 Config<P, M, C>: ValidConfig,
126 P: ValidPads,
127 M: MasterMode,
128 C: CharSize,
129 C::Word: PrimInt,
130 DataWidth: AsPrimitive<C::Word>,
131{
132 type Error = Error;
133
134 #[inline]
135 fn read(&mut self) -> nb::Result<C::Word, Error> {
136 <Self as ehal_nb::serial::Read<C::Word>>::read(self)
137 }
138}
139
140/// Implement [`Read`] for [`Rx`] [`Spi`] structs in [`Slave`]
141/// [`OpMode`]
142///
143/// [`Read`] is only implemented for `Spi` structs with `Rx`
144/// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate
145/// transactions, so it does not have to store any internal state. It only has
146/// to wait on `RXC`.
147///
148/// [`Read`]: ehal_nb::serial::Read
149impl<P, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx>
150where
151 Config<P, Slave, C>: ValidConfig,
152 P: ValidPads,
153 C: CharSize,
154 C::Word: PrimInt,
155 DataWidth: AsPrimitive<C::Word>,
156{
157 /// Wait for an `RXC` flag, then read the word
158 #[inline]
159 fn read(&mut self) -> nb::Result<C::Word, Error> {
160 let flags = self.read_flags_errors()?;
161 if flags.contains(Flags::RXC) {
162 unsafe { Ok(self.read_data().as_()) }
163 } else {
164 Err(WouldBlock)
165 }
166 }
167}
168
169/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`]
170/// [`OpMode`]
171///
172/// [`serial::Read`] is only implemented for `Spi` structs with `Rx`
173/// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate
174/// transactions, so it does not have to store any internal state. It only has
175/// to wait on `RXC`.
176impl<P, C> serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx>
177where
178 Config<P, Slave, C>: ValidConfig,
179 P: ValidPads,
180 C: CharSize,
181 C::Word: PrimInt,
182 DataWidth: AsPrimitive<C::Word>,
183{
184 type Error = Error;
185
186 /// Wait for an `RXC` flag, then read the word
187 #[inline]
188 fn read(&mut self) -> nb::Result<C::Word, Error> {
189 <Self as ehal_nb::serial::Read<C::Word>>::read(self)
190 }
191}
192
193//=============================================================================
194// embedded_io::Read
195//=============================================================================
196impl<P, M> embedded_io::Read for Spi<Config<P, M, EightBit>, Rx>
197where
198 Config<P, M, EightBit>: ValidConfig,
199 P: ValidPads,
200 M: MasterMode,
201{
202 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
203 for byte in buf.iter_mut() {
204 let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?;
205 *byte = w;
206 }
207
208 Ok(buf.len())
209 }
210}
211
212impl<P> embedded_io::Read for Spi<Config<P, Slave, EightBit>, Rx>
213where
214 Config<P, Slave, EightBit>: ValidConfig,
215 P: ValidPads,
216{
217 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
218 if buf.is_empty() {
219 return Ok(0);
220 };
221
222 for byte in buf.iter_mut() {
223 let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?;
224 *byte = w;
225 }
226
227 Ok(buf.len())
228 }
229}
230
231//=============================================================================
232// serial::Write
233//=============================================================================
234
235/// Implement [`Write`] for [`Tx`] [`Spi`] structs
236///
237/// [`Write`] is only implemented for `Spi` structs with `Tx`
238/// [`Capability`]. Because the `Capability` is `Tx`, this implementation never
239/// reads the DATA register and ignores all buffer overflow errors.
240///
241/// [`Write`]: ehal_nb::serial::Write
242impl<P, M, C> ehal_nb::serial::Write<C::Word> for Spi<Config<P, M, C>, Tx>
243where
244 Config<P, M, C>: ValidConfig,
245 P: ValidPads,
246 M: OpMode,
247 C: CharSize,
248 C::Word: PrimInt + AsPrimitive<DataWidth>,
249{
250 #[inline]
251 fn write(&mut self, word: C::Word) -> nb::Result<(), Error> {
252 // Ignore buffer overflow errors
253 if self.read_flags().contains(Flags::DRE) {
254 unsafe { self.write_data(word.as_()) };
255 Ok(())
256 } else {
257 Err(WouldBlock)
258 }
259 }
260
261 #[inline]
262 fn flush(&mut self) -> nb::Result<(), Error> {
263 // Ignore buffer overflow errors
264 if self.read_flags().contains(Flags::TXC) {
265 Ok(())
266 } else {
267 Err(WouldBlock)
268 }
269 }
270}
271
272/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs
273///
274/// `serial::Write` is only implemented for `Spi` structs with `Tx`
275/// [`Capability`]. Because the `Capability` is `Tx`, this implementation never
276/// reads the DATA register and ignores all buffer overflow errors.
277impl<P, M, C> serial::Write<C::Word> for Spi<Config<P, M, C>, Tx>
278where
279 Config<P, M, C>: ValidConfig,
280 P: ValidPads,
281 M: OpMode,
282 C: CharSize,
283 C::Word: PrimInt + AsPrimitive<DataWidth>,
284{
285 type Error = Error;
286
287 #[inline]
288 fn write(&mut self, word: C::Word) -> nb::Result<(), Error> {
289 <Self as ehal_nb::serial::Write<C::Word>>::write(self, word)
290 }
291
292 #[inline]
293 fn flush(&mut self) -> nb::Result<(), Error> {
294 <Self as ehal_nb::serial::Write<C::Word>>::flush(self)
295 }
296}
297
298//=============================================================================
299// blocking::serial::Write
300//=============================================================================
301
302impl<C> blocking::serial::write::Default<C::Word> for Spi<C, Tx>
303where
304 C: ValidConfig,
305 Spi<C, Tx>: serial::Write<C::Word>,
306{
307}
308
309//=============================================================================
310// embedded_io::Write
311//=============================================================================
312impl<P, M> embedded_io::Write for Spi<Config<P, M, EightBit>, Tx>
313where
314 Config<P, M, EightBit>: ValidConfig,
315 P: ValidPads,
316 M: OpMode,
317{
318 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
319 for byte in buf {
320 nb::block!(<Self as ehal_nb::serial::Write>::write(self, *byte))?;
321 }
322
323 Ok(buf.len())
324 }
325
326 fn flush(&mut self) -> Result<(), Self::Error> {
327 nb::block!(<Self as ehal_nb::serial::Write>::flush(self))
328 }
329}
330
331//=============================================================================
332// spi::FullDuplex
333//=============================================================================
334
335/// Implement embedded-hal-nb [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`]
336///
337/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`]
338/// [`Capability`]. The [`Word`] size used in the implementation depends on the
339/// corresponding [`CharSize`].
340///
341/// [`spi::FullDuplex`]: ehal_nb::spi::FullDuplex
342impl<C> ehal_nb::spi::FullDuplex<C::Word> for Spi<C, Duplex>
343where
344 C: ValidConfig,
345 C::Word: PrimInt + AsPrimitive<u16>,
346 u16: AsPrimitive<C::Word>,
347{
348 #[inline]
349 fn read(&mut self) -> nb::Result<C::Word, Error> {
350 let flags = self.read_flags_errors()?;
351 if flags.contains(Flags::RXC) {
352 unsafe { Ok(self.read_data().as_()) }
353 } else {
354 Err(WouldBlock)
355 }
356 }
357
358 #[inline]
359 fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> {
360 let flags = self.read_flags_errors()?;
361 if flags.contains(Flags::DRE) {
362 unsafe { self.write_data(word.as_()) };
363 Ok(())
364 } else {
365 Err(WouldBlock)
366 }
367 }
368}
369
370/// Implement embedded-hal 0.2 [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`]
371///
372/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`]
373/// [`Capability`]. The [`Word`] size used in the implementation depends on the
374/// corresponding [`CharSize`].
375///
376/// [`spi::FullDuplex`]: crate::ehal_02::spi::FullDuplex
377impl<C> crate::ehal_02::spi::FullDuplex<C::Word> for Spi<C, Duplex>
378where
379 C: ValidConfig,
380 C::Word: PrimInt + AsPrimitive<u16>,
381 u16: AsPrimitive<C::Word>,
382{
383 type Error = Error;
384
385 #[inline]
386 fn read(&mut self) -> nb::Result<C::Word, Error> {
387 let flags = self.read_flags_errors()?;
388 if flags.contains(Flags::RXC) {
389 unsafe { Ok(self.read_data().as_()) }
390 } else {
391 Err(WouldBlock)
392 }
393 }
394
395 #[inline]
396 fn send(&mut self, word: C::Word) -> nb::Result<(), Error> {
397 let flags = self.read_flags_errors()?;
398 if flags.contains(Flags::DRE) {
399 unsafe { self.write_data(word.as_()) };
400 Ok(())
401 } else {
402 Err(WouldBlock)
403 }
404 }
405}
406
407//=============================================================================
408// Note on macros
409//=============================================================================
410
411// Macros are necessary for the following implementations of the embedded HAL
412// `blocking` traits because of a limitation in the Rust trait system. The
413// compiler can't seem to recongnize that the `blocking::spi::*::Default` traits
414// can never be implemented for [`Spi`] in downstream crates, because that would
415// violate the orphan rules.
416
417//=============================================================================
418// blocking::spi::Transfer
419//=============================================================================
420
421macro_rules! impl_blocking_spi_transfer {
422 ( $($CharSize:ident),+ ) => {
423 $(
424 /// Implement [`Transfer`] for [`Spi`] structs that can [`Receive`]
425 ///
426 /// The transfer accepts a slice of primitive integers, depending on
427 /// the [`CharSize`] (`u8` or `u16`).
428 ///
429 /// [`Transfer`]: blocking::spi::Transfer
430 impl<P, M, A> blocking::spi::Transfer<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, A>
431 where
432 Config<P, M, $CharSize>: ValidConfig,
433 P: ValidPads,
434 M: OpMode,
435 A: Receive,
436 {
437 type Error = Error;
438
439 #[inline]
440 fn transfer<'w>(&mut self, words: &'w mut [Word<$CharSize>]) -> Result<&'w [Word<$CharSize>], Error> {
441 let cells = core::cell::Cell::from_mut(words).as_slice_of_cells();
442 let mut to_send = cells.iter();
443 let mut to_recv = cells.iter();
444 while to_recv.len() > 0 {
445 let flags = self.read_flags_errors()?;
446 if to_send.len() > 0 && flags.contains(Flags::DRE) {
447 let word = match to_send.next() {
448 Some(cell) => cell.get(),
449 None => unreachable!(),
450 };
451 self.config.as_mut().regs.write_data(word as u16);
452 }
453 if to_recv.len() > to_send.len() && flags.contains(Flags::RXC) {
454 let word = self.config.as_mut().regs.read_data() as Word<$CharSize>;
455 match to_recv.next() {
456 Some(cell) => cell.set(word),
457 None => unreachable!(),
458 }
459 }
460 }
461 Ok(words)
462 }
463 }
464 )+
465 }
466}
467
468impl_blocking_spi_transfer!(EightBit, NineBit);
469
470//=============================================================================
471// blocking::spi::Write
472//=============================================================================
473
474macro_rules! impl_blocking_spi_write {
475 ( $($CharSize:ident),+ ) => {
476 $(
477 /// Implement [`Write`] for [`Spi`] structs with [`Duplex`]
478 /// [`Capability`]
479 ///
480 /// The transfer accepts a slice of primitive integers, depending on
481 /// the [`CharSize`] (`u8` or `u16`).
482 ///
483 /// [`Write`]: blocking::spi::Write
484 impl<P, M> blocking::spi::Write<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Duplex>
485 where
486 Config<P, M, $CharSize>: ValidConfig,
487 P: ValidPads,
488 M: OpMode,
489 {
490 type Error = Error;
491
492 #[inline]
493 fn write(&mut self, words: &[Word<$CharSize>]) -> Result<(), Error> {
494 // We are `Duplex`, so we must receive as many words as we send,
495 // otherwise we could trigger an overflow
496 let mut to_send = words.iter();
497 let mut to_recv = to_send.len();
498 while to_recv > 0 {
499 let flags = self.read_flags_errors()?;
500 if to_send.len() > 0 && flags.contains(Flags::DRE) {
501 let word = match to_send.next() {
502 Some(word) => *word,
503 None => unreachable!(),
504 };
505 self.config.as_mut().regs.write_data(word as u16);
506 }
507 if to_recv > to_send.len() && flags.contains(Flags::RXC) {
508 self.config.as_mut().regs.read_data();
509 to_recv -= 1;
510 }
511 }
512 Ok(())
513 }
514 }
515
516 /// Implement [`Write`] for [`Spi`] structs with [`Tx`]
517 /// [`Capability`]
518 ///
519 /// The transfer accepts a slice of primitive integers, depending on
520 /// the [`CharSize`] (`u8` or `u16`).
521 ///
522 /// Because the `Capability` is `Tx`, this implementation never
523 /// reads the DATA register and ignores all buffer overflow errors.
524 ///
525 /// [`Write`]: blocking::spi::Write
526 impl<P, M> blocking::spi::Write<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Tx>
527 where
528 Config<P, M, $CharSize>: ValidConfig,
529 P: ValidPads,
530 M: OpMode,
531 {
532 type Error = Error;
533
534 #[inline]
535 fn write(&mut self, words: &[Word<$CharSize>]) -> Result<(), Error> {
536 // We are `Tx`, so we don't have to consider reading at all, ever.
537 for word in words {
538 loop {
539 // Ignore buffer overflow errors
540 if self.read_status().contains(Status::LENERR) {
541 return Err(Error::LengthError)
542 } else if self.read_flags().contains(Flags::DRE) {
543 self.config.as_mut().regs.write_data(*word as u16);
544 break
545 }
546 }
547 }
548 // Wait until all data is shifted out
549 while !self.read_flags().contains(Flags::TXC) {}
550 Ok(())
551 }
552 }
553 )+
554 }
555}
556
557impl_blocking_spi_write!(EightBit, NineBit);
558
559//=============================================================================
560// blocking::spi::WriteIter
561//=============================================================================
562
563macro_rules! impl_blocking_spi_write_iter {
564 ( $($CharSize:ident),+ ) => {
565 $(
566 /// Implement [`WriteIter`] for [`Spi`] structs with [`Duplex`]
567 /// [`Capability`]
568 ///
569 /// The transfer accepts a slice of primitive integers, depending on
570 /// the [`CharSize`] (`u8` or `u16`).
571 ///
572 /// [`WriteIter`]: blocking::spi::WriteIter
573 impl<P, M> blocking::spi::WriteIter<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Duplex>
574 where
575 Config<P, M, $CharSize>: ValidConfig,
576 P: ValidPads,
577 M: OpMode,
578 {
579 type Error = Error;
580
581 #[inline]
582 fn write_iter<WI>(&mut self, words: WI) -> Result<(), Error>
583 where
584 WI: IntoIterator<Item = Word<$CharSize>>,
585 {
586 // We are `Duplex`, so we must receive as many words as we send,
587 // otherwise we could trigger an overflow. However, we don't know
588 // how many words there are to start with, so we have to send and
589 // receive them one at a time.
590 for word in words.into_iter() {
591 loop {
592 let flags = self.read_flags_errors()?;
593 if flags.contains(Flags::DRE) {
594 unsafe { self.write_data(word as u16) };
595 break
596 }
597 }
598 loop {
599 let flags = self.read_flags_errors()?;
600 if flags.contains(Flags::RXC) {
601 self.config.as_mut().regs.read_data() as Word<$CharSize>;
602 break
603 }
604 }
605 }
606 Ok(())
607 }
608 }
609
610 /// Implement [`WriteIter`] for [`Spi`] structs with [`Tx`]
611 /// [`Capability`]
612 ///
613 /// The transfer accepts a slice of primitive integers, depending on
614 /// the [`CharSize`] (`u8` or `u16`).
615 ///
616 /// Because the `Capability` is `Tx`, this implementation never
617 /// reads the DATA register and ignores all buffer overflow errors.
618 ///
619 /// [`WriteIter`]: blocking::spi::WriteIter
620 impl<P, M> blocking::spi::WriteIter<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Tx>
621 where
622 Config<P, M, $CharSize>: ValidConfig,
623 P: ValidPads,
624 M: OpMode,
625 {
626 type Error = Error;
627
628 #[inline]
629 fn write_iter<WI>(&mut self, words: WI) -> Result<(), Error>
630 where
631 WI: IntoIterator<Item = Word<$CharSize>>,
632 {
633 // We are `Tx`, so we don't have to consider reading at all, ever.
634 for word in words.into_iter() {
635 loop {
636 // Ignore buffer overflow errors
637 if self.read_status().contains(Status::LENERR) {
638 return Err(Error::LengthError)
639 } else if self.read_flags().contains(Flags::DRE) {
640 unsafe { self.write_data(word as u16) };
641 break
642 }
643 }
644 }
645 // Wait until all data is shifted out
646 while !self.read_flags().contains(Flags::TXC) {}
647 Ok(())
648 }
649 }
650 )+
651 };
652}
653
654impl_blocking_spi_write_iter!(EightBit, NineBit);