1use crate::{Mutex, pac};
2use embassy_embedded_hal::SetConfig;
3use embedded_hal::spi::{ErrorType, Operation, Phase, Polarity};
4use paste::paste;
5
6pub fn init() {
10 unsafe {
11 pac::mss_config_clk_rst(
12 pac::mss_peripherals__MSS_PERIPH_SPI0,
13 pac::MPFS_HAL_FIRST_HART as u8,
14 pac::PERIPH_RESET_STATE__PERIPHERAL_ON,
15 );
16 pac::mss_config_clk_rst(
17 pac::mss_peripherals__MSS_PERIPH_SPI1,
18 pac::MPFS_HAL_FIRST_HART as u8,
19 pac::PERIPH_RESET_STATE__PERIPHERAL_ON,
20 );
21 pac::MSS_SPI_init(&raw mut pac::g_mss_spi0_lo);
22 pac::MSS_SPI_init(&raw mut pac::g_mss_spi1_lo);
23
24 }
30 debug!("SPI initialized");
31}
32
33pub trait SpiPeripheral: crate::Peripheral {
34 #[doc(hidden)]
35 fn address(&self) -> *mut pac::mss_spi_instance_t;
36 #[doc(hidden)]
37 fn number(&self) -> u8;
38 #[doc(hidden)]
39 fn slave_num(&self) -> u8;
40}
41
42#[derive(Debug)]
43pub enum SpiError {
44 InvalidClockDiv,
45}
46
47impl embedded_hal::spi::Error for SpiError {
48 fn kind(&self) -> embedded_hal::spi::ErrorKind {
49 embedded_hal::spi::ErrorKind::Other
50 }
51}
52
53static SPI0_IN_USE: Mutex = Mutex::new();
54static SPI1_IN_USE: Mutex = Mutex::new();
55
56macro_rules! impl_spi {
57 ($n:expr, $slave_num:expr) => {
58 paste! {
59 impl_spi!([<Spi $n Slave $slave_num>], [<SPI $n _SLAVE $slave_num _TAKEN>], $n, $slave_num, [<g_mss_spi $n _lo>]);
60 }
61 };
62
63 ($PERIPH:ident, $PERIPH_TAKEN:ident, $spi_num:expr, $slave_num:expr, $instance:ident) => {
65 pub struct $PERIPH {
66 _private: (),
67 }
68 static mut $PERIPH_TAKEN: bool = false;
69
70 impl crate::Peripheral for $PERIPH {
71 fn take() -> Option<Self> {
72 critical_section::with(|_| unsafe {
73 if $PERIPH_TAKEN {
74 None
75 } else {
76 $PERIPH_TAKEN = true;
77 Some(Self { _private: () })
78 }
79 })
80 }
81
82 unsafe fn steal() -> Self {
83 Self { _private: () }
84 }
85 }
86 impl SpiPeripheral for $PERIPH {
87 fn address(&self) -> *mut pac::mss_spi_instance_t {
88 &raw mut pac::$instance
89 }
90
91 fn number(&self) -> u8 {
92 $spi_num
93 }
94
95 fn slave_num(&self) -> u8 {
96 $slave_num
97 }
98 }
99
100 };
101}
102
103impl_spi!(0, 0);
104impl_spi!(0, 1);
105impl_spi!(1, 0);
106impl_spi!(1, 1);
107
108#[derive(Debug, Clone, Copy)]
109pub struct SpiConfig {
110 clock_div: u16,
114 phase: Phase,
115 polarity: Polarity,
116}
117
118impl Default for SpiConfig {
119 fn default() -> Self {
120 Self {
121 clock_div: 8,
122 phase: Phase::CaptureOnFirstTransition,
123 polarity: Polarity::IdleLow,
124 }
125 }
126}
127
128impl SpiConfig {
129 pub fn new(clock_div: u16, phase: Phase, polarity: Polarity) -> Result<Self, SpiError> {
130 if clock_div < 2 || clock_div > 512 || clock_div % 2 != 0 {
131 return Err(SpiError::InvalidClockDiv);
132 }
133 Ok(Self {
134 clock_div,
135 phase,
136 polarity,
137 })
138 }
139}
140
141pub struct Spi<T: SpiPeripheral> {
142 peripheral: T,
143}
144
145impl<T: SpiPeripheral> ErrorType for Spi<T> {
146 type Error = SpiError;
147}
148
149impl<T: SpiPeripheral> Spi<T> {
150 pub fn new(peripheral: T, config: SpiConfig) -> Self {
151 let mut spi = Spi { peripheral };
152 spi.set_config(&config).unwrap();
153 spi
154 }
155}
156
157impl<T: SpiPeripheral> SetConfig for Spi<T> {
158 type Config = SpiConfig;
159 type ConfigError = SpiError;
160 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
161 let mode = match (config.phase, config.polarity) {
162 (Phase::CaptureOnFirstTransition, Polarity::IdleLow) => {
163 pac::__mss_spi_protocol_mode_t_MSS_SPI_MODE0
164 }
165 (Phase::CaptureOnSecondTransition, Polarity::IdleLow) => {
166 pac::__mss_spi_protocol_mode_t_MSS_SPI_MODE1
167 }
168 (Phase::CaptureOnFirstTransition, Polarity::IdleHigh) => {
169 pac::__mss_spi_protocol_mode_t_MSS_SPI_MODE2
170 }
171 (Phase::CaptureOnSecondTransition, Polarity::IdleHigh) => {
172 pac::__mss_spi_protocol_mode_t_MSS_SPI_MODE3
173 }
174 };
175 unsafe {
176 pac::MSS_SPI_configure_master_mode(
177 self.peripheral.address(),
178 self.peripheral.slave_num() as u32,
179 mode,
180 config.clock_div as u32,
181 pac::MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE as u8, Some(mss_spi_overflow_handler),
183 );
184 }
185 Ok(())
186 }
187}
188
189extern "C" fn mss_spi_overflow_handler(mss_spi_core: u8) {
190 unsafe {
191 if mss_spi_core != 0 {
192 pac::mss_config_clk_rst(
194 pac::mss_peripherals__MSS_PERIPH_SPI1,
195 pac::MPFS_HAL_FIRST_HART as u8,
196 pac::PERIPH_RESET_STATE__PERIPHERAL_OFF,
197 );
198 pac::mss_config_clk_rst(
200 pac::mss_peripherals__MSS_PERIPH_SPI1,
201 pac::MPFS_HAL_FIRST_HART as u8,
202 pac::PERIPH_RESET_STATE__PERIPHERAL_ON,
203 );
204 } else {
205 pac::mss_config_clk_rst(
207 pac::mss_peripherals__MSS_PERIPH_SPI0,
208 pac::MPFS_HAL_FIRST_HART as u8,
209 pac::PERIPH_RESET_STATE__PERIPHERAL_OFF,
210 );
211 pac::mss_config_clk_rst(
213 pac::mss_peripherals__MSS_PERIPH_SPI0,
214 pac::MPFS_HAL_FIRST_HART as u8,
215 pac::PERIPH_RESET_STATE__PERIPHERAL_ON,
216 );
217 }
218 }
219}
220
221impl<T: SpiPeripheral> embedded_hal::spi::SpiDevice for Spi<T> {
222 fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
223 let mutex = if self.peripheral.number() == 0 {
224 &SPI0_IN_USE
225 } else {
226 &SPI1_IN_USE
227 };
228 let lock = mutex.lock();
229
230 unsafe {
231 pac::MSS_SPI_set_slave_select(
232 self.peripheral.address(),
233 self.peripheral.slave_num() as u32,
234 );
235 for operation in operations {
236 match operation {
237 Operation::Write(data) => {
238 self.write(data)?;
239 }
240 Operation::Read(data) => {
241 self.read(data)?;
242 }
243 Operation::Transfer(rx, tx) => {
244 self.transfer(rx, tx)?;
245 }
246 Operation::TransferInPlace(data) => {
247 self.transfer_in_place(data)?;
248 }
249 Operation::DelayNs(ns) => {
250 pac::sleep_ms(*ns as u64 / 1000);
251 }
252 }
253 }
254 pac::MSS_SPI_clear_slave_select(
255 self.peripheral.address(),
256 self.peripheral.slave_num() as u32,
257 );
258 }
259 mutex.release(lock);
260
261 Ok(())
262 }
263}
264
265impl<T: SpiPeripheral> Spi<T> {
266 fn write(&mut self, data: &[u8]) -> Result<(), SpiError> {
267 if data.is_empty() {
268 return Ok(());
269 }
270 let buffer_aligned: bool = data.as_ptr().align_offset(4) == 0 && data.len() > 3;
271 trace!(
272 "Writing to SPI {:x?}. Buffer aligned: {}; Byte count: {}",
273 data,
274 buffer_aligned,
275 data.len()
276 );
277
278 unsafe {
279 let spi = &mut (*(*self.peripheral.address()).hw_reg);
280
281 let word_count = if buffer_aligned { data.len() / 4 } else { 0 } as u32;
282 if word_count > 0 {
283 let words = data.as_ptr() as *const u32;
285
286 spi.FRAMESIZE = 32;
288 spi.FRAMESUP = word_count as u32 & pac::spi::BYTESUPPER_MASK;
289 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
290 | ((word_count << pac::spi::TXRXDFCOUNT_SHIFT) & pac::spi::TXRXDFCOUNT_MASK);
291 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
292 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
293
294 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
296 let _ = core::ptr::read_volatile(&spi.RX_DATA);
297 }
298
299 for i in 0..(word_count as usize) {
300 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
302 {
303 core::hint::spin_loop();
304 }
305 core::ptr::write_volatile(&mut spi.TX_DATA, (*words.add(i)).to_be());
307 }
308
309 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
311 core::hint::spin_loop();
312 }
313
314 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
316 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
317 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
318 }
319
320 let data = &data[word_count as usize * 4..];
321
322 if !data.is_empty() {
323 spi.FRAMESIZE = 8;
325 spi.FRAMESUP = data.len() as u32 & pac::spi::BYTESUPPER_MASK;
326 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
327 | (((data.len() as u32) << pac::spi::TXRXDFCOUNT_SHIFT)
328 & pac::spi::TXRXDFCOUNT_MASK);
329 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
330 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
331
332 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
334 let _ = core::ptr::read_volatile(&spi.RX_DATA);
335 }
336
337 for i in 0..data.len() {
338 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
340 {
341 core::hint::spin_loop();
342 }
343 core::ptr::write_volatile(&mut spi.TX_DATA, data[i] as u32);
345 }
346
347 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
349 core::hint::spin_loop();
350 }
351
352 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
354 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
355 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
356 }
357 }
358 Ok(())
359 }
360
361 fn read(&mut self, data: &mut [u8]) -> Result<(), SpiError> {
362 if data.is_empty() {
363 return Ok(());
364 }
365 let buffer_aligned: bool = data.as_ptr().align_offset(4) == 0 && data.len() > 3;
366
367 trace!(
368 "Reading from SPI. Buffer aligned: {}; Byte count: {}",
369 buffer_aligned,
370 data.len()
371 );
372
373 unsafe {
374 let spi = &mut (*(*self.peripheral.address()).hw_reg);
375 let word_count = if buffer_aligned { data.len() / 4 } else { 0 } as u32;
376 if word_count > 0 {
377 let words = data.as_ptr() as *mut u32;
378
379 spi.FRAMESIZE = 32;
381 spi.FRAMESUP = word_count as u32 & pac::spi::BYTESUPPER_MASK;
382 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
383 | ((word_count << pac::spi::TXRXDFCOUNT_SHIFT) & pac::spi::TXRXDFCOUNT_MASK);
384 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
385 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
386
387 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
389 let _ = core::ptr::read_volatile(&spi.RX_DATA);
390 }
391
392 for i in 0..(word_count as usize) {
393 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
395 {
396 core::hint::spin_loop();
397 }
398 core::ptr::write_volatile(&mut spi.TX_DATA, 0xFFFFFFFF);
400 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK)
402 != 0
403 {
404 core::hint::spin_loop();
405 }
406 *words.add(i) = core::ptr::read_volatile(&spi.RX_DATA).to_be();
407 }
408
409 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
411 core::hint::spin_loop();
412 }
413
414 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
416 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
417 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
418 }
419
420 let data = &mut data[word_count as usize * 4..];
421
422 if !data.is_empty() {
423 spi.FRAMESIZE = 8;
425 spi.FRAMESUP = data.len() as u32 & pac::spi::BYTESUPPER_MASK;
426 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
427 | (((data.len() as u32) << pac::spi::TXRXDFCOUNT_SHIFT)
428 & pac::spi::TXRXDFCOUNT_MASK);
429 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
430 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
431
432 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
434 let _ = core::ptr::read_volatile(&spi.RX_DATA);
435 }
436
437 for i in 0..data.len() {
438 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
440 {
441 core::hint::spin_loop();
442 }
443 core::ptr::write_volatile(&mut spi.TX_DATA, 0xFFFFFFFF);
445 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK)
447 != 0
448 {
449 core::hint::spin_loop();
450 }
451 data[i] = core::ptr::read_volatile(&spi.RX_DATA) as u8;
452 }
453
454 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
456 core::hint::spin_loop();
457 }
458
459 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
461 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
462 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
463 }
464 }
465
466 Ok(())
467 }
468
469 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), SpiError> {
470 if read.is_empty() && write.is_empty() {
471 return Ok(());
472 }
473 let buffer_aligned: bool = write.as_ptr().align_offset(4) == 0
474 && read.as_ptr().align_offset(4) == 0
475 && (write.len() > 3 || read.len() > 3);
476
477 trace!(
478 "Transferring from SPI. Read len: {}; Write: {:x?}; Buffer aligned: {}",
479 read.len(),
480 write,
481 buffer_aligned
482 );
483
484 let total_bytes = read.len().max(write.len());
485 let mut tx_bytes_sent = 0;
486 let mut rx_bytes_received = 0;
487
488 unsafe {
489 let spi = &mut (*(*self.peripheral.address()).hw_reg);
490 let word_count = if buffer_aligned { total_bytes / 4 } else { 0 } as u32;
491 if word_count > 0 {
492 let tx_words = write.as_ptr() as *mut u32;
493 let rx_words = read.as_ptr() as *mut u32;
494
495 spi.FRAMESIZE = 32;
497 spi.FRAMESUP = word_count as u32 & pac::spi::BYTESUPPER_MASK;
498 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
499 | ((word_count << pac::spi::TXRXDFCOUNT_SHIFT) & pac::spi::TXRXDFCOUNT_MASK);
500 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
501 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
502
503 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
505 let _ = core::ptr::read_volatile(&spi.RX_DATA);
506 }
507
508 for i in 0..(word_count as usize) {
509 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
511 {
512 core::hint::spin_loop();
513 }
514 if tx_bytes_sent + 4 <= write.len() {
515 core::ptr::write_volatile(&mut spi.TX_DATA, (*tx_words.add(i)).to_be());
517 tx_bytes_sent += 4;
518 } else if tx_bytes_sent < write.len() {
519 let mut tx_data = 0x0;
520 let tx_bytes_remaining = write.len() - tx_bytes_sent;
521 while tx_bytes_sent < write.len() {
522 tx_data <<= 8;
523 tx_data |= write[tx_bytes_sent] as u32;
524 tx_bytes_sent += 1;
525 }
526 for _ in 0..(4 - tx_bytes_remaining) {
527 tx_data <<= 8;
528 tx_data |= 0xFF;
529 }
530 core::ptr::write_volatile(&mut spi.TX_DATA, tx_data);
532 } else {
533 core::ptr::write_volatile(&mut spi.TX_DATA, 0xFFFFFFFF);
535 }
536 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK)
538 != 0
539 {
540 core::hint::spin_loop();
541 }
542 let word = core::ptr::read_volatile(&spi.RX_DATA);
543 if rx_bytes_received + 4 <= read.len() {
544 *rx_words.add(i) = word.to_be();
545 rx_bytes_received += 4;
546 } else if rx_bytes_received < read.len() {
547 let rx_bytes_remaining = read.len() - rx_bytes_received;
548 for i in 0..(4 - rx_bytes_remaining) {
549 read[rx_bytes_received] = (word >> (8 * i)) as u8;
550 rx_bytes_received += 1;
551 }
552 }
553 }
554
555 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
557 core::hint::spin_loop();
558 }
559
560 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
562 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
563 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
564 }
565
566 let write = &write[tx_bytes_sent..];
567 let read = &mut read[rx_bytes_received..];
568 let remaining_bytes = read.len().max(write.len());
569
570 if remaining_bytes > 0 {
571 spi.FRAMESIZE = 8;
573 spi.FRAMESUP = remaining_bytes as u32 & pac::spi::BYTESUPPER_MASK;
574 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
575 | (((remaining_bytes as u32) << pac::spi::TXRXDFCOUNT_SHIFT)
576 & pac::spi::TXRXDFCOUNT_MASK);
577 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
578 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
579
580 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
582 let _ = core::ptr::read_volatile(&spi.RX_DATA);
583 }
584
585 for i in 0..remaining_bytes {
586 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
588 {
589 core::hint::spin_loop();
590 }
591 if i < write.len() {
592 core::ptr::write_volatile(&mut spi.TX_DATA, write[i] as u32);
594 }
595 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK)
597 != 0
598 {
599 core::hint::spin_loop();
600 }
601 if i < read.len() {
602 read[i] = core::ptr::read_volatile(&spi.RX_DATA) as u8;
603 }
604 }
605
606 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
608 core::hint::spin_loop();
609 }
610
611 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
613 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
614 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
615 }
616 }
617
618 Ok(())
619 }
620
621 fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), SpiError> {
622 if data.is_empty() {
623 return Ok(());
624 }
625
626 let buffer_aligned: bool = data.as_ptr().align_offset(4) == 0 && data.len() > 3;
627 trace!(
628 "Transferring in place, buffer aligned? {}; Data: {:x?}",
629 buffer_aligned,
630 data
631 );
632
633 unsafe {
634 let spi = &mut (*(*self.peripheral.address()).hw_reg);
635 let word_count = if buffer_aligned { data.len() / 4 } else { 0 } as u32;
636
637 if word_count > 0 {
638 let words = data.as_ptr() as *mut u32;
639
640 spi.FRAMESIZE = 32;
642 spi.FRAMESUP = word_count as u32 & pac::spi::BYTESUPPER_MASK;
643 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
644 | ((word_count << pac::spi::TXRXDFCOUNT_SHIFT) & pac::spi::TXRXDFCOUNT_MASK);
645 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
646 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
647
648 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
650 let _ = core::ptr::read_volatile(&spi.RX_DATA);
651 }
652
653 for i in 0..(word_count as usize) {
654 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
656 {
657 core::hint::spin_loop();
658 }
659 core::ptr::write_volatile(&mut spi.TX_DATA, (*words.add(i)).to_be());
661
662 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK)
664 != 0
665 {
666 core::hint::spin_loop();
667 }
668 *words.add(i) = core::ptr::read_volatile(&spi.RX_DATA).to_be();
669 }
670
671 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
673 core::hint::spin_loop();
674 }
675
676 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
678 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
679 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
680 }
681
682 let data = &mut data[word_count as usize * 4..];
683
684 if !data.is_empty() {
685 spi.FRAMESIZE = 8;
687 spi.FRAMESUP = data.len() as u32 & pac::spi::BYTESUPPER_MASK;
688 let control = (spi.CONTROL & !pac::spi::TXRXDFCOUNT_MASK)
689 | (((data.len() as u32) << pac::spi::TXRXDFCOUNT_SHIFT)
690 & pac::spi::TXRXDFCOUNT_MASK);
691 spi.CONTROL = control | pac::spi::CTRL_ENABLE_MASK;
692 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
693
694 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK) == 0 {
696 let _ = core::ptr::read_volatile(&spi.RX_DATA);
697 }
698
699 for i in 0..data.len() {
700 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::TX_FIFO_FULL_MASK) != 0
702 {
703 core::hint::spin_loop();
704 }
705 core::ptr::write_volatile(&mut spi.TX_DATA, data[i] as u32);
707
708 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::RX_FIFO_EMPTY_MASK)
710 != 0
711 {
712 core::hint::spin_loop();
713 }
714 data[i] = core::ptr::read_volatile(&spi.RX_DATA) as u8;
715 }
716
717 while (core::ptr::read_volatile(&spi.STATUS) & pac::spi::ACTIVE_MASK) != 0 {
719 core::hint::spin_loop();
720 }
721
722 spi.COMMAND |= pac::spi::TX_FIFO_RESET_MASK | pac::spi::RX_FIFO_RESET_MASK;
724 spi.CONTROL &= !pac::spi::CTRL_ENABLE_MASK;
725 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
726 }
727 }
728
729 Ok(())
730 }
731}