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;
92 uint32_t spin_budget = POLLING_FALLBACK_SPIN_BUDGET;
93 auto polling_timed_out = [&]() ->
bool
96 if ((NOW_US - START_US) >= POLLING_TIMEOUT_US)
100 if (spin_budget > 0U)
107 for (uint32_t i = 0; i < len; ++i)
109 while (DL_SPI_isTXFIFOFull(res_.instance))
111 if (polling_timed_out())
116 const uint8_t TX_BYTE = (tx ==
nullptr) ? 0 : tx[i];
117 DL_SPI_transmitData8(res_.instance, TX_BYTE);
120 while (!DL_SPI_receiveDataCheck8(res_.instance, &rx_byte))
122 if (polling_timed_out())
134 while (DL_SPI_isBusy(res_.instance))
136 if (polling_timed_out())
145bool MSPM0SPI::DmaBusy()
const
152 return DL_DMA_isChannelEnabled(DMA, res_.dma_rx_channel) ||
153 DL_DMA_isChannelEnabled(DMA, res_.dma_tx_channel);
156void MSPM0SPI::StartDmaDuplex(uint32_t count)
158 masked_interrupts_for_tx_only_ = 0;
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);
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);
173 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
174 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
177void MSPM0SPI::StartDmaRxOnly(uint32_t offset, uint32_t count)
181 ASSERT(offset < rx.
size_);
183 ASSERT(count <= RX_ONLY_REPEAT_TX_MAX_FRAMES);
184 ASSERT((offset + count) <= rx.
size_);
186 masked_interrupts_for_tx_only_ = 0;
188 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
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);
202 DL_SPI_setRepeatTransmit(res_.instance,
static_cast<uint8_t
>(count - 1U));
203 DL_SPI_transmitData8(res_.instance, 0U);
206void MSPM0SPI::StartDmaTxOnly(uint32_t count)
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;
212 masked_interrupts_for_tx_only_ =
213 DL_SPI_getEnabledInterrupts(res_.instance, TX_ONLY_MASKED_INTERRUPTS);
214 if (masked_interrupts_for_tx_only_ != 0U)
216 DL_SPI_disableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
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);
229void MSPM0SPI::StopDma()
231 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
232 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
234 if (dma_mode_ == DmaMode::RX_ONLY)
236 DL_SPI_setRepeatTransmit(res_.instance, 0U);
239 rx_only_offset_ = 0U;
240 rx_only_remaining_ = 0U;
242 if (masked_interrupts_for_tx_only_ != 0U)
244 DL_SPI_enableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
245 masked_interrupts_for_tx_only_ = 0U;
249ErrorCode MSPM0SPI::CompleteDmaOperation(OperationRW& op,
bool in_isr)
252 if (op.type != OperationRW::OperationType::BLOCK)
258 const ErrorCode WAIT_ANS = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
261 const bool IRQ_WAS_ENABLED = (NVIC_GetEnableIRQ(res_.irqn) != 0U);
264 NVIC_DisableIRQ(res_.irqn);
268 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
269 NVIC_ClearPendingIRQ(res_.irqn);
272 dma_mode_ = DmaMode::DUPLEX;
283 NVIC_EnableIRQ(res_.irqn);
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);
304 if (op.
type != OperationRW::OperationType::BLOCK)
323 if (!IS_READ_ONLY && tx.
size_ < NEED)
328 ASSERT(rx.
size_ >= NEED);
331 ASSERT(tx.
size_ >= NEED);
334 uint8_t* tx_bytes =
nullptr;
337 tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
338 if (write_data.
size_ > 0)
342 if (write_data.
size_ < NEED)
348 if (NEED > dma_enable_min_size_)
350 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
351 NVIC_ClearPendingIRQ(res_.irqn);
354 read_buff_ = read_data;
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);
369 dma_mode_ = DmaMode::DUPLEX;
370 StartDmaDuplex(NEED);
372 return CompleteDmaOperation(op, in_isr);
375 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, NEED);
384 if (op.
type != OperationRW::OperationType::BLOCK)
396 if (op.
type != OperationRW::OperationType::BLOCK)
411 ASSERT(rx.
size_ >= size);
412 ASSERT(tx.
size_ >= size);
414 if (size > dma_enable_min_size_)
416 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
417 NVIC_ClearPendingIRQ(res_.irqn);
420 dma_mode_ = DmaMode::DUPLEX;
421 read_buff_ = {
nullptr, 0};
426 StartDmaDuplex(
static_cast<uint32_t
>(size));
427 return CompleteDmaOperation(op, in_isr);
431 PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_),
432 static_cast<const uint8_t*
>(tx.
addr_),
static_cast<uint32_t
>(size));
436 if (op.
type != OperationRW::OperationType::BLOCK)
446 const uint32_t NEED_READ =
static_cast<uint32_t
>(read_data.
size_);
449 if (op.
type != OperationRW::OperationType::BLOCK)
464 ASSERT(rx.
size_ >= (NEED_READ + 1));
465 ASSERT(tx.
size_ >= (NEED_READ + 1));
467 auto* tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
468 tx_bytes[0] =
static_cast<uint8_t
>(reg | 0x80);
471 const uint32_t TOTAL = NEED_READ + 1;
473 if (TOTAL > dma_enable_min_size_)
475 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
476 NVIC_ClearPendingIRQ(res_.irqn);
479 dma_mode_ = DmaMode::DUPLEX;
480 read_buff_ = read_data;
485 StartDmaDuplex(TOTAL);
486 return CompleteDmaOperation(op, in_isr);
489 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, TOTAL);
493 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
499 if (op.
type != OperationRW::OperationType::BLOCK)
510 const uint32_t NEED_WRITE =
static_cast<uint32_t
>(write_data.
size_);
513 if (op.
type != OperationRW::OperationType::BLOCK)
526 ASSERT(tx.
size_ >= (NEED_WRITE + 1));
528 auto* tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
529 tx_bytes[0] =
static_cast<uint8_t
>(reg & 0x7F);
532 const uint32_t TOTAL = NEED_WRITE + 1;
534 if (TOTAL > dma_enable_min_size_)
536 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
537 NVIC_ClearPendingIRQ(res_.irqn);
540 dma_mode_ = DmaMode::TX_ONLY;
541 read_buff_ = {
nullptr, 0};
546 StartDmaTxOnly(TOTAL);
547 return CompleteDmaOperation(op, in_isr);
551 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, TOTAL);
555 if (op.
type != OperationRW::OperationType::BLOCK)
563void MSPM0SPI::OnInterrupt(uint8_t index)
565 if (index >= MAX_SPI_INSTANCES)
570 MSPM0SPI* spi = instance_map_[index];
576 spi->HandleInterrupt();
579void MSPM0SPI::HandleInterrupt()
583 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
587 auto drain_rx_fifo = [
this]() ->
bool
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))
597 return (remaining > 0U);
600 auto complete_dma_ok = [
this]()
602 if (read_buff_.
size_ > 0)
605 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
614 read_buff_.
size_ = 0;
619 dma_mode_ = DmaMode::DUPLEX;
624 switch (DL_SPI_getPendingInterrupt(res_.instance))
626 case DL_SPI_IIDX_DMA_DONE_RX:
628 if (dma_mode_ == DmaMode::TX_ONLY)
633 if (dma_mode_ == DmaMode::RX_ONLY && rx_only_remaining_ > 0U)
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);
648 case DL_SPI_IIDX_DMA_DONE_TX:
649 if (dma_mode_ == DmaMode::TX_ONLY)
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);
659 dma_mode_ = DmaMode::DUPLEX;
669 case DL_SPI_IIDX_TX_UNDERFLOW:
670 case DL_SPI_IIDX_PARITY_ERROR:
673 dma_mode_ = DmaMode::DUPLEX;
678 case DL_SPI_IIDX_RX_OVERFLOW:
679 if (dma_mode_ == DmaMode::TX_ONLY)
681 (void)drain_rx_fifo();
682 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW);
688 dma_mode_ = DmaMode::DUPLEX;
693 case DL_SPI_IIDX_RX_TIMEOUT:
694 if (dma_mode_ == DmaMode::TX_ONLY)
696 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_TIMEOUT);
702 dma_mode_ = DmaMode::DUPLEX;
712#if defined(SPI0_BASE)
713extern "C" void SPI0_IRQHandler(
void)
715 LibXR::MSPM0SPI::OnInterrupt(0);
719#if defined(SPI1_BASE)
720extern "C" void SPI1_IRQHandler(
void)
722 LibXR::MSPM0SPI::OnInterrupt(1);
726#if defined(SPI2_BASE)
727extern "C" void SPI2_IRQHandler(
void)
729 LibXR::MSPM0SPI::OnInterrupt(2);
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
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.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
串行外设接口(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 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.