1#include "mspm0_spi.hpp"
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;
17MSPM0SPI* MSPM0SPI::instance_map_[MAX_SPI_INSTANCES] = {
nullptr};
19MSPM0SPI::MSPM0SPI(Resources res,
RawData dma_rx_buffer,
RawData dma_tx_buffer,
21 :
SPI(dma_rx_buffer, dma_tx_buffer),
23 dma_enable_min_size_(dma_enable_min_size)
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);
34 instance_map_[res_.index] =
this;
36 NVIC_ClearPendingIRQ(res_.irqn);
37 NVIC_EnableIRQ(res_.irqn);
39 const ErrorCode SET_CFG_ANS = SetConfig(config);
40 ASSERT(SET_CFG_ANS == ErrorCode::OK);
45 DL_SPI_FRAME_FORMAT frame_format = DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA0;
49 ? DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA0
50 : DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA1;
55 ? DL_SPI_FRAME_FORMAT_MOTO4_POL1_PHA0
56 : DL_SPI_FRAME_FORMAT_MOTO4_POL1_PHA1;
60 if (DIV < 2 || DIV > 512 || (DIV & 0x1) != 0)
65 const uint32_t SCR = (DIV >> 1) - 1;
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);
80ErrorCode MSPM0SPI::PollingTransfer(uint8_t* rx,
const uint8_t* tx, uint32_t len)
82 constexpr uint32_t POLLING_TIMEOUT_US = 20000U;
83 constexpr uint32_t POLLING_FALLBACK_SPIN_BUDGET = 1000000U;
91 const uint64_t START_US =
94 uint32_t spin_budget = POLLING_FALLBACK_SPIN_BUDGET;
95 auto polling_timed_out = [&]() ->
bool
100 return (NOW_US - START_US) >= POLLING_TIMEOUT_US;
104 if (spin_budget == 0U)
112 for (uint32_t i = 0; i < len; ++i)
114 while (DL_SPI_isTXFIFOFull(res_.instance))
116 if (polling_timed_out())
121 const uint8_t TX_BYTE = (tx ==
nullptr) ? 0 : tx[i];
122 DL_SPI_transmitData8(res_.instance, TX_BYTE);
125 while (!DL_SPI_receiveDataCheck8(res_.instance, &rx_byte))
127 if (polling_timed_out())
139 while (DL_SPI_isBusy(res_.instance))
141 if (polling_timed_out())
150bool MSPM0SPI::DmaBusy()
const
157 return DL_DMA_isChannelEnabled(DMA, res_.dma_rx_channel) ||
158 DL_DMA_isChannelEnabled(DMA, res_.dma_tx_channel);
161void MSPM0SPI::StartDmaDuplex(uint32_t count)
163 masked_interrupts_for_tx_only_ = 0;
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);
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);
178 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
179 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
182void MSPM0SPI::StartDmaRxOnly(uint32_t offset, uint32_t count)
186 ASSERT(offset < rx.
size_);
188 ASSERT(count <= RX_ONLY_REPEAT_TX_MAX_FRAMES);
189 ASSERT((offset + count) <= rx.
size_);
191 masked_interrupts_for_tx_only_ = 0;
193 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
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);
207 DL_SPI_setRepeatTransmit(res_.instance,
static_cast<uint8_t
>(count - 1U));
208 DL_SPI_transmitData8(res_.instance, 0U);
211void MSPM0SPI::StartDmaTxOnly(uint32_t count)
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;
217 masked_interrupts_for_tx_only_ =
218 DL_SPI_getEnabledInterrupts(res_.instance, TX_ONLY_MASKED_INTERRUPTS);
219 if (masked_interrupts_for_tx_only_ != 0U)
221 DL_SPI_disableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
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);
234void MSPM0SPI::StopDma()
236 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
237 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
239 if (dma_mode_ == DmaMode::RX_ONLY)
241 DL_SPI_setRepeatTransmit(res_.instance, 0U);
244 rx_only_offset_ = 0U;
245 rx_only_remaining_ = 0U;
247 if (masked_interrupts_for_tx_only_ != 0U)
249 DL_SPI_enableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
250 masked_interrupts_for_tx_only_ = 0U;
254ErrorCode MSPM0SPI::CompleteDmaOperation(OperationRW& op,
bool in_isr)
257 if (op.type != OperationRW::OperationType::BLOCK)
263 const ErrorCode WAIT_ANS = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
266 const bool IRQ_WAS_ENABLED = (NVIC_GetEnableIRQ(res_.irqn) != 0U);
269 NVIC_DisableIRQ(res_.irqn);
273 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
274 NVIC_ClearPendingIRQ(res_.irqn);
277 dma_mode_ = DmaMode::DUPLEX;
288 NVIC_EnableIRQ(res_.irqn);
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);
309 if (op.
type != OperationRW::OperationType::BLOCK)
328 if (!IS_READ_ONLY && tx.
size_ < NEED)
333 ASSERT(rx.
size_ >= NEED);
336 ASSERT(tx.
size_ >= NEED);
339 uint8_t* tx_bytes =
nullptr;
342 tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
343 if (write_data.
size_ > 0)
347 if (write_data.
size_ < NEED)
353 if (NEED > dma_enable_min_size_)
355 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
356 NVIC_ClearPendingIRQ(res_.irqn);
359 read_buff_ = read_data;
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);
374 dma_mode_ = DmaMode::DUPLEX;
375 StartDmaDuplex(NEED);
377 return CompleteDmaOperation(op, in_isr);
380 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, NEED);
389 if (op.
type != OperationRW::OperationType::BLOCK)
401 if (op.
type != OperationRW::OperationType::BLOCK)
416 ASSERT(rx.
size_ >= size);
417 ASSERT(tx.
size_ >= size);
419 if (size > dma_enable_min_size_)
421 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
422 NVIC_ClearPendingIRQ(res_.irqn);
425 dma_mode_ = DmaMode::DUPLEX;
426 read_buff_ = {
nullptr, 0};
431 StartDmaDuplex(
static_cast<uint32_t
>(size));
432 return CompleteDmaOperation(op, in_isr);
436 PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_),
437 static_cast<const uint8_t*
>(tx.
addr_),
static_cast<uint32_t
>(size));
441 if (op.
type != OperationRW::OperationType::BLOCK)
451 const uint32_t NEED_READ =
static_cast<uint32_t
>(read_data.
size_);
454 if (op.
type != OperationRW::OperationType::BLOCK)
469 ASSERT(rx.
size_ >= (NEED_READ + 1));
470 ASSERT(tx.
size_ >= (NEED_READ + 1));
472 auto* tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
473 tx_bytes[0] =
static_cast<uint8_t
>(reg | 0x80);
476 const uint32_t TOTAL = NEED_READ + 1;
478 if (TOTAL > dma_enable_min_size_)
480 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
481 NVIC_ClearPendingIRQ(res_.irqn);
484 dma_mode_ = DmaMode::DUPLEX;
485 read_buff_ = read_data;
490 StartDmaDuplex(TOTAL);
491 return CompleteDmaOperation(op, in_isr);
494 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, TOTAL);
498 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
504 if (op.
type != OperationRW::OperationType::BLOCK)
515 const uint32_t NEED_WRITE =
static_cast<uint32_t
>(write_data.
size_);
518 if (op.
type != OperationRW::OperationType::BLOCK)
531 ASSERT(tx.
size_ >= (NEED_WRITE + 1));
533 auto* tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
534 tx_bytes[0] =
static_cast<uint8_t
>(reg & 0x7F);
537 const uint32_t TOTAL = NEED_WRITE + 1;
539 if (TOTAL > dma_enable_min_size_)
541 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
542 NVIC_ClearPendingIRQ(res_.irqn);
545 dma_mode_ = DmaMode::TX_ONLY;
546 read_buff_ = {
nullptr, 0};
551 StartDmaTxOnly(TOTAL);
552 return CompleteDmaOperation(op, in_isr);
556 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, TOTAL);
560 if (op.
type != OperationRW::OperationType::BLOCK)
568void MSPM0SPI::OnInterrupt(uint8_t index)
570 if (index >= MAX_SPI_INSTANCES)
575 MSPM0SPI* spi = instance_map_[index];
581 spi->HandleInterrupt();
584void MSPM0SPI::HandleInterrupt()
588 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
592 auto drain_rx_fifo = [
this]() ->
bool
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))
602 return (remaining > 0U);
605 auto complete_dma_ok = [
this]()
607 if (read_buff_.
size_ > 0)
610 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
619 read_buff_.
size_ = 0;
624 dma_mode_ = DmaMode::DUPLEX;
629 switch (DL_SPI_getPendingInterrupt(res_.instance))
631 case DL_SPI_IIDX_DMA_DONE_RX:
633 if (dma_mode_ == DmaMode::TX_ONLY)
638 if (dma_mode_ == DmaMode::RX_ONLY && rx_only_remaining_ > 0U)
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);
653 case DL_SPI_IIDX_DMA_DONE_TX:
654 if (dma_mode_ == DmaMode::TX_ONLY)
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);
664 dma_mode_ = DmaMode::DUPLEX;
674 case DL_SPI_IIDX_TX_UNDERFLOW:
675 case DL_SPI_IIDX_PARITY_ERROR:
678 dma_mode_ = DmaMode::DUPLEX;
683 case DL_SPI_IIDX_RX_OVERFLOW:
684 if (dma_mode_ == DmaMode::TX_ONLY)
686 (void)drain_rx_fifo();
687 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW);
693 dma_mode_ = DmaMode::DUPLEX;
698 case DL_SPI_IIDX_RX_TIMEOUT:
699 if (dma_mode_ == DmaMode::TX_ONLY)
701 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_TIMEOUT);
707 dma_mode_ = DmaMode::DUPLEX;
717#if defined(SPI0_BASE)
718extern "C" void SPI0_IRQHandler(
void)
720 LibXR::MSPM0SPI::OnInterrupt(0);
724#if defined(SPI1_BASE)
725extern "C" void SPI1_IRQHandler(
void)
727 LibXR::MSPM0SPI::OnInterrupt(1);
常量原始数据封装类。 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.
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.
Prescaler GetMaxPrescaler() const override
获取 SPI 设备的最大分频系数。Gets the maximum prescaler 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.
ErrorCode ReadAndWrite(RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
进行 SPI 读写操作。Performs SPI read and write operations.
ErrorCode MemRead(uint16_t reg, RawData read_data, OperationRW &op, bool in_isr=false) override
从 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
原始数据封装类。 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).
@ 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.
static constexpr uint32_t PrescalerToDiv(Prescaler prescaler)
将分频系数转换为除数。Converts a prescaler to a divisor.
WriteOperation OperationRW
定义读写操作类型的别名。Defines an alias for the read/write operation type.
void SwitchBuffer()
切换缓冲区。Switches the buffer.
RawData GetTxBuffer()
获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
@ LOW
时钟空闲时为低电平。Clock idle low.
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
static Timebase * timebase
静态指针,用于存储全局时间基对象。 Static pointer storing the global timebase instance.
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
@ SIZE_ERR
尺寸错误 | Size error
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ 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.
ClockPhase clock_phase
SPI 时钟相位。SPI clock phase.
Prescaler prescaler
SPI 分频系数。SPI prescaler.
ClockPolarity clock_polarity
SPI 时钟极性。SPI clock polarity.