libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::MSPM0SPI Class Reference
Inheritance diagram for LibXR::MSPM0SPI:
[legend]
Collaboration diagram for LibXR::MSPM0SPI:
[legend]

Data Structures

struct  Resources
 

Public Member Functions

 MSPM0SPI (Resources res, RawData dma_rx_buffer, RawData dma_tx_buffer, uint32_t dma_enable_min_size=3, SPI::Configuration config={SPI::ClockPolarity::LOW, SPI::ClockPhase::EDGE_1, SPI::Prescaler::DIV_4, false})
 
ErrorCode ReadAndWrite (RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
 进行 SPI 读写操作。Performs SPI read and write operations.
 
ErrorCode SetConfig (SPI::Configuration config) override
 设置 SPI 配置参数。Sets SPI configuration parameters.
 
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.
 
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.
 
uint32_t GetMaxBusSpeed () const override
 获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.
 
Prescaler GetMaxPrescaler () const override
 获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.
 
ErrorCode Transfer (size_t size, OperationRW &op, bool in_isr=false) override
 进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).
 
- Public Member Functions inherited from LibXR::SPI
 SPI (RawData rx_buffer, RawData tx_buffer)
 构造函数。Constructor.
 
virtual ErrorCode Read (RawData read_data, OperationRW &op, bool in_isr=false)
 进行 SPI 读取操作。Performs SPI read operation.
 
virtual ErrorCode Write (ConstRawData write_data, OperationRW &op, bool in_isr=false)
 进行 SPI 写入操作。Performs SPI write operation.
 
uint32_t GetBusSpeed () const
 获取 SPI 设备的当前总线速度。Gets the current bus speed of the SPI device.
 
Prescaler CalcPrescaler (uint32_t target_max_bus_speed, uint32_t target_min_bus_speed, bool increase)
 计算 SPI 分频系数。Calculates the SPI prescaler.
 
RawData GetRxBuffer ()
 获取接收数据的缓冲区。Gets the buffer for storing received data.
 
RawData GetTxBuffer ()
 获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
 
void SwitchBuffer ()
 切换缓冲区。Switches the buffer.
 
void SetActiveLength (size_t len)
 设置缓冲区的有效数据长度。Sets the length of valid data in the buffer.
 
size_t GetActiveLength () const
 获取缓冲区的有效数据长度。Gets the length of valid data in the buffer.
 
ConfigurationGetConfig ()
 获取 SPI 配置参数。Gets the SPI configuration parameters.
 
bool IsDoubleBuffer () const
 检查是否使用双缓冲区。Checks if double buffering is enabled.
 

Static Public Member Functions

static void OnInterrupt (uint8_t index)
 
static constexpr uint8_t ResolveIndex (IRQn_Type irqn)
 
- Static Public Member Functions inherited from LibXR::SPI
static constexpr uint32_t PrescalerToDiv (Prescaler prescaler)
 将分频系数转换为除数。Converts a prescaler to a divisor.
 

Private Types

enum class  DmaMode : uint8_t { DUPLEX , RX_ONLY , TX_ONLY }
 

Private Member Functions

ErrorCode PollingTransfer (uint8_t *rx, const uint8_t *tx, uint32_t len)
 
ErrorCode CompleteDmaOperation (OperationRW &op, bool in_isr)
 
void StartDmaDuplex (uint32_t count)
 
void StartDmaRxOnly (uint32_t offset, uint32_t count)
 
void StartDmaTxOnly (uint32_t count)
 
void StopDma ()
 
void HandleInterrupt ()
 
bool DmaBusy () const
 

Private Attributes

Resources res_
 
uint32_t dma_enable_min_size_
 
OperationRW rw_op_
 
volatile ErrorCode dma_result_ = ErrorCode::OK
 
RawData read_buff_
 
bool mem_read_ = false
 
DmaMode dma_mode_ = DmaMode::DUPLEX
 
uint32_t masked_interrupts_for_tx_only_ = 0
 
uint32_t rx_only_offset_ = 0
 
uint32_t rx_only_remaining_ = 0
 
volatile bool busy_ = false
 

Static Private Attributes

static constexpr uint8_t MAX_SPI_INSTANCES = 2
 
static constexpr uint8_t INVALID_INSTANCE_INDEX = 0xFF
 
static constexpr uint32_t RX_ONLY_REPEAT_TX_MAX_FRAMES = 256U
 
static MSPM0SPIinstance_map_ [MAX_SPI_INSTANCES] = {nullptr}
 

Additional Inherited Members

- Public Types inherited from LibXR::SPI
enum class  ClockPolarity : uint8_t { LOW = 0 , HIGH = 1 }
 定义 SPI 时钟极性。Defines the SPI clock polarity. More...
 
enum class  ClockPhase : uint8_t { EDGE_1 = 0 , EDGE_2 = 1 }
 定义 SPI 时钟相位。Defines the SPI clock phase. More...
 
enum class  Prescaler : uint8_t {
  DIV_1 = 0 , DIV_2 = 1 , DIV_4 = 2 , DIV_8 = 3 ,
  DIV_16 = 4 , DIV_32 = 5 , DIV_64 = 6 , DIV_128 = 7 ,
  DIV_256 = 8 , DIV_512 = 9 , DIV_1024 = 10 , DIV_2048 = 11 ,
  DIV_4096 = 12 , DIV_8192 = 13 , DIV_16384 = 14 , DIV_32768 = 15 ,
  DIV_65536 = 16 , UNKNOWN = 0xFF
}
 
using OperationRW = WriteOperation
 定义读写操作类型的别名。Defines an alias for the read/write operation type.
 

Detailed Description

Definition at line 11 of file mspm0_spi.hpp.

Member Enumeration Documentation

◆ DmaMode

enum class LibXR::MSPM0SPI::DmaMode : uint8_t
strongprivate

Definition at line 66 of file mspm0_spi.hpp.

67 {
68 DUPLEX,
69 RX_ONLY,
70 TX_ONLY
71 };

Constructor & Destructor Documentation

◆ MSPM0SPI()

MSPM0SPI::MSPM0SPI ( Resources res,
RawData dma_rx_buffer,
RawData dma_tx_buffer,
uint32_t dma_enable_min_size = 3,
SPI::Configuration config = {SPI::ClockPolarity::LOWSPI::ClockPhase::EDGE_1SPI::Prescaler::DIV_4, false} )

Definition at line 19 of file mspm0_spi.cpp.

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}
ErrorCode SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
Definition mspm0_spi.cpp:43
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
SPI(RawData rx_buffer, RawData tx_buffer)
构造函数。Constructor.
Definition spi.hpp:110
ErrorCode
定义错误码枚举
Definition libxr_def.hpp:64
@ OK
操作成功 | Operation successful

Member Function Documentation

◆ CompleteDmaOperation()

ErrorCode MSPM0SPI::CompleteDmaOperation ( OperationRW & op,
bool in_isr )
private

Definition at line 254 of file mspm0_spi.cpp.

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}
WriteOperation OperationRW
定义读写操作类型的别名。Defines an alias for the read/write operation type.
Definition spi.hpp:63
@ TIMEOUT
超时 | Timeout

◆ DmaBusy()

bool MSPM0SPI::DmaBusy ( ) const
private

Definition at line 150 of file mspm0_spi.cpp.

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}

◆ GetMaxBusSpeed()

uint32_t MSPM0SPI::GetMaxBusSpeed ( ) const
overridevirtual

获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.

Returns
SPI 设备的最大时钟速度(单位:Hz)。The maximum clock speed of the SPI device (in Hz).

Implements LibXR::SPI.

Definition at line 76 of file mspm0_spi.cpp.

76{ return res_.clock_freq; }

◆ GetMaxPrescaler()

SPI::Prescaler MSPM0SPI::GetMaxPrescaler ( ) const
overridevirtual

获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.

Returns
SPI 设备的最大分频系数。The maximum prescaler of the SPI device.

Implements LibXR::SPI.

Definition at line 78 of file mspm0_spi.cpp.

@ DIV_512
分频系数为 512。Division factor is 512.

◆ HandleInterrupt()

void MSPM0SPI::HandleInterrupt ( )
private

Definition at line 584 of file mspm0_spi.cpp.

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}
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
原始数据封装类。 A class for encapsulating raw data.
RawData GetRxBuffer()
获取接收数据的缓冲区。Gets the buffer for storing received data.
Definition spi.hpp:306
void SwitchBuffer()
切换缓冲区。Switches the buffer.
Definition spi.hpp:337
@ FAILED
操作失败 | Operation failed
constexpr auto min(T1 a, T2 b) -> typename std::common_type< T1, T2 >::type
计算两个数的最小值

◆ MemRead()

ErrorCode MSPM0SPI::MemRead ( uint16_t reg,
RawData read_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.

Parameters
reg寄存器地址。Register address.
read_data读取的数据缓冲区。Buffer to store read data.
op操作类型(同步/异步)。Operation mode (sync/async).
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 449 of file mspm0_spi.cpp.

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}
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
RawData GetTxBuffer()
获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
Definition spi.hpp:322
@ BUSY
忙碌 | Busy
@ PENDING
等待中 | Pending

◆ MemWrite()

ErrorCode MSPM0SPI::MemWrite ( uint16_t reg,
ConstRawData write_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.

Parameters
reg寄存器地址。Register address.
write_data写入的数据缓冲区。Buffer containing data to write.
op操作类型(同步/异步)。Operation mode (sync/async).
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 512 of file mspm0_spi.cpp.

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}
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).

◆ OnInterrupt()

void MSPM0SPI::OnInterrupt ( uint8_t index)
static

Definition at line 568 of file mspm0_spi.cpp.

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}

◆ PollingTransfer()

ErrorCode MSPM0SPI::PollingTransfer ( uint8_t * rx,
const uint8_t * tx,
uint32_t len )
private

Definition at line 80 of file mspm0_spi.cpp.

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}
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

◆ ReadAndWrite()

ErrorCode MSPM0SPI::ReadAndWrite ( RawData read_data,
ConstRawData write_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

进行 SPI 读写操作。Performs SPI read and write operations.

Parameters
read_data存储读取数据的缓冲区。Buffer to store the read data.
write_data需要写入的数据缓冲区。Buffer containing the data to be written.
op读写操作类型。Type of read/write operation.
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 301 of file mspm0_spi.cpp.

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}
@ SIZE_ERR
尺寸错误 | Size error
constexpr auto max(T1 a, T2 b) -> typename std::common_type< T1, T2 >::type
计算两个数的最大值

◆ ResolveIndex()

static constexpr uint8_t LibXR::MSPM0SPI::ResolveIndex ( IRQn_Type irqn)
inlinestaticconstexpr

Definition at line 48 of file mspm0_spi.hpp.

49 {
50 switch (irqn)
51 {
52#if defined(SPI0_BASE)
53 case SPI0_INT_IRQn:
54 return 0;
55#endif
56#if defined(SPI1_BASE)
57 case SPI1_INT_IRQn:
58 return 1;
59#endif
60 default:
61 return INVALID_INSTANCE_INDEX;
62 }
63 }

◆ SetConfig()

ErrorCode MSPM0SPI::SetConfig ( SPI::Configuration config)
overridevirtual

设置 SPI 配置参数。Sets SPI configuration parameters.

Parameters
config需要应用的 SPI 配置。The SPI configuration to apply.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 43 of file mspm0_spi.cpp.

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}
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
static constexpr uint32_t PrescalerToDiv(Prescaler prescaler)
将分频系数转换为除数。Converts a prescaler to a divisor.
Definition spi.hpp:70
@ LOW
时钟空闲时为低电平。Clock idle low.
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
Definition spi.hpp:396
@ NOT_SUPPORT
不支持 | Not supported
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

◆ StartDmaDuplex()

void MSPM0SPI::StartDmaDuplex ( uint32_t count)
private

Definition at line 161 of file mspm0_spi.cpp.

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}

◆ StartDmaRxOnly()

void MSPM0SPI::StartDmaRxOnly ( uint32_t offset,
uint32_t count )
private

Definition at line 182 of file mspm0_spi.cpp.

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}

◆ StartDmaTxOnly()

void MSPM0SPI::StartDmaTxOnly ( uint32_t count)
private

Definition at line 211 of file mspm0_spi.cpp.

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}

◆ StopDma()

void MSPM0SPI::StopDma ( )
private

Definition at line 234 of file mspm0_spi.cpp.

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}

◆ Transfer()

ErrorCode MSPM0SPI::Transfer ( size_t size,
OperationRW & op,
bool in_isr = false )
overridevirtual

进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).

Parameters
size需要传输的数据大小。The size of the data to be transferred.
op读写操作类型。Type of read/write operation.
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 397 of file mspm0_spi.cpp.

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}

Field Documentation

◆ busy_

volatile bool LibXR::MSPM0SPI::busy_ = false
private

Definition at line 103 of file mspm0_spi.hpp.

◆ dma_enable_min_size_

uint32_t LibXR::MSPM0SPI::dma_enable_min_size_
private

Definition at line 94 of file mspm0_spi.hpp.

◆ dma_mode_

DmaMode LibXR::MSPM0SPI::dma_mode_ = DmaMode::DUPLEX
private

Definition at line 99 of file mspm0_spi.hpp.

◆ dma_result_

volatile ErrorCode LibXR::MSPM0SPI::dma_result_ = ErrorCode::OK
private

Definition at line 96 of file mspm0_spi.hpp.

◆ instance_map_

MSPM0SPI * MSPM0SPI::instance_map_ = {nullptr}
staticprivate

Definition at line 105 of file mspm0_spi.hpp.

◆ INVALID_INSTANCE_INDEX

uint8_t LibXR::MSPM0SPI::INVALID_INSTANCE_INDEX = 0xFF
staticconstexprprivate

Definition at line 74 of file mspm0_spi.hpp.

◆ masked_interrupts_for_tx_only_

uint32_t LibXR::MSPM0SPI::masked_interrupts_for_tx_only_ = 0
private

Definition at line 100 of file mspm0_spi.hpp.

◆ MAX_SPI_INSTANCES

uint8_t LibXR::MSPM0SPI::MAX_SPI_INSTANCES = 2
staticconstexprprivate

Definition at line 73 of file mspm0_spi.hpp.

◆ mem_read_

bool LibXR::MSPM0SPI::mem_read_ = false
private

Definition at line 98 of file mspm0_spi.hpp.

◆ read_buff_

RawData LibXR::MSPM0SPI::read_buff_
private

Definition at line 97 of file mspm0_spi.hpp.

◆ res_

Resources LibXR::MSPM0SPI::res_
private

Definition at line 93 of file mspm0_spi.hpp.

◆ rw_op_

OperationRW LibXR::MSPM0SPI::rw_op_
private

Definition at line 95 of file mspm0_spi.hpp.

◆ rx_only_offset_

uint32_t LibXR::MSPM0SPI::rx_only_offset_ = 0
private

Definition at line 101 of file mspm0_spi.hpp.

◆ rx_only_remaining_

uint32_t LibXR::MSPM0SPI::rx_only_remaining_ = 0
private

Definition at line 102 of file mspm0_spi.hpp.

◆ RX_ONLY_REPEAT_TX_MAX_FRAMES

uint32_t LibXR::MSPM0SPI::RX_ONLY_REPEAT_TX_MAX_FRAMES = 256U
staticconstexprprivate

Definition at line 75 of file mspm0_spi.hpp.


The documentation for this class was generated from the following files: