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 bool HAS_TIMEBASE = (Timebase::timebase != nullptr);
91 const uint64_t START_US =
92 HAS_TIMEBASE ? static_cast<uint64_t>(Timebase::GetMicroseconds()) : 0ULL;
93
94 uint32_t spin_budget = POLLING_FALLBACK_SPIN_BUDGET;
95 auto polling_timed_out = [&]() -> bool
96 {
97 if (HAS_TIMEBASE)
98 {
99 const uint64_t NOW_US = static_cast<uint64_t>(Timebase::GetMicroseconds());
100 return (NOW_US - START_US) >= POLLING_TIMEOUT_US;
101 }
102 // timebase 未就绪时的最后兜底策略 / Last-resort fallback when timebase is
103 // not ready yet.
104 if (spin_budget == 0U)
105 {
106 return true;
107 }
108 --spin_budget;
109 return false;
110 };
111
112 for (uint32_t i = 0; i < len; ++i)
113 {
114 while (DL_SPI_isTXFIFOFull(res_.instance))
115 {
116 if (polling_timed_out())
117 {
118 return ErrorCode::TIMEOUT;
119 }
120 }
121 const uint8_t TX_BYTE = (tx == nullptr) ? 0 : tx[i];
122 DL_SPI_transmitData8(res_.instance, TX_BYTE);
123
124 uint8_t rx_byte = 0;
125 while (!DL_SPI_receiveDataCheck8(res_.instance, &rx_byte))
126 {
127 if (polling_timed_out())
128 {
129 return ErrorCode::TIMEOUT;
130 }
131 }
132
133 if (rx != nullptr)
134 {
135 rx[i] = rx_byte;
136 }
137 }
138
139 while (DL_SPI_isBusy(res_.instance))
140 {
141 if (polling_timed_out())
142 {
143 return ErrorCode::TIMEOUT;
144 }
145 }
146
147 return ErrorCode::OK;
148}
149
150bool MSPM0SPI::DmaBusy() const
151{
152 if (busy_)
153 {
154 return true;
155 }
156
157 return DL_DMA_isChannelEnabled(DMA, res_.dma_rx_channel) ||
158 DL_DMA_isChannelEnabled(DMA, res_.dma_tx_channel);
159}
160
161void MSPM0SPI::StartDmaDuplex(uint32_t count)
162{
163 masked_interrupts_for_tx_only_ = 0;
164
165 RawData rx = GetRxBuffer();
166 RawData tx = GetTxBuffer();
167
168 DL_DMA_setSrcAddr(DMA, res_.dma_rx_channel,
169 reinterpret_cast<uint32_t>(&res_.instance->RXDATA));
170 DL_DMA_setDestAddr(DMA, res_.dma_rx_channel, reinterpret_cast<uint32_t>(rx.addr_));
171 DL_DMA_setTransferSize(DMA, res_.dma_rx_channel, count);
172
173 DL_DMA_setSrcAddr(DMA, res_.dma_tx_channel, reinterpret_cast<uint32_t>(tx.addr_));
174 DL_DMA_setDestAddr(DMA, res_.dma_tx_channel,
175 reinterpret_cast<uint32_t>(&res_.instance->TXDATA));
176 DL_DMA_setTransferSize(DMA, res_.dma_tx_channel, count);
177
178 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
179 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
180}
181
182void MSPM0SPI::StartDmaRxOnly(uint32_t offset, uint32_t count)
183{
184 RawData rx = GetRxBuffer();
185
186 ASSERT(offset < rx.size_);
187 ASSERT(count > 0U);
188 ASSERT(count <= RX_ONLY_REPEAT_TX_MAX_FRAMES);
189 ASSERT((offset + count) <= rx.size_);
190
191 masked_interrupts_for_tx_only_ = 0;
192
193 auto* rx_bytes = static_cast<uint8_t*>(rx.addr_);
194
195 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
196 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
197 DL_DMA_setSrcAddr(DMA, res_.dma_rx_channel,
198 reinterpret_cast<uint32_t>(&res_.instance->RXDATA));
199 DL_DMA_setDestAddr(DMA, res_.dma_rx_channel,
200 reinterpret_cast<uint32_t>(rx_bytes + offset));
201 DL_DMA_setTransferSize(DMA, res_.dma_rx_channel, count);
202 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
203
204 // RX-only DMA 仍需要主机时钟,使用硬件重复 dummy TX 提供时钟 / RX-only DMA
205 // still needs controller clocks; use repeated dummy TX in hardware so read-only
206 // transfers can avoid occupying the TX DMA channel.
207 DL_SPI_setRepeatTransmit(res_.instance, static_cast<uint8_t>(count - 1U));
208 DL_SPI_transmitData8(res_.instance, 0U);
209}
210
211void MSPM0SPI::StartDmaTxOnly(uint32_t count)
212{
213 constexpr uint32_t TX_ONLY_MASKED_INTERRUPTS = DL_SPI_INTERRUPT_DMA_DONE_RX |
214 DL_SPI_INTERRUPT_RX_OVERFLOW |
215 DL_SPI_INTERRUPT_RX_TIMEOUT;
216
217 masked_interrupts_for_tx_only_ =
218 DL_SPI_getEnabledInterrupts(res_.instance, TX_ONLY_MASKED_INTERRUPTS);
219 if (masked_interrupts_for_tx_only_ != 0U)
220 {
221 DL_SPI_disableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
222 }
223
224 RawData tx = GetTxBuffer();
225
226 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
227 DL_DMA_setSrcAddr(DMA, res_.dma_tx_channel, reinterpret_cast<uint32_t>(tx.addr_));
228 DL_DMA_setDestAddr(DMA, res_.dma_tx_channel,
229 reinterpret_cast<uint32_t>(&res_.instance->TXDATA));
230 DL_DMA_setTransferSize(DMA, res_.dma_tx_channel, count);
231 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
232}
233
234void MSPM0SPI::StopDma()
235{
236 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
237 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
238
239 if (dma_mode_ == DmaMode::RX_ONLY)
240 {
241 DL_SPI_setRepeatTransmit(res_.instance, 0U);
242 }
243
244 rx_only_offset_ = 0U;
245 rx_only_remaining_ = 0U;
246
247 if (masked_interrupts_for_tx_only_ != 0U)
248 {
249 DL_SPI_enableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
250 masked_interrupts_for_tx_only_ = 0U;
251 }
252}
253
254ErrorCode MSPM0SPI::CompleteDmaOperation(OperationRW& op, bool in_isr)
255{
256 op.MarkAsRunning();
257 if (op.type != OperationRW::OperationType::BLOCK)
258 {
259 return ErrorCode::OK;
260 }
261
262 ASSERT(!in_isr);
263 const ErrorCode WAIT_ANS = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
264 if (WAIT_ANS == ErrorCode::TIMEOUT)
265 {
266 const bool IRQ_WAS_ENABLED = (NVIC_GetEnableIRQ(res_.irqn) != 0U);
267 if (IRQ_WAS_ENABLED)
268 {
269 NVIC_DisableIRQ(res_.irqn);
270 }
271
272 StopDma();
273 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
274 NVIC_ClearPendingIRQ(res_.irqn);
275
276 busy_ = false;
277 dma_mode_ = DmaMode::DUPLEX;
278 dma_result_ = ErrorCode::TIMEOUT;
279 rw_op_ = OperationRW();
280 // Drain any timeout-race semaphore credits posted right before IRQ disable,
281 // so the next BLOCK transfer cannot consume a stale completion signal.
282 while (op.data.sem_info.sem->Wait(0U) == ErrorCode::OK)
283 {
284 }
285
286 if (IRQ_WAS_ENABLED)
287 {
288 NVIC_EnableIRQ(res_.irqn);
289 }
290 return ErrorCode::TIMEOUT;
291 }
292
293 if (WAIT_ANS != ErrorCode::OK)
294 {
295 return WAIT_ANS;
296 }
297
298 return dma_result_;
299}
300
302 OperationRW& op, bool in_isr)
303{
304 const uint32_t NEED = static_cast<uint32_t>(max(read_data.size_, write_data.size_));
305 const bool IS_READ_ONLY = (write_data.size_ == 0U) && (read_data.size_ > 0U);
306
307 if (NEED == 0)
308 {
309 if (op.type != OperationRW::OperationType::BLOCK)
310 {
311 op.UpdateStatus(in_isr, ErrorCode::OK);
312 }
313 return ErrorCode::OK;
314 }
315
316 if (DmaBusy())
317 {
318 return ErrorCode::BUSY;
319 }
320
321 RawData rx = GetRxBuffer();
322 RawData tx = GetTxBuffer();
323
324 if (rx.size_ < NEED)
325 {
326 return ErrorCode::SIZE_ERR;
327 }
328 if (!IS_READ_ONLY && tx.size_ < NEED)
329 {
330 return ErrorCode::SIZE_ERR;
331 }
332
333 ASSERT(rx.size_ >= NEED);
334 if (!IS_READ_ONLY)
335 {
336 ASSERT(tx.size_ >= NEED);
337 }
338
339 uint8_t* tx_bytes = nullptr;
340 if (!IS_READ_ONLY)
341 {
342 tx_bytes = static_cast<uint8_t*>(tx.addr_);
343 if (write_data.size_ > 0)
344 {
345 Memory::FastCopy(tx_bytes, write_data.addr_, write_data.size_);
346 }
347 if (write_data.size_ < NEED)
348 {
349 Memory::FastSet(tx_bytes + write_data.size_, 0, NEED - write_data.size_);
350 }
351 }
352
353 if (NEED > dma_enable_min_size_)
354 {
355 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
356 NVIC_ClearPendingIRQ(res_.irqn);
357
358 mem_read_ = false;
359 read_buff_ = read_data;
360 rw_op_ = op;
361 dma_result_ = ErrorCode::PENDING;
362 busy_ = true;
363
364 if (IS_READ_ONLY)
365 {
366 dma_mode_ = DmaMode::RX_ONLY;
367 const uint32_t FIRST_CHUNK = min(NEED, RX_ONLY_REPEAT_TX_MAX_FRAMES);
368 rx_only_offset_ = FIRST_CHUNK;
369 rx_only_remaining_ = NEED - FIRST_CHUNK;
370 StartDmaRxOnly(0U, FIRST_CHUNK);
371 }
372 else
373 {
374 dma_mode_ = DmaMode::DUPLEX;
375 StartDmaDuplex(NEED);
376 }
377 return CompleteDmaOperation(op, in_isr);
378 }
379
380 ErrorCode ans = PollingTransfer(static_cast<uint8_t*>(rx.addr_), tx_bytes, NEED);
381
382 if (ans == ErrorCode::OK && read_data.size_ > 0)
383 {
384 Memory::FastCopy(read_data.addr_, rx.addr_, read_data.size_);
385 }
386
387 SwitchBuffer();
388
389 if (op.type != OperationRW::OperationType::BLOCK)
390 {
391 op.UpdateStatus(in_isr, ans);
392 }
393
394 return ans;
395}
396
397ErrorCode MSPM0SPI::Transfer(size_t size, OperationRW& op, bool in_isr)
398{
399 if (size == 0)
400 {
401 if (op.type != OperationRW::OperationType::BLOCK)
402 {
403 op.UpdateStatus(in_isr, ErrorCode::OK);
404 }
405 return ErrorCode::OK;
406 }
407
408 if (DmaBusy())
409 {
410 return ErrorCode::BUSY;
411 }
412
413 RawData rx = GetRxBuffer();
414 RawData tx = GetTxBuffer();
415
416 ASSERT(rx.size_ >= size);
417 ASSERT(tx.size_ >= size);
418
419 if (size > dma_enable_min_size_)
420 {
421 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
422 NVIC_ClearPendingIRQ(res_.irqn);
423
424 mem_read_ = false;
425 dma_mode_ = DmaMode::DUPLEX;
426 read_buff_ = {nullptr, 0};
427 rw_op_ = op;
428 dma_result_ = ErrorCode::PENDING;
429 busy_ = true;
430
431 StartDmaDuplex(static_cast<uint32_t>(size));
432 return CompleteDmaOperation(op, in_isr);
433 }
434
435 ErrorCode ans =
436 PollingTransfer(static_cast<uint8_t*>(rx.addr_),
437 static_cast<const uint8_t*>(tx.addr_), static_cast<uint32_t>(size));
438
439 SwitchBuffer();
440
441 if (op.type != OperationRW::OperationType::BLOCK)
442 {
443 op.UpdateStatus(in_isr, ans);
444 }
445
446 return ans;
447}
448
449ErrorCode MSPM0SPI::MemRead(uint16_t reg, RawData read_data, OperationRW& op, bool in_isr)
450{
451 const uint32_t NEED_READ = static_cast<uint32_t>(read_data.size_);
452 if (NEED_READ == 0)
453 {
454 if (op.type != OperationRW::OperationType::BLOCK)
455 {
456 op.UpdateStatus(in_isr, ErrorCode::OK);
457 }
458 return ErrorCode::OK;
459 }
460
461 if (DmaBusy())
462 {
463 return ErrorCode::BUSY;
464 }
465
466 RawData rx = GetRxBuffer();
467 RawData tx = GetTxBuffer();
468
469 ASSERT(rx.size_ >= (NEED_READ + 1));
470 ASSERT(tx.size_ >= (NEED_READ + 1));
471
472 auto* tx_bytes = static_cast<uint8_t*>(tx.addr_);
473 tx_bytes[0] = static_cast<uint8_t>(reg | 0x80);
474 Memory::FastSet(tx_bytes + 1, 0, NEED_READ);
475
476 const uint32_t TOTAL = NEED_READ + 1;
477
478 if (TOTAL > dma_enable_min_size_)
479 {
480 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
481 NVIC_ClearPendingIRQ(res_.irqn);
482
483 mem_read_ = true;
484 dma_mode_ = DmaMode::DUPLEX;
485 read_buff_ = read_data;
486 rw_op_ = op;
487 dma_result_ = ErrorCode::PENDING;
488 busy_ = true;
489
490 StartDmaDuplex(TOTAL);
491 return CompleteDmaOperation(op, in_isr);
492 }
493
494 ErrorCode ans = PollingTransfer(static_cast<uint8_t*>(rx.addr_), tx_bytes, TOTAL);
495
496 if (ans == ErrorCode::OK)
497 {
498 auto* rx_bytes = static_cast<uint8_t*>(rx.addr_);
499 Memory::FastCopy(read_data.addr_, rx_bytes + 1, NEED_READ);
500 }
501
502 SwitchBuffer();
503
504 if (op.type != OperationRW::OperationType::BLOCK)
505 {
506 op.UpdateStatus(in_isr, ans);
507 }
508
509 return ans;
510}
511
513 bool in_isr)
514{
515 const uint32_t NEED_WRITE = static_cast<uint32_t>(write_data.size_);
516 if (NEED_WRITE == 0)
517 {
518 if (op.type != OperationRW::OperationType::BLOCK)
519 {
520 op.UpdateStatus(in_isr, ErrorCode::OK);
521 }
522 return ErrorCode::OK;
523 }
524
525 if (DmaBusy())
526 {
527 return ErrorCode::BUSY;
528 }
529
530 RawData tx = GetTxBuffer();
531 ASSERT(tx.size_ >= (NEED_WRITE + 1));
532
533 auto* tx_bytes = static_cast<uint8_t*>(tx.addr_);
534 tx_bytes[0] = static_cast<uint8_t>(reg & 0x7F);
535 Memory::FastCopy(tx_bytes + 1, write_data.addr_, NEED_WRITE);
536
537 const uint32_t TOTAL = NEED_WRITE + 1;
538
539 if (TOTAL > dma_enable_min_size_)
540 {
541 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
542 NVIC_ClearPendingIRQ(res_.irqn);
543
544 mem_read_ = false;
545 dma_mode_ = DmaMode::TX_ONLY;
546 read_buff_ = {nullptr, 0};
547 rw_op_ = op;
548 dma_result_ = ErrorCode::PENDING;
549 busy_ = true;
550
551 StartDmaTxOnly(TOTAL);
552 return CompleteDmaOperation(op, in_isr);
553 }
554
555 RawData rx = GetRxBuffer();
556 ErrorCode ans = PollingTransfer(static_cast<uint8_t*>(rx.addr_), tx_bytes, TOTAL);
557
558 SwitchBuffer();
559
560 if (op.type != OperationRW::OperationType::BLOCK)
561 {
562 op.UpdateStatus(in_isr, ans);
563 }
564
565 return ans;
566}
567
568void MSPM0SPI::OnInterrupt(uint8_t index)
569{
570 if (index >= MAX_SPI_INSTANCES)
571 {
572 return;
573 }
574
575 MSPM0SPI* spi = instance_map_[index];
576 if (spi == nullptr)
577 {
578 return;
579 }
580
581 spi->HandleInterrupt();
582}
583
584void MSPM0SPI::HandleInterrupt()
585{
586 if (!busy_)
587 {
588 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
589 return;
590 }
591
592 auto drain_rx_fifo = [this]() -> bool
593 {
594 constexpr uint32_t RX_FIFO_DRAIN_MAX_ITERATIONS = 1024U;
595 uint32_t remaining = RX_FIFO_DRAIN_MAX_ITERATIONS;
596 uint8_t discard = 0U;
597 while (remaining > 0U && DL_SPI_receiveDataCheck8(res_.instance, &discard))
598 {
599 --remaining;
600 }
601
602 return (remaining > 0U);
603 };
604
605 auto complete_dma_ok = [this]()
606 {
607 if (read_buff_.size_ > 0)
608 {
609 RawData rx = GetRxBuffer();
610 auto* rx_bytes = static_cast<uint8_t*>(rx.addr_);
611 if (mem_read_)
612 {
613 Memory::FastCopy(read_buff_.addr_, rx_bytes + 1, read_buff_.size_);
614 }
615 else
616 {
617 Memory::FastCopy(read_buff_.addr_, rx_bytes, read_buff_.size_);
618 }
619 read_buff_.size_ = 0;
620 }
621
622 SwitchBuffer();
623 busy_ = false;
624 dma_mode_ = DmaMode::DUPLEX;
625 dma_result_ = ErrorCode::OK;
626 rw_op_.UpdateStatus(true, dma_result_);
627 };
628
629 switch (DL_SPI_getPendingInterrupt(res_.instance))
630 {
631 case DL_SPI_IIDX_DMA_DONE_RX:
632 {
633 if (dma_mode_ == DmaMode::TX_ONLY)
634 {
635 break;
636 }
637
638 if (dma_mode_ == DmaMode::RX_ONLY && rx_only_remaining_ > 0U)
639 {
640 const uint32_t NEXT_CHUNK = min(rx_only_remaining_, RX_ONLY_REPEAT_TX_MAX_FRAMES);
641 const uint32_t NEXT_OFFSET = rx_only_offset_;
642 rx_only_offset_ += NEXT_CHUNK;
643 rx_only_remaining_ -= NEXT_CHUNK;
644 StartDmaRxOnly(NEXT_OFFSET, NEXT_CHUNK);
645 break;
646 }
647
648 StopDma();
649 complete_dma_ok();
650 break;
651 }
652
653 case DL_SPI_IIDX_DMA_DONE_TX:
654 if (dma_mode_ == DmaMode::TX_ONLY)
655 {
656 StopDma();
657 const bool DRAIN_DONE = drain_rx_fifo();
658 DL_SPI_clearInterruptStatus(
659 res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW | DL_SPI_INTERRUPT_RX_TIMEOUT);
660
661 if (!DRAIN_DONE)
662 {
663 busy_ = false;
664 dma_mode_ = DmaMode::DUPLEX;
665 dma_result_ = ErrorCode::FAILED;
666 rw_op_.UpdateStatus(true, dma_result_);
667 break;
668 }
669
670 complete_dma_ok();
671 }
672 break;
673
674 case DL_SPI_IIDX_TX_UNDERFLOW:
675 case DL_SPI_IIDX_PARITY_ERROR:
676 StopDma();
677 busy_ = false;
678 dma_mode_ = DmaMode::DUPLEX;
679 dma_result_ = ErrorCode::FAILED;
680 rw_op_.UpdateStatus(true, dma_result_);
681 break;
682
683 case DL_SPI_IIDX_RX_OVERFLOW:
684 if (dma_mode_ == DmaMode::TX_ONLY)
685 {
686 (void)drain_rx_fifo();
687 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW);
688 break;
689 }
690
691 StopDma();
692 busy_ = false;
693 dma_mode_ = DmaMode::DUPLEX;
694 dma_result_ = ErrorCode::FAILED;
695 rw_op_.UpdateStatus(true, dma_result_);
696 break;
697
698 case DL_SPI_IIDX_RX_TIMEOUT:
699 if (dma_mode_ == DmaMode::TX_ONLY)
700 {
701 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_TIMEOUT);
702 break;
703 }
704
705 StopDma();
706 busy_ = false;
707 dma_mode_ = DmaMode::DUPLEX;
708 dma_result_ = ErrorCode::TIMEOUT;
709 rw_op_.UpdateStatus(true, dma_result_);
710 break;
711
712 default:
713 break;
714 }
715}
716
717#if defined(SPI0_BASE)
718extern "C" void SPI0_IRQHandler(void) // NOLINT
719{
720 LibXR::MSPM0SPI::OnInterrupt(0);
721}
722#endif
723
724#if defined(SPI1_BASE)
725extern "C" void SPI1_IRQHandler(void) // NOLINT
726{
727 LibXR::MSPM0SPI::OnInterrupt(1);
728}
729#endif
常量原始数据封装类。 A class for encapsulating constant raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).
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
Definition libxr_mem.cpp:5
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:178
OperationType type
Definition libxr_rw.hpp:237
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
串行外设接口(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 Timebase * timebase
静态指针,用于存储全局时间基对象。 Static pointer storing the global timebase instance.
Definition timebase.hpp:119
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
Definition timebase.hpp:49
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