1use crate::pac;
2use embassy_embedded_hal::SetConfig;
3use embedded_hal::spi::{Phase, Polarity};
4
5static mut QSPI_TAKEN: bool = false;
6
7pub fn init() {
8 unsafe {
9 pac::mss_config_clk_rst(
10 pac::mss_peripherals__MSS_PERIPH_QSPIXIP,
11 pac::MPFS_HAL_FIRST_HART as u8,
12 pac::PERIPH_RESET_STATE__PERIPHERAL_ON,
13 );
14 pac::MSS_QSPI_init();
15 }
16}
17
18pub struct Qspi {
19 _private: (),
20}
21
22impl crate::Peripheral for Qspi {
23 fn take() -> Option<Self> {
24 critical_section::with(|_| unsafe {
25 if QSPI_TAKEN {
26 None
27 } else {
28 QSPI_TAKEN = true;
29 Some(Self { _private: () })
30 }
31 })
32 }
33
34 unsafe fn steal() -> Self {
35 Self { _private: () }
36 }
37}
38
39impl embedded_hal::spi::ErrorType for Qspi {
40 type Error = SpiError;
41}
42
43#[derive(Debug)]
44pub enum SpiError {}
45
46impl embedded_hal::spi::Error for SpiError {
47 fn kind(&self) -> embedded_hal::spi::ErrorKind {
48 embedded_hal::spi::ErrorKind::Other
49 }
50}
51
52#[derive(Debug, Clone, Copy)]
53pub struct SpiConfig {
54 pub frequency: SpiFrequency,
55 pub phase: Phase,
56 pub polarity: Polarity,
57}
58
59impl Default for SpiConfig {
60 fn default() -> Self {
61 Self {
62 frequency: SpiFrequency::F5_000_000,
63 phase: Phase::CaptureOnFirstTransition,
64 polarity: Polarity::IdleLow,
65 }
66 }
67}
68
69#[derive(Debug, Clone, Copy)]
70#[repr(u8)]
71pub enum SpiFrequency {
72 F75_000_000 = 1, F37_500_000 = 2, F25_000_000 = 3, F18_750_000 = 4, F15_000_000 = 5, F12_500_000 = 6, F10_714_285 = 7, F9_375_000 = 8, F8_333_333 = 9, F7_500_000 = 0xA, F6_818_181 = 0xB, F6_250_000 = 0xC, F5_769_230 = 0xD, F5_357_142 = 0xE, F5_000_000 = 0xF, }
88
89impl SetConfig for Qspi {
90 type Config = SpiConfig;
91 type ConfigError = ();
92 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
93 unsafe {
94 let sample = if config.phase == Phase::CaptureOnFirstTransition {
95 pac::MSS_QSPI_SAMPLE_POSAGE_SPICLK
96 } else {
97 pac::MSS_QSPI_SAMPLE_NEGAGE_SPICLK
98 };
99 let mode = if config.polarity == Polarity::IdleLow {
100 pac::mss_qspi_protocol_mode_t_MSS_QSPI_MODE0
101 } else {
102 pac::mss_qspi_protocol_mode_t_MSS_QSPI_MODE3
103 };
104 let value = (sample << pac::CTRL_SAMPLE)
105 | ((config.frequency as u32) << pac::CTRL_CLKRATE)
106 | (pac::mss_qspi_io_format_t_MSS_QSPI_NORMAL << pac::CTRL_QMODE12)
107 | (mode << pac::CTRL_CLKIDL)
108 | (0 << pac::CTRL_XIP)
109 | (0 << pac::CTRL_XIPADDR)
110 | pac::CTRL_EN_MASK;
111 trace!("QSPI Control Register: {:#032b}", value);
112 (*pac::QSPI).CONTROL = value;
113 }
114 Ok(())
115 }
116}
117
118impl embedded_hal::spi::SpiBus<u8> for Qspi {
121 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
122 let buffer_aligned: bool = words.as_ptr().align_offset(4) == 0 && words.len() > 3;
123 trace!("Reading from QSPI. Buffer aligned: {:?}", buffer_aligned);
124 unsafe {
125 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_READY_MASK) == 0 {
127 core::hint::spin_loop();
128 }
129
130 (*pac::QSPI).INTENABLE = 0;
132
133 let total_bytes = words.len();
135 (*pac::QSPI).FRAMESUP = (total_bytes as u32) & pac::FRMS_UBYTES_MASK;
136
137 let mut frame_ctrl = (total_bytes as u32) & 0xFFFF;
139 frame_ctrl |= 0 << pac::FRMS_CBYTES; frame_ctrl |= ((*pac::QSPI).CONTROL & pac::CTRL_QMODE12_MASK) << pac::FRMS_QSPI; frame_ctrl |= if buffer_aligned {
143 pac::FRMS_FWORD_MASK
144 } else {
145 pac::FRMS_FBYTE_MASK
146 };
147 (*pac::QSPI).FRAMES = frame_ctrl;
148 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
149
150 let word_count = if buffer_aligned { total_bytes / 4 } else { 0 };
151 if buffer_aligned {
152 (*pac::QSPI).CONTROL |= pac::CTRL_FLAGSX4_MASK;
154
155 let words_32 = words.as_ptr() as *mut u32;
157
158 for i in 0..word_count {
159 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK)
161 != 0
162 {
163 core::hint::spin_loop();
164 }
165 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX4, 0xFFFFFFFF);
167
168 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RFEMPTY_MASK)
170 != 0
171 {
172 core::hint::spin_loop();
173 }
174 *words_32.add(i) = core::ptr::read_volatile(&(*pac::QSPI).RXDATAX4);
175 }
176
177 (*pac::QSPI).CONTROL &= !pac::CTRL_FLAGSX4_MASK;
179
180 if total_bytes % 4 != 0 {
181 pac::sleep_ms(10);
183 }
184 }
185
186 let remaining_start = word_count * 4;
188 for i in remaining_start..total_bytes {
189 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK) != 0
191 {
192 core::hint::spin_loop();
193 }
194 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX1, 0xFF);
196
197 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RFEMPTY_MASK) != 0
199 {
200 core::hint::spin_loop();
201 }
202 words[i] = core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1);
203 }
204 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RDONE_MASK) == 0 {
206 warn!("Warning: read not complete");
207 if (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_FLAGSX4_MASK) != 0 {
208 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX4);
209 } else {
210 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1);
211 }
212 }
213 }
214 trace!("QSPI read complete: {:x?}", words);
215 Ok(())
216 }
217
218 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
219 let buffer_aligned: bool = words.as_ptr().align_offset(4) == 0 && words.len() > 3;
220 trace!(
221 "Writing to QSPI {:x?}. Buffer aligned: {:?}",
222 words,
223 buffer_aligned
224 );
225 unsafe {
226 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_READY_MASK) == 0 {
228 core::hint::spin_loop();
229 }
230
231 (*pac::QSPI).INTENABLE = 0;
233
234 let total_bytes = words.len();
236 (*pac::QSPI).FRAMESUP = (total_bytes as u32) & pac::FRMS_UBYTES_MASK;
237
238 let mut frame_ctrl = (total_bytes as u32) & 0xFFFF;
240 frame_ctrl |= 0 << pac::FRMS_CBYTES; frame_ctrl |= ((*pac::QSPI).CONTROL & pac::CTRL_QMODE12_MASK) << pac::FRMS_QSPI; frame_ctrl |= pac::FRMS_FWORD_MASK; (*pac::QSPI).FRAMES = frame_ctrl;
245 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
246
247 let word_count = if buffer_aligned { total_bytes / 4 } else { 0 };
248 if buffer_aligned {
249 (*pac::QSPI).CONTROL |= pac::CTRL_FLAGSX4_MASK;
251
252 let words_32 = words.as_ptr() as *const u32;
254
255 for i in 0..word_count {
256 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK)
258 != 0
259 {
260 core::hint::spin_loop();
261 }
262 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX4, *words_32.add(i));
264 }
265
266 (*pac::QSPI).CONTROL &= !pac::CTRL_FLAGSX4_MASK;
268
269 if total_bytes % 4 != 0 {
270 pac::sleep_ms(10);
272 }
273 }
274
275 let remaining_start = word_count * 4;
277 for i in remaining_start..total_bytes {
278 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK) != 0
280 {
281 core::hint::spin_loop();
282 }
283 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX1, words[i]);
285 }
286 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TDONE_MASK) == 0 {
288 core::hint::spin_loop();
289 }
290 }
291 trace!("QSPI write complete");
292 Ok(())
293 }
294
295 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
296 let buffer_aligned: bool = write.as_ptr().align_offset(4) == 0
297 && read.as_ptr().align_offset(4) == 0
298 && (write.len() > 3 || read.len() > 3);
299 trace!(
300 "QSPI transfer {:x?}. Buffer aligned: {:?}",
301 write,
302 buffer_aligned
303 );
304 unsafe {
305 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_READY_MASK) == 0 {
307 core::hint::spin_loop();
308 }
309
310 (*pac::QSPI).INTENABLE = 0;
312
313 let total_bytes = read.len().max(write.len());
315 (*pac::QSPI).FRAMESUP = (total_bytes as u32) & pac::FRMS_UBYTES_MASK;
316
317 let mut frame_ctrl = (total_bytes as u32) & 0xFFFF;
319 frame_ctrl |= 0 << pac::FRMS_CBYTES; frame_ctrl |= ((*pac::QSPI).CONTROL & pac::CTRL_QMODE12_MASK) << pac::FRMS_QSPI; frame_ctrl |= if buffer_aligned {
323 pac::FRMS_FWORD_MASK
324 } else {
325 pac::FRMS_FBYTE_MASK
326 };
327 (*pac::QSPI).FRAMES = frame_ctrl;
328 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
329
330 (*pac::QSPI).CONTROL |= pac::CTRL_FLAGSX4_MASK;
332
333 let write_32 = write.as_ptr() as *const u32;
335 let read_32 = read.as_ptr() as *mut u32;
336 let word_count = if buffer_aligned { total_bytes / 4 } else { 0 };
337 let tx_word_count = write.len() / 4;
338 let rx_word_count = read.len() / 4;
339 if buffer_aligned {
340 for i in 0..word_count {
341 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK)
343 != 0
344 {
345 core::hint::spin_loop();
346 }
347 if i < tx_word_count {
348 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX4, *write_32.add(i));
350 } else {
351 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX4, 0xFFFFFFFF);
353 }
354
355 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RFEMPTY_MASK)
357 != 0
358 {
359 core::hint::spin_loop();
360 }
361 if i < rx_word_count {
362 *read_32.add(i) = core::ptr::read_volatile(&(*pac::QSPI).RXDATAX4);
363 } else {
364 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1); }
366 }
367
368 (*pac::QSPI).CONTROL &= !pac::CTRL_FLAGSX4_MASK;
370
371 if total_bytes % 4 != 0 {
372 pac::sleep_ms(10);
374 }
375 }
376
377 let remaining_start = word_count * 4;
379 for i in remaining_start..total_bytes {
380 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK) != 0
382 {
383 core::hint::spin_loop();
384 }
385 if i < write.len() {
386 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX1, write[i]);
388 } else {
389 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX1, 0xFF);
391 }
392
393 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RFEMPTY_MASK) != 0
395 {
396 core::hint::spin_loop();
397 }
398 if i < read.len() {
399 read[i] = core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1);
400 } else {
401 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1); }
403 }
404 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RDONE_MASK) == 0 {
406 warn!("Warning: read not complete");
407 if (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_FLAGSX4_MASK) != 0 {
408 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX4);
409 } else {
410 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1);
411 }
412 }
413 }
414 trace!("QSPI transfer received {:x?}", read);
415 Ok(())
416 }
417
418 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
419 let buffer_aligned: bool = words.as_ptr().align_offset(4) == 0 && words.len() > 3;
420 trace!(
421 "QSPI transfer_in_place {:x?}. Buffer aligned: {:?}",
422 words,
423 buffer_aligned
424 );
425 unsafe {
426 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_READY_MASK) == 0 {
428 core::hint::spin_loop();
429 }
430
431 (*pac::QSPI).INTENABLE = 0;
433
434 let total_bytes = words.len();
436 (*pac::QSPI).FRAMESUP = (total_bytes as u32) & pac::FRMS_UBYTES_MASK;
437
438 let mut frame_ctrl = (total_bytes as u32) & 0xFFFF;
440 frame_ctrl |= 0 << pac::FRMS_CBYTES; frame_ctrl |= ((*pac::QSPI).CONTROL & pac::CTRL_QMODE12_MASK) << pac::FRMS_QSPI; frame_ctrl |= if buffer_aligned {
444 pac::FRMS_FWORD_MASK
445 } else {
446 pac::FRMS_FBYTE_MASK
447 };
448 (*pac::QSPI).FRAMES = frame_ctrl;
449 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
450
451 let word_count = if buffer_aligned { total_bytes / 4 } else { 0 };
452 if buffer_aligned {
453 (*pac::QSPI).CONTROL |= pac::CTRL_FLAGSX4_MASK;
455
456 let words_32 = words.as_ptr() as *mut u32;
458
459 for i in 0..word_count {
460 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK)
462 != 0
463 {
464 core::hint::spin_loop();
465 }
466 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX4, *words_32.add(i));
468
469 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RFEMPTY_MASK)
471 != 0
472 {
473 core::hint::spin_loop();
474 }
475 *words_32.add(i) = core::ptr::read_volatile(&(*pac::QSPI).RXDATAX4);
476 }
477
478 (*pac::QSPI).CONTROL &= !pac::CTRL_FLAGSX4_MASK;
480
481 if total_bytes % 4 != 0 {
482 pac::sleep_ms(10);
484 }
485 }
486
487 let remaining_start = word_count * 4;
489 for i in remaining_start..total_bytes {
490 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_TFFULL_MASK) != 0
492 {
493 core::hint::spin_loop();
494 }
495 core::ptr::write_volatile(&mut (*pac::QSPI).TXDATAX1, words[i]);
497
498 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RFEMPTY_MASK) != 0
500 {
501 core::hint::spin_loop();
502 }
503 words[i] = core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1);
504 }
505 while (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_RDONE_MASK) == 0 {
507 warn!("Warning: read not complete");
508 if (core::ptr::read_volatile(&(*pac::QSPI).STATUS) & pac::STTS_FLAGSX4_MASK) != 0 {
509 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX4);
510 } else {
511 core::ptr::read_volatile(&(*pac::QSPI).RXDATAX1);
512 }
513 }
514 }
515 trace!("QSPI transfer_in_place received {:x?}", words);
516 Ok(())
517 }
518
519 fn flush(&mut self) -> Result<(), Self::Error> {
520 Ok(())
521 }
522}
523
524impl embedded_hal_async::spi::SpiBus<u8> for Qspi {
526 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
527 embedded_hal::spi::SpiBus::read(self, words)
528 }
529
530 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
531 embedded_hal::spi::SpiBus::write(self, words)
532 }
533
534 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
535 embedded_hal::spi::SpiBus::transfer(self, read, write)
536 }
537
538 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
539 embedded_hal::spi::SpiBus::transfer_in_place(self, words)
540 }
541
542 async fn flush(&mut self) -> Result<(), Self::Error> {
543 embedded_hal::spi::SpiBus::flush(self)
544 }
545}
546
547