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 = 1
 
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 12 of file mspm0_spi.hpp.

Member Enumeration Documentation

◆ DmaMode

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

Definition at line 71 of file mspm0_spi.hpp.

72 {
73 DUPLEX,
74 RX_ONLY,
75 TX_ONLY
76 };

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_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
SPI(RawData rx_buffer, RawData tx_buffer)
构造函数。Constructor.
Definition spi.hpp:110
ErrorCode
定义错误码枚举
@ OK
操作成功 | Operation successful

Member Function Documentation

◆ CompleteDmaOperation()

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

Definition at line 249 of file mspm0_spi.cpp.

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}
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 145 of file mspm0_spi.cpp.

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}

◆ 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 579 of file mspm0_spi.cpp.

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}
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.
可写原始数据视图 / Mutable raw data view
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(LeftType a, RightType b) -> std::common_type_t< LeftType, RightType >
计算两个数的最小值

◆ 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 444 of file mspm0_spi.cpp.

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}
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 507 of file mspm0_spi.cpp.

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}
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address

◆ OnInterrupt()

void MSPM0SPI::OnInterrupt ( uint8_t index)
static

Definition at line 563 of file mspm0_spi.cpp.

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}

◆ 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 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}
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.

◆ 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 296 of file mspm0_spi.cpp.

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

◆ ResolveIndex()

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

Definition at line 49 of file mspm0_spi.hpp.

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

◆ 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 156 of file mspm0_spi.cpp.

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}

◆ StartDmaRxOnly()

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

Definition at line 177 of file mspm0_spi.cpp.

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}

◆ StartDmaTxOnly()

void MSPM0SPI::StartDmaTxOnly ( uint32_t count)
private

Definition at line 206 of file mspm0_spi.cpp.

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}

◆ StopDma()

void MSPM0SPI::StopDma ( )
private

Definition at line 229 of file mspm0_spi.cpp.

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}

◆ 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 392 of file mspm0_spi.cpp.

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}

Field Documentation

◆ busy_

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

Definition at line 114 of file mspm0_spi.hpp.

◆ dma_enable_min_size_

uint32_t LibXR::MSPM0SPI::dma_enable_min_size_
private

Definition at line 105 of file mspm0_spi.hpp.

◆ dma_mode_

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

Definition at line 110 of file mspm0_spi.hpp.

◆ dma_result_

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

Definition at line 107 of file mspm0_spi.hpp.

◆ instance_map_

MSPM0SPI * MSPM0SPI::instance_map_ = {nullptr}
staticprivate

Definition at line 116 of file mspm0_spi.hpp.

◆ INVALID_INSTANCE_INDEX

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

Definition at line 85 of file mspm0_spi.hpp.

◆ masked_interrupts_for_tx_only_

uint32_t LibXR::MSPM0SPI::masked_interrupts_for_tx_only_ = 0
private

Definition at line 111 of file mspm0_spi.hpp.

◆ MAX_SPI_INSTANCES

uint8_t LibXR::MSPM0SPI::MAX_SPI_INSTANCES = 1
staticconstexprprivate

Definition at line 83 of file mspm0_spi.hpp.

◆ mem_read_

bool LibXR::MSPM0SPI::mem_read_ = false
private

Definition at line 109 of file mspm0_spi.hpp.

◆ read_buff_

RawData LibXR::MSPM0SPI::read_buff_
private

Definition at line 108 of file mspm0_spi.hpp.

◆ res_

Resources LibXR::MSPM0SPI::res_
private

Definition at line 104 of file mspm0_spi.hpp.

◆ rw_op_

OperationRW LibXR::MSPM0SPI::rw_op_
private

Definition at line 106 of file mspm0_spi.hpp.

◆ rx_only_offset_

uint32_t LibXR::MSPM0SPI::rx_only_offset_ = 0
private

Definition at line 112 of file mspm0_spi.hpp.

◆ rx_only_remaining_

uint32_t LibXR::MSPM0SPI::rx_only_remaining_ = 0
private

Definition at line 113 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 86 of file mspm0_spi.hpp.


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