libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
mspm0_spi.cpp
1#include "mspm0_spi.hpp"
2
3#include <cstring>
4
5#include "timebase.hpp"
6
7using namespace LibXR;
8
9namespace
10{
11constexpr uint32_t MSPM0_SPI_DMA_INTERRUPT_MASK =
12 DL_SPI_INTERRUPT_DMA_DONE_RX | DL_SPI_INTERRUPT_DMA_DONE_TX |
13 DL_SPI_INTERRUPT_TX_UNDERFLOW | DL_SPI_INTERRUPT_PARITY_ERROR |
14 DL_SPI_INTERRUPT_RX_OVERFLOW | DL_SPI_INTERRUPT_RX_TIMEOUT;
15} // namespace
16
17MSPM0SPI* MSPM0SPI::instance_map_[MAX_SPI_INSTANCES] = {nullptr};
18
19MSPM0SPI::MSPM0SPI(Resources res, RawData dma_rx_buffer, RawData dma_tx_buffer,
20 uint32_t dma_enable_min_size, SPI::Configuration config)
21 : SPI(dma_rx_buffer, dma_tx_buffer),
22 res_(res),
23 dma_enable_min_size_(dma_enable_min_size)
24{
25 ASSERT(res_.instance != nullptr);
26 ASSERT(res_.clock_freq > 0);
27 ASSERT(res_.index < MAX_SPI_INSTANCES);
28 ASSERT(instance_map_[res_.index] == nullptr);
29 ASSERT(dma_rx_buffer.addr_ != nullptr);
30 ASSERT(dma_tx_buffer.addr_ != nullptr);
31 ASSERT(dma_rx_buffer.size_ > 0);
32 ASSERT(dma_tx_buffer.size_ > 0);
33
34 instance_map_[res_.index] = this;
35
36 NVIC_ClearPendingIRQ(res_.irqn);
37 NVIC_EnableIRQ(res_.irqn);
38
39 const ErrorCode SET_CFG_ANS = SetConfig(config);
40 ASSERT(SET_CFG_ANS == ErrorCode::OK);
41}
42
44{
45 DL_SPI_FRAME_FORMAT frame_format = DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA0;
47 {
48 frame_format = (config.clock_phase == ClockPhase::EDGE_1)
49 ? DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA0
50 : DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA1;
51 }
52 else
53 {
54 frame_format = (config.clock_phase == ClockPhase::EDGE_1)
55 ? DL_SPI_FRAME_FORMAT_MOTO4_POL1_PHA0
56 : DL_SPI_FRAME_FORMAT_MOTO4_POL1_PHA1;
57 }
58
59 const uint32_t DIV = SPI::PrescalerToDiv(config.prescaler);
60 if (DIV < 2 || DIV > 512 || (DIV & 0x1) != 0)
61 {
63 }
64
65 const uint32_t SCR = (DIV >> 1) - 1;
66
67 DL_SPI_disable(res_.instance);
68 DL_SPI_setFrameFormat(res_.instance, frame_format);
69 DL_SPI_setBitRateSerialClockDivider(res_.instance, SCR);
70 DL_SPI_enable(res_.instance);
71
72 GetConfig() = config;
73 return ErrorCode::OK;
74}
75
76uint32_t MSPM0SPI::GetMaxBusSpeed() const { return res_.clock_freq; }
77
79
80ErrorCode MSPM0SPI::PollingTransfer(uint8_t* rx, const uint8_t* tx, uint32_t len)
81{
82 constexpr uint32_t POLLING_TIMEOUT_US = 20000U;
83 constexpr uint32_t POLLING_FALLBACK_SPIN_BUDGET = 1000000U;
84
85 if (len == 0)
86 {
87 return ErrorCode::OK;
88 }
89
90 const uint64_t START_US = static_cast<uint64_t>(Timebase::GetMicroseconds());
91
92 uint32_t spin_budget = POLLING_FALLBACK_SPIN_BUDGET;
93 auto polling_timed_out = [&]() -> bool
94 {
95 const uint64_t NOW_US = static_cast<uint64_t>(Timebase::GetMicroseconds());
96 if ((NOW_US - START_US) >= POLLING_TIMEOUT_US)
97 {
98 return true;
99 }
100 if (spin_budget > 0U)
101 {
102 --spin_budget;
103 }
104 return false;
105 };
106
107 for (uint32_t i = 0; i < len; ++i)
108 {
109 while (DL_SPI_isTXFIFOFull(res_.instance))
110 {
111 if (polling_timed_out())
112 {
113 return ErrorCode::TIMEOUT;
114 }
115 }
116 const uint8_t TX_BYTE = (tx == nullptr) ? 0 : tx[i];
117 DL_SPI_transmitData8(res_.instance, TX_BYTE);
118
119 uint8_t rx_byte = 0;
120 while (!DL_SPI_receiveDataCheck8(res_.instance, &rx_byte))
121 {
122 if (polling_timed_out())
123 {
124 return ErrorCode::TIMEOUT;
125 }
126 }
127
128 if (rx != nullptr)
129 {
130 rx[i] = rx_byte;
131 }
132 }
133
134 while (DL_SPI_isBusy(res_.instance))
135 {
136 if (polling_timed_out())
137 {
138 return ErrorCode::TIMEOUT;
139 }
140 }
141
142 return ErrorCode::OK;
143}
144
145bool MSPM0SPI::DmaBusy() const
146{
147 if (busy_)
148 {
149 return true;
150 }
151
152 return DL_DMA_isChannelEnabled(DMA, res_.dma_rx_channel) ||
153 DL_DMA_isChannelEnabled(DMA, res_.dma_tx_channel);
154}
155
156void MSPM0SPI::StartDmaDuplex(uint32_t count)
157{
158 masked_interrupts_for_tx_only_ = 0;
159
160 RawData rx = GetRxBuffer();
161 RawData tx = GetTxBuffer();
162
163 DL_DMA_setSrcAddr(DMA, res_.dma_rx_channel,
164 reinterpret_cast<uint32_t>(&res_.instance->RXDATA));
165 DL_DMA_setDestAddr(DMA, res_.dma_rx_channel, reinterpret_cast<uint32_t>(rx.addr_));
166 DL_DMA_setTransferSize(DMA, res_.dma_rx_channel, count);
167
168 DL_DMA_setSrcAddr(DMA, res_.dma_tx_channel, reinterpret_cast<uint32_t>(tx.addr_));
169 DL_DMA_setDestAddr(DMA, res_.dma_tx_channel,
170 reinterpret_cast<uint32_t>(&res_.instance->TXDATA));
171 DL_DMA_setTransferSize(DMA, res_.dma_tx_channel, count);
172
173 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
174 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
175}
176
177void MSPM0SPI::StartDmaRxOnly(uint32_t offset, uint32_t count)
178{
179 RawData rx = GetRxBuffer();
180
181 ASSERT(offset < rx.size_);
182 ASSERT(count > 0U);
183 ASSERT(count <= RX_ONLY_REPEAT_TX_MAX_FRAMES);
184 ASSERT((offset + count) <= rx.size_);
185
186 masked_interrupts_for_tx_only_ = 0;
187
188 auto* rx_bytes = static_cast<uint8_t*>(rx.addr_);
189
190 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
191 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
192 DL_DMA_setSrcAddr(DMA, res_.dma_rx_channel,
193 reinterpret_cast<uint32_t>(&res_.instance->RXDATA));
194 DL_DMA_setDestAddr(DMA, res_.dma_rx_channel,
195 reinterpret_cast<uint32_t>(rx_bytes + offset));
196 DL_DMA_setTransferSize(DMA, res_.dma_rx_channel, count);
197 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
198
199 // RX-only DMA 仍需要主机时钟,使用硬件重复 dummy TX 提供时钟 / RX-only DMA
200 // still needs controller clocks; use repeated dummy TX in hardware so read-only
201 // transfers can avoid occupying the TX DMA channel.
202 DL_SPI_setRepeatTransmit(res_.instance, static_cast<uint8_t>(count - 1U));
203 DL_SPI_transmitData8(res_.instance, 0U);
204}
205
206void MSPM0SPI::StartDmaTxOnly(uint32_t count)
207{
208 constexpr uint32_t TX_ONLY_MASKED_INTERRUPTS = DL_SPI_INTERRUPT_DMA_DONE_RX |
209 DL_SPI_INTERRUPT_RX_OVERFLOW |
210 DL_SPI_INTERRUPT_RX_TIMEOUT;
211
212 masked_interrupts_for_tx_only_ =
213 DL_SPI_getEnabledInterrupts(res_.instance, TX_ONLY_MASKED_INTERRUPTS);
214 if (masked_interrupts_for_tx_only_ != 0U)
215 {
216 DL_SPI_disableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
217 }
218
219 RawData tx = GetTxBuffer();
220
221 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
222 DL_DMA_setSrcAddr(DMA, res_.dma_tx_channel, reinterpret_cast<uint32_t>(tx.addr_));
223 DL_DMA_setDestAddr(DMA, res_.dma_tx_channel,
224 reinterpret_cast<uint32_t>(&res_.instance->TXDATA));
225 DL_DMA_setTransferSize(DMA, res_.dma_tx_channel, count);
226 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
227}
228
229void MSPM0SPI::StopDma()
230{
231 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
232 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
233
234 if (dma_mode_ == DmaMode::RX_ONLY)
235 {
236 DL_SPI_setRepeatTransmit(res_.instance, 0U);
237 }
238
239 rx_only_offset_ = 0U;
240 rx_only_remaining_ = 0U;
241
242 if (masked_interrupts_for_tx_only_ != 0U)
243 {
244 DL_SPI_enableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
245 masked_interrupts_for_tx_only_ = 0U;
246 }
247}
248
249ErrorCode MSPM0SPI::CompleteDmaOperation(OperationRW& op, bool in_isr)
250{
251 op.MarkAsRunning();
252 if (op.type != OperationRW::OperationType::BLOCK)
253 {
254 return ErrorCode::OK;
255 }
256
257 ASSERT(!in_isr);
258 const ErrorCode WAIT_ANS = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
259 if (WAIT_ANS == ErrorCode::TIMEOUT)
260 {
261 const bool IRQ_WAS_ENABLED = (NVIC_GetEnableIRQ(res_.irqn) != 0U);
262 if (IRQ_WAS_ENABLED)
263 {
264 NVIC_DisableIRQ(res_.irqn);
265 }
266
267 StopDma();
268 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
269 NVIC_ClearPendingIRQ(res_.irqn);
270
271 busy_ = false;
272 dma_mode_ = DmaMode::DUPLEX;
273 dma_result_ = ErrorCode::TIMEOUT;
274 rw_op_ = OperationRW();
275 // Drain any timeout-race semaphore credits posted right before IRQ disable,
276 // so the next BLOCK transfer cannot consume a stale completion signal.
277 while (op.data.sem_info.sem->Wait(0U) == ErrorCode::OK)
278 {
279 }
280
281 if (IRQ_WAS_ENABLED)
282 {
283 NVIC_EnableIRQ(res_.irqn);
284 }
285 return ErrorCode::TIMEOUT;
286 }
287
288 if (WAIT_ANS != ErrorCode::OK)
289 {
290 return WAIT_ANS;
291 }
292
293 return dma_result_;
294}
295
297 OperationRW& op, bool in_isr)
298{
299 const uint32_t NEED = static_cast<uint32_t>(max(read_data.size_, write_data.size_));
300 const bool IS_READ_ONLY = (write_data.size_ == 0U) && (read_data.size_ > 0U);
301
302 if (NEED == 0)
303 {
304 if (op.type != OperationRW::OperationType::BLOCK)
305 {
306 op.UpdateStatus(in_isr, ErrorCode::OK);
307 }
308 return ErrorCode::OK;
309 }
310
311 if (DmaBusy())
312 {
313 return ErrorCode::BUSY;
314 }
315
316 RawData rx = GetRxBuffer();
317 RawData tx = GetTxBuffer();
318
319 if (rx.size_ < NEED)
320 {
321 return ErrorCode::SIZE_ERR;
322 }
323 if (!IS_READ_ONLY && tx.size_ < NEED)
324 {
325 return ErrorCode::SIZE_ERR;
326 }
327
328 ASSERT(rx.size_ >= NEED);
329 if (!IS_READ_ONLY)
330 {
331 ASSERT(tx.size_ >= NEED);
332 }
333
334 uint8_t* tx_bytes = nullptr;
335 if (!IS_READ_ONLY)
336 {
337 tx_bytes = static_cast<uint8_t*>(tx.addr_);
338 if (write_data.size_ > 0)
339 {
340 Memory::FastCopy(tx_bytes, write_data.addr_, write_data.size_);
341 }
342 if (write_data.size_ < NEED)
343 {
344 Memory::FastSet(tx_bytes + write_data.size_, 0, NEED - write_data.size_);
345 }
346 }
347
348 if (NEED > dma_enable_min_size_)
349 {
350 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
351 NVIC_ClearPendingIRQ(res_.irqn);
352
353 mem_read_ = false;
354 read_buff_ = read_data;
355 rw_op_ = op;
356 dma_result_ = ErrorCode::PENDING;
357 busy_ = true;
358
359 if (IS_READ_ONLY)
360 {
361 dma_mode_ = DmaMode::RX_ONLY;
362 const uint32_t FIRST_CHUNK = min(NEED, RX_ONLY_REPEAT_TX_MAX_FRAMES);
363 rx_only_offset_ = FIRST_CHUNK;
364 rx_only_remaining_ = NEED - FIRST_CHUNK;
365 StartDmaRxOnly(0U, FIRST_CHUNK);
366 }
367 else
368 {
369 dma_mode_ = DmaMode::DUPLEX;
370 StartDmaDuplex(NEED);
371 }
372 return CompleteDmaOperation(op, in_isr);
373 }
374
375 ErrorCode ans = PollingTransfer(static_cast<uint8_t*>(rx.addr_), tx_bytes, NEED);
376
377 if (ans == ErrorCode::OK && read_data.size_ > 0)
378 {
379 Memory::FastCopy(read_data.addr_, rx.addr_, read_data.size_);
380 }
381
382 SwitchBuffer();
383
384 if (op.type != OperationRW::OperationType::BLOCK)
385 {
386 op.UpdateStatus(in_isr, ans);
387 }
388
389 return ans;
390}
391
392ErrorCode MSPM0SPI::Transfer(size_t size, OperationRW& op, bool in_isr)
393{
394 if (size == 0)
395 {
396 if (op.type != OperationRW::OperationType::BLOCK)
397 {
398 op.UpdateStatus(in_isr, ErrorCode::OK);
399 }
400 return ErrorCode::OK;
401 }
402
403 if (DmaBusy())
404 {
405 return ErrorCode::BUSY;
406 }
407
408 RawData rx = GetRxBuffer();
409 RawData tx = GetTxBuffer();
410
411 ASSERT(rx.size_ >= size);
412 ASSERT(tx.size_ >= size);
413
414 if (size > dma_enable_min_size_)
415 {
416 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
417 NVIC_ClearPendingIRQ(res_.irqn);
418
419 mem_read_ = false;
420 dma_mode_ = DmaMode::DUPLEX;
421 read_buff_ = {nullptr, 0};
422 rw_op_ = op;
423 dma_result_ = ErrorCode::PENDING;
424 busy_ = true;
425
426 StartDmaDuplex(static_cast<uint32_t>(size));
427 return CompleteDmaOperation(op, in_isr);
428 }
429
430 ErrorCode ans =
431 PollingTransfer(static_cast<uint8_t*>(rx.addr_),
432 static_cast<const uint8_t*>(tx.addr_), static_cast<uint32_t>(size));
433
434 SwitchBuffer();
435
436 if (op.type != OperationRW::OperationType::BLOCK)
437 {
438 op.UpdateStatus(in_isr, ans);
439 }
440
441 return ans;
442}
443
444ErrorCode MSPM0SPI::MemRead(uint16_t reg, RawData read_data, OperationRW& op, bool in_isr)
445{
446 const uint32_t NEED_READ = static_cast<uint32_t>(read_data.size_);
447 if (NEED_READ == 0)
448 {
449 if (op.type != OperationRW::OperationType::BLOCK)
450 {
451 op.UpdateStatus(in_isr, ErrorCode::OK);
452 }
453 return ErrorCode::OK;
454 }
455
456 if (DmaBusy())
457 {
458 return ErrorCode::BUSY;
459 }
460
461 RawData rx = GetRxBuffer();
462 RawData tx = GetTxBuffer();
463
464 ASSERT(rx.size_ >= (NEED_READ + 1));
465 ASSERT(tx.size_ >= (NEED_READ + 1));
466
467 auto* tx_bytes = static_cast<uint8_t*>(tx.addr_);
468 tx_bytes[0] = static_cast<uint8_t>(reg | 0x80);
469 Memory::FastSet(tx_bytes + 1, 0, NEED_READ);
470
471 const uint32_t TOTAL = NEED_READ + 1;
472
473 if (TOTAL > dma_enable_min_size_)
474 {
475 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
476 NVIC_ClearPendingIRQ(res_.irqn);
477
478 mem_read_ = true;
479 dma_mode_ = DmaMode::DUPLEX;
480 read_buff_ = read_data;
481 rw_op_ = op;
482 dma_result_ = ErrorCode::PENDING;
483 busy_ = true;
484
485 StartDmaDuplex(TOTAL);
486 return CompleteDmaOperation(op, in_isr);
487 }
488
489 ErrorCode ans = PollingTransfer(static_cast<uint8_t*>(rx.addr_), tx_bytes, TOTAL);
490
491 if (ans == ErrorCode::OK)
492 {
493 auto* rx_bytes = static_cast<uint8_t*>(rx.addr_);
494 Memory::FastCopy(read_data.addr_, rx_bytes + 1, NEED_READ);
495 }
496
497 SwitchBuffer();
498
499 if (op.type != OperationRW::OperationType::BLOCK)
500 {
501 op.UpdateStatus(in_isr, ans);
502 }
503
504 return ans;
505}
506
508 bool in_isr)
509{
510 const uint32_t NEED_WRITE = static_cast<uint32_t>(write_data.size_);
511 if (NEED_WRITE == 0)
512 {
513 if (op.type != OperationRW::OperationType::BLOCK)
514 {
515 op.UpdateStatus(in_isr, ErrorCode::OK);
516 }
517 return ErrorCode::OK;
518 }
519
520 if (DmaBusy())
521 {
522 return ErrorCode::BUSY;
523 }
524
525 RawData tx = GetTxBuffer();
526 ASSERT(tx.size_ >= (NEED_WRITE + 1));
527
528 auto* tx_bytes = static_cast<uint8_t*>(tx.addr_);
529 tx_bytes[0] = static_cast<uint8_t>(reg & 0x7F);
530 Memory::FastCopy(tx_bytes + 1, write_data.addr_, NEED_WRITE);
531
532 const uint32_t TOTAL = NEED_WRITE + 1;
533
534 if (TOTAL > dma_enable_min_size_)
535 {
536 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
537 NVIC_ClearPendingIRQ(res_.irqn);
538
539 mem_read_ = false;
540 dma_mode_ = DmaMode::TX_ONLY;
541 read_buff_ = {nullptr, 0};
542 rw_op_ = op;
543 dma_result_ = ErrorCode::PENDING;
544 busy_ = true;
545
546 StartDmaTxOnly(TOTAL);
547 return CompleteDmaOperation(op, in_isr);
548 }
549
550 RawData rx = GetRxBuffer();
551 ErrorCode ans = PollingTransfer(static_cast<uint8_t*>(rx.addr_), tx_bytes, TOTAL);
552
553 SwitchBuffer();
554
555 if (op.type != OperationRW::OperationType::BLOCK)
556 {
557 op.UpdateStatus(in_isr, ans);
558 }
559
560 return ans;
561}
562
563void MSPM0SPI::OnInterrupt(uint8_t index)
564{
565 if (index >= MAX_SPI_INSTANCES)
566 {
567 return;
568 }
569
570 MSPM0SPI* spi = instance_map_[index];
571 if (spi == nullptr)
572 {
573 return;
574 }
575
576 spi->HandleInterrupt();
577}
578
579void MSPM0SPI::HandleInterrupt()
580{
581 if (!busy_)
582 {
583 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
584 return;
585 }
586
587 auto drain_rx_fifo = [this]() -> bool
588 {
589 constexpr uint32_t RX_FIFO_DRAIN_MAX_ITERATIONS = 1024U;
590 uint32_t remaining = RX_FIFO_DRAIN_MAX_ITERATIONS;
591 uint8_t discard = 0U;
592 while (remaining > 0U && DL_SPI_receiveDataCheck8(res_.instance, &discard))
593 {
594 --remaining;
595 }
596
597 return (remaining > 0U);
598 };
599
600 auto complete_dma_ok = [this]()
601 {
602 if (read_buff_.size_ > 0)
603 {
604 RawData rx = GetRxBuffer();
605 auto* rx_bytes = static_cast<uint8_t*>(rx.addr_);
606 if (mem_read_)
607 {
608 Memory::FastCopy(read_buff_.addr_, rx_bytes + 1, read_buff_.size_);
609 }
610 else
611 {
612 Memory::FastCopy(read_buff_.addr_, rx_bytes, read_buff_.size_);
613 }
614 read_buff_.size_ = 0;
615 }
616
617 SwitchBuffer();
618 busy_ = false;
619 dma_mode_ = DmaMode::DUPLEX;
620 dma_result_ = ErrorCode::OK;
621 rw_op_.UpdateStatus(true, dma_result_);
622 };
623
624 switch (DL_SPI_getPendingInterrupt(res_.instance))
625 {
626 case DL_SPI_IIDX_DMA_DONE_RX:
627 {
628 if (dma_mode_ == DmaMode::TX_ONLY)
629 {
630 break;
631 }
632
633 if (dma_mode_ == DmaMode::RX_ONLY && rx_only_remaining_ > 0U)
634 {
635 const uint32_t NEXT_CHUNK = min(rx_only_remaining_, RX_ONLY_REPEAT_TX_MAX_FRAMES);
636 const uint32_t NEXT_OFFSET = rx_only_offset_;
637 rx_only_offset_ += NEXT_CHUNK;
638 rx_only_remaining_ -= NEXT_CHUNK;
639 StartDmaRxOnly(NEXT_OFFSET, NEXT_CHUNK);
640 break;
641 }
642
643 StopDma();
644 complete_dma_ok();
645 break;
646 }
647
648 case DL_SPI_IIDX_DMA_DONE_TX:
649 if (dma_mode_ == DmaMode::TX_ONLY)
650 {
651 StopDma();
652 const bool DRAIN_DONE = drain_rx_fifo();
653 DL_SPI_clearInterruptStatus(
654 res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW | DL_SPI_INTERRUPT_RX_TIMEOUT);
655
656 if (!DRAIN_DONE)
657 {
658 busy_ = false;
659 dma_mode_ = DmaMode::DUPLEX;
660 dma_result_ = ErrorCode::FAILED;
661 rw_op_.UpdateStatus(true, dma_result_);
662 break;
663 }
664
665 complete_dma_ok();
666 }
667 break;
668
669 case DL_SPI_IIDX_TX_UNDERFLOW:
670 case DL_SPI_IIDX_PARITY_ERROR:
671 StopDma();
672 busy_ = false;
673 dma_mode_ = DmaMode::DUPLEX;
674 dma_result_ = ErrorCode::FAILED;
675 rw_op_.UpdateStatus(true, dma_result_);
676 break;
677
678 case DL_SPI_IIDX_RX_OVERFLOW:
679 if (dma_mode_ == DmaMode::TX_ONLY)
680 {
681 (void)drain_rx_fifo();
682 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW);
683 break;
684 }
685
686 StopDma();
687 busy_ = false;
688 dma_mode_ = DmaMode::DUPLEX;
689 dma_result_ = ErrorCode::FAILED;
690 rw_op_.UpdateStatus(true, dma_result_);
691 break;
692
693 case DL_SPI_IIDX_RX_TIMEOUT:
694 if (dma_mode_ == DmaMode::TX_ONLY)
695 {
696 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_TIMEOUT);
697 break;
698 }
699
700 StopDma();
701 busy_ = false;
702 dma_mode_ = DmaMode::DUPLEX;
703 dma_result_ = ErrorCode::TIMEOUT;
704 rw_op_.UpdateStatus(true, dma_result_);
705 break;
706
707 default:
708 break;
709 }
710}
711
712#if defined(SPI0_BASE)
713extern "C" void SPI0_IRQHandler(void) // NOLINT
714{
715 LibXR::MSPM0SPI::OnInterrupt(0);
716}
717#endif
718
719#if defined(SPI1_BASE)
720extern "C" void SPI1_IRQHandler(void) // NOLINT
721{
722 LibXR::MSPM0SPI::OnInterrupt(1);
723}
724#endif
725
726#if defined(SPI2_BASE)
727extern "C" void SPI2_IRQHandler(void) // NOLINT
728{
729 LibXR::MSPM0SPI::OnInterrupt(2);
730}
731#endif
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
uint32_t GetMaxBusSpeed() const override
获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.
Definition mspm0_spi.cpp:76
ErrorCode Transfer(size_t size, OperationRW &op, bool in_isr=false) override
进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).
ErrorCode SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
Definition mspm0_spi.cpp:43
Prescaler GetMaxPrescaler() const override
获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.
Definition mspm0_spi.cpp:78
ErrorCode MemWrite(uint16_t reg, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
向 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
ErrorCode ReadAndWrite(RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
进行 SPI 读写操作。Performs SPI read and write operations.
ErrorCode MemRead(uint16_t reg, RawData read_data, OperationRW &op, bool in_isr=false) override
从 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
OperationType type
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
串行外设接口(SPI)抽象类。Abstract class for Serial Peripheral Interface (SPI).
Definition spi.hpp:14
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
@ DIV_512
分频系数为 512。Division factor is 512.
RawData GetRxBuffer()
获取接收数据的缓冲区。Gets the buffer for storing received data.
Definition spi.hpp:306
static constexpr uint32_t PrescalerToDiv(Prescaler prescaler)
将分频系数转换为除数。Converts a prescaler to a divisor.
Definition spi.hpp:70
WriteOperation OperationRW
定义读写操作类型的别名。Defines an alias for the read/write operation type.
Definition spi.hpp:63
void SwitchBuffer()
切换缓冲区。Switches the buffer.
Definition spi.hpp:337
RawData GetTxBuffer()
获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
Definition spi.hpp:322
@ LOW
时钟空闲时为低电平。Clock idle low.
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
Definition spi.hpp:396
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ TIMEOUT
超时 | Timeout
@ SIZE_ERR
尺寸错误 | Size error
@ BUSY
忙碌 | Busy
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ PENDING
等待中 | Pending
@ OK
操作成功 | Operation successful
constexpr auto min(LeftType a, RightType b) -> std::common_type_t< LeftType, RightType >
计算两个数的最小值
constexpr auto max(LeftType a, RightType b) -> std::common_type_t< LeftType, RightType >
计算两个数的最大值
存储 SPI 配置参数的结构体。Structure for storing SPI configuration parameters.
Definition spi.hpp:85
ClockPhase clock_phase
SPI 时钟相位。SPI clock phase.
Definition spi.hpp:88
Prescaler prescaler
SPI 分频系数。SPI prescaler.
Definition spi.hpp:89
ClockPolarity clock_polarity
SPI 时钟极性。SPI clock polarity.
Definition spi.hpp:86