1use num_traits::{AsPrimitive, PrimInt};
4
5use crate::dmac::{channel, sram::DmacDescriptor, AnyChannel, Beat, Buffer, Ready};
6use crate::ehal::spi::SpiBus;
7use crate::sercom::dma::{
8 read_dma, read_dma_linked, write_dma, write_dma_linked, SercomPtr, SharedSliceBuffer,
9 SinkSourceBuffer,
10};
11
12use super::{
13 Capability, Config, DataWidth, Duplex, Error, MasterMode, OpMode, Receive, Sercom, Size, Slave,
14 Spi, Transmit, ValidConfig, ValidPads, Word,
15};
16
17impl<P, M, Z, D, R, T> Spi<Config<P, M, Z>, D, R, T>
18where
19 P: ValidPads,
20 M: OpMode,
21 Z: Size,
22 Config<P, M, Z>: ValidConfig,
23 D: Capability,
24 Z::Word: Beat,
25{
26 #[inline]
27 pub(in super::super) fn sercom_ptr(&self) -> SercomPtr<Z::Word> {
28 SercomPtr(self.config.regs.spi().data().as_ptr() as *mut _)
29 }
30}
31
32impl<P, M, Z, D, R, T, S> Spi<Config<P, M, Z>, D, R, T>
34where
35 P: ValidPads,
36 M: OpMode,
37 Z: Size + 'static,
38 Config<P, M, Z>: ValidConfig<Sercom = S>,
39 D: Transmit,
40 S: Sercom,
41 Z::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
42 DataWidth: AsPrimitive<Z::Word>,
43 T: AnyChannel<Status = Ready>,
44{
45 pub(super) fn write_dma(&mut self, buf: &[Z::Word]) -> Result<usize, Error> {
46 if buf.is_empty() {
47 return Ok(0);
48 }
49
50 self.config.as_mut().regs.rx_disable();
52
53 let sercom_ptr = self.sercom_ptr();
54 let tx = self._tx_channel.as_mut();
55 let mut words = crate::sercom::dma::SharedSliceBuffer::from_slice(buf);
56
57 unsafe {
61 crate::sercom::dma::write_dma::<_, _, S>(tx, sercom_ptr, &mut words);
62 }
63
64 while !tx.xfer_complete() {
65 core::hint::spin_loop();
66 }
67
68 tx.stop();
70
71 if D::RX_ENABLE {
73 self.config.as_mut().regs.rx_enable();
74 }
75
76 self._tx_channel.as_mut().xfer_success()?;
77 Ok(buf.len())
78 }
79}
80
81impl<P, M, S, C, D, R, T> Spi<Config<P, M, C>, D, R, T>
82where
83 Config<P, M, C>: ValidConfig<Sercom = S>,
84 S: Sercom,
85 P: ValidPads,
86 M: MasterMode,
87 C: Size + 'static,
88 C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
89 DataWidth: AsPrimitive<C::Word>,
90 D: Capability,
91 R: AnyChannel<Status = Ready>,
92 T: AnyChannel<Status = Ready>,
93{
94 #[inline]
95 fn transfer_blocking<Source: Buffer<Beat = C::Word>, Dest: Buffer<Beat = C::Word>>(
96 &mut self,
97 dest: &mut Dest,
98 source: &mut Source,
99 ) -> Result<(), Error> {
100 let sercom_ptr = self.sercom_ptr();
101 let rx = self._rx_channel.as_mut();
102 let tx = self._tx_channel.as_mut();
103
104 unsafe {
108 read_dma::<_, _, S>(rx, sercom_ptr.clone(), dest);
109 write_dma::<_, _, S>(tx, sercom_ptr, source);
110 }
111
112 while !(rx.xfer_complete() && tx.xfer_complete()) {
113 core::hint::spin_loop();
114 }
115
116 tx.stop();
118 rx.stop();
119
120 self.read_status().check_bus_error()?;
122 self._rx_channel
123 .as_mut()
124 .xfer_success()
125 .and(self._tx_channel.as_mut().xfer_success())?;
126 Ok(())
127 }
128
129 #[inline]
130 pub(super) fn read_dma_master(&mut self, mut words: &mut [C::Word]) -> Result<(), Error> {
131 if words.is_empty() {
132 return Ok(());
133 }
134
135 let mut source_word = self.config.nop_word.as_();
136 let mut source = SinkSourceBuffer::new(&mut source_word, words.len());
137
138 self.transfer_blocking(&mut words, &mut source)
139 }
140}
141
142impl<P, M, S, C, R, T> SpiBus<Word<C>> for Spi<Config<P, M, C>, Duplex, R, T>
144where
145 Config<P, M, C>: ValidConfig<Sercom = S>,
146 S: Sercom,
147 P: ValidPads,
148 M: MasterMode,
149 C: Size + 'static,
150 C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
151 DataWidth: AsPrimitive<C::Word>,
152 R: AnyChannel<Status = Ready>,
153 T: AnyChannel<Status = Ready>,
154{
155 #[inline]
156 fn read(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
157 self.read_dma_master(words)
158 }
159
160 #[inline]
161 fn write(&mut self, words: &[C::Word]) -> Result<(), Self::Error> {
162 self.write_dma(words)?;
163 Ok(())
164 }
165
166 #[inline]
167 fn transfer(&mut self, mut read: &mut [C::Word], write: &[C::Word]) -> Result<(), Self::Error> {
168 use core::cmp::Ordering;
169
170 if write.is_empty() && read.is_empty() {
172 return Ok(());
173 }
174
175 if write.is_empty() {
177 return self.read_dma_master(read);
178 } else if read.is_empty() {
179 self.write_dma(write)?;
180 return Ok(());
181 }
182
183 let mut linked_descriptor = DmacDescriptor::default();
187
188 let mut source_sink_word = self.config.nop_word.as_();
194 let mut sercom_ptr = self.sercom_ptr();
195
196 let (read_link, write_link) = match read.len().cmp(&write.len()) {
197 Ordering::Equal => {
198 let mut write = SharedSliceBuffer::from_slice(write);
199 return self.transfer_blocking(&mut read, &mut write);
200 }
201
202 Ordering::Less => {
205 let mut sink =
206 SinkSourceBuffer::new(&mut source_sink_word, write.len() - read.len());
207 unsafe {
208 channel::write_descriptor(
209 &mut linked_descriptor,
210 &mut sercom_ptr,
211 &mut sink,
212 core::ptr::null_mut(),
214 );
215 }
216
217 (Some(&mut linked_descriptor), None)
218 }
219
220 Ordering::Greater => {
223 let mut source =
224 SinkSourceBuffer::new(&mut source_sink_word, read.len() - write.len());
225 unsafe {
226 channel::write_descriptor(
227 &mut linked_descriptor,
228 &mut source,
229 &mut sercom_ptr,
230 core::ptr::null_mut(),
232 );
233 }
234
235 (None, Some(&mut linked_descriptor))
236 }
237 };
238
239 let rx = self._rx_channel.as_mut();
240 let tx = self._tx_channel.as_mut();
241
242 let mut write = SharedSliceBuffer::from_slice(write);
243
244 unsafe {
248 read_dma_linked::<_, _, S>(rx, sercom_ptr.clone(), &mut read, read_link);
249 write_dma_linked::<_, _, S>(tx, sercom_ptr, &mut write, write_link);
250 }
251
252 while !(rx.xfer_complete() && tx.xfer_complete()) {
253 core::hint::spin_loop();
254 }
255
256 tx.stop();
258 rx.stop();
259
260 self.read_status().check_bus_error()?;
262 self._rx_channel
263 .as_mut()
264 .xfer_success()
265 .and(self._tx_channel.as_mut().xfer_success())?;
266 Ok(())
267 }
268
269 #[inline]
270 fn transfer_in_place(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
271 unsafe {
279 let mut read_buf = SharedSliceBuffer::from_slice_unchecked(words);
280 let mut write_buf = SharedSliceBuffer::from_slice(words);
281 self.transfer_blocking(&mut read_buf, &mut write_buf)
282 }
283 }
284
285 #[inline]
286 fn flush(&mut self) -> Result<(), Error> {
287 self.flush_tx();
288 Ok(())
289 }
290}
291
292impl<P, M, Z, D, R, T, S> embedded_io::Write for Spi<Config<P, M, Z>, D, R, T>
295where
296 P: ValidPads,
297 M: OpMode,
298 Z: Size<Word = u8> + 'static,
299 Config<P, M, Z>: ValidConfig<Sercom = S>,
300 D: Transmit,
301 S: Sercom,
302 T: AnyChannel<Status = Ready>,
303{
304 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
305 Spi::write_dma(self, buf)
306 }
307
308 fn flush(&mut self) -> Result<(), Self::Error> {
309 self.flush_tx();
310 Ok(())
311 }
312}
313
314impl<P, M, Z, D, R, T, S> embedded_io::Read for Spi<Config<P, M, Z>, D, R, T>
317where
318 P: ValidPads,
319 M: MasterMode,
320 Z: Size<Word = u8> + 'static,
321 Config<P, M, Z>: ValidConfig<Sercom = S>,
322 D: Receive,
323 S: Sercom,
324 R: AnyChannel<Status = Ready>,
325 T: AnyChannel<Status = Ready>,
326{
327 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
328 self.read_dma_master(buf)?;
329 Ok(buf.len())
330 }
331}
332
333impl<P, Z, D, R, T, S> embedded_io::Read for Spi<Config<P, Slave, Z>, D, R, T>
336where
337 P: ValidPads,
338 Z: Size<Word = u8> + 'static,
339 Config<P, Slave, Z>: ValidConfig<Sercom = S>,
340 D: Receive,
341 S: Sercom,
342 R: AnyChannel<Status = Ready>,
343{
344 fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
345 if buf.is_empty() {
346 return Ok(0);
347 }
348
349 self.flush_rx()?;
353 let sercom_ptr = self.sercom_ptr();
354 let rx = self._rx_channel.as_mut();
355
356 unsafe {
359 read_dma::<_, _, S>(rx, sercom_ptr.clone(), &mut buf);
360 }
361
362 while !(rx.xfer_complete()) {
363 core::hint::spin_loop();
364 }
365
366 rx.stop();
368
369 self.read_status().check_bus_error()?;
371 self._rx_channel.as_mut().xfer_success()?;
372 Ok(buf.len())
373 }
374}