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