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;
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);
47 const ErrorCode SET_CFG_ANS = SetConfig(config);
48 ASSERT(SET_CFG_ANS == ErrorCode::OK);
53 DL_SPI_FRAME_FORMAT frame_format = DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA0;
57 ? DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA0
58 : DL_SPI_FRAME_FORMAT_MOTO4_POL0_PHA1;
63 ? DL_SPI_FRAME_FORMAT_MOTO4_POL1_PHA0
64 : DL_SPI_FRAME_FORMAT_MOTO4_POL1_PHA1;
68 if (DIV < 2 || DIV > 512 || (DIV & 0x1) != 0)
73 const uint32_t SCR = (DIV >> 1) - 1;
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);
88ErrorCode MSPM0SPI::PollingTransfer(uint8_t* rx,
const uint8_t* tx, uint32_t len)
90 constexpr uint32_t POLLING_TIMEOUT_US = 20000U;
91 constexpr uint32_t POLLING_FALLBACK_SPIN_BUDGET = 1000000U;
100 uint32_t spin_budget = POLLING_FALLBACK_SPIN_BUDGET;
101 auto polling_timed_out = [&]() ->
bool
104 if ((NOW_US - START_US) >= POLLING_TIMEOUT_US)
108 if (spin_budget > 0U)
115 for (uint32_t i = 0; i < len; ++i)
117 while (DL_SPI_isTXFIFOFull(res_.instance))
119 if (polling_timed_out())
124 const uint8_t TX_BYTE = (tx ==
nullptr) ? 0 : tx[i];
125 DL_SPI_transmitData8(res_.instance, TX_BYTE);
128 while (!DL_SPI_receiveDataCheck8(res_.instance, &rx_byte))
130 if (polling_timed_out())
142 while (DL_SPI_isBusy(res_.instance))
144 if (polling_timed_out())
153bool MSPM0SPI::DmaBusy()
const
160 return DL_DMA_isChannelEnabled(DMA, res_.dma_rx_channel) ||
161 DL_DMA_isChannelEnabled(DMA, res_.dma_tx_channel);
164void MSPM0SPI::StartDmaDuplex(uint32_t count)
166 masked_interrupts_for_tx_only_ = 0;
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);
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);
181 DL_DMA_enableChannel(DMA, res_.dma_rx_channel);
182 DL_DMA_enableChannel(DMA, res_.dma_tx_channel);
185void MSPM0SPI::StartDmaRxOnly(uint32_t offset, uint32_t count)
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_);
194 masked_interrupts_for_tx_only_ = 0;
196 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
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);
210 DL_SPI_setRepeatTransmit(res_.instance,
static_cast<uint8_t
>(count - 1U));
211 DL_SPI_transmitData8(res_.instance, 0U);
214void MSPM0SPI::StartDmaTxOnly(uint32_t count)
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;
220 masked_interrupts_for_tx_only_ =
221 DL_SPI_getEnabledInterrupts(res_.instance, TX_ONLY_MASKED_INTERRUPTS);
222 if (masked_interrupts_for_tx_only_ != 0U)
224 DL_SPI_disableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
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);
237void MSPM0SPI::StopDma()
239 DL_DMA_disableChannel(DMA, res_.dma_tx_channel);
240 DL_DMA_disableChannel(DMA, res_.dma_rx_channel);
242 if (dma_mode_ == DmaMode::RX_ONLY)
244 DL_SPI_setRepeatTransmit(res_.instance, 0U);
247 rx_only_offset_ = 0U;
248 rx_only_remaining_ = 0U;
250 if (masked_interrupts_for_tx_only_ != 0U)
252 DL_SPI_enableInterrupt(res_.instance, masked_interrupts_for_tx_only_);
253 masked_interrupts_for_tx_only_ = 0U;
257ErrorCode MSPM0SPI::CompleteDmaOperation(OperationRW& op,
bool in_isr)
260 if (op.type != OperationRW::OperationType::BLOCK)
266 const ErrorCode WAIT_ANS = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
269 const bool IRQ_WAS_ENABLED = (NVIC_GetEnableIRQ(res_.irqn) != 0U);
272 NVIC_DisableIRQ(res_.irqn);
276 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
277 NVIC_ClearPendingIRQ(res_.irqn);
280 dma_mode_ = DmaMode::DUPLEX;
291 NVIC_EnableIRQ(res_.irqn);
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);
312 if (op.
type != OperationRW::OperationType::BLOCK)
331 if (!IS_READ_ONLY && tx.
size_ < NEED)
336 uint8_t* tx_bytes =
nullptr;
339 tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
340 if (write_data.
size_ > 0)
344 if (write_data.
size_ < NEED)
350 if (NEED > dma_enable_min_size_)
352 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
353 NVIC_ClearPendingIRQ(res_.irqn);
356 read_buff_ = read_data;
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);
371 dma_mode_ = DmaMode::DUPLEX;
372 StartDmaDuplex(NEED);
374 return CompleteDmaOperation(op, in_isr);
377 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, NEED);
386 if (op.
type != OperationRW::OperationType::BLOCK)
398 if (op.
type != OperationRW::OperationType::BLOCK)
413 ASSERT(rx.
size_ >= size);
414 ASSERT(tx.
size_ >= size);
416 if (size > dma_enable_min_size_)
418 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
419 NVIC_ClearPendingIRQ(res_.irqn);
422 dma_mode_ = DmaMode::DUPLEX;
423 read_buff_ = {
nullptr, 0};
428 StartDmaDuplex(
static_cast<uint32_t
>(size));
429 return CompleteDmaOperation(op, in_isr);
433 PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_),
434 static_cast<const uint8_t*
>(tx.
addr_),
static_cast<uint32_t
>(size));
438 if (op.
type != OperationRW::OperationType::BLOCK)
448 const uint32_t NEED_READ =
static_cast<uint32_t
>(read_data.
size_);
451 if (op.
type != OperationRW::OperationType::BLOCK)
466 ASSERT(rx.
size_ >= (NEED_READ + 1));
467 ASSERT(tx.
size_ >= (NEED_READ + 1));
469 auto* tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
470 tx_bytes[0] =
static_cast<uint8_t
>(reg | 0x80);
473 const uint32_t TOTAL = NEED_READ + 1;
475 if (TOTAL > dma_enable_min_size_)
477 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
478 NVIC_ClearPendingIRQ(res_.irqn);
481 dma_mode_ = DmaMode::DUPLEX;
482 read_buff_ = read_data;
487 StartDmaDuplex(TOTAL);
488 return CompleteDmaOperation(op, in_isr);
491 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, TOTAL);
495 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
501 if (op.
type != OperationRW::OperationType::BLOCK)
512 const uint32_t NEED_WRITE =
static_cast<uint32_t
>(write_data.
size_);
515 if (op.
type != OperationRW::OperationType::BLOCK)
528 ASSERT(tx.
size_ >= (NEED_WRITE + 1));
530 auto* tx_bytes =
static_cast<uint8_t*
>(tx.
addr_);
531 tx_bytes[0] =
static_cast<uint8_t
>(reg & 0x7F);
534 const uint32_t TOTAL = NEED_WRITE + 1;
536 if (TOTAL > dma_enable_min_size_)
538 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
539 NVIC_ClearPendingIRQ(res_.irqn);
542 dma_mode_ = DmaMode::TX_ONLY;
543 read_buff_ = {
nullptr, 0};
548 StartDmaTxOnly(TOTAL);
549 return CompleteDmaOperation(op, in_isr);
553 ErrorCode ans = PollingTransfer(
static_cast<uint8_t*
>(rx.
addr_), tx_bytes, TOTAL);
557 if (op.
type != OperationRW::OperationType::BLOCK)
565void MSPM0SPI::OnInterrupt(uint8_t index)
567 if (index >= MAX_SPI_INSTANCES)
572 MSPM0SPI* spi = instance_map_[index];
578 spi->HandleInterrupt();
581void MSPM0SPI::HandleInterrupt()
585 DL_SPI_clearInterruptStatus(res_.instance, MSPM0_SPI_DMA_INTERRUPT_MASK);
589 auto drain_rx_fifo = [
this]() ->
bool
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))
599 return (remaining > 0U);
602 auto complete_dma_ok = [
this]()
604 if (read_buff_.
size_ > 0)
607 auto* rx_bytes =
static_cast<uint8_t*
>(rx.
addr_);
616 read_buff_.
size_ = 0;
621 dma_mode_ = DmaMode::DUPLEX;
626 switch (DL_SPI_getPendingInterrupt(res_.instance))
628 case DL_SPI_IIDX_DMA_DONE_RX:
630 if (dma_mode_ == DmaMode::TX_ONLY)
635 if (dma_mode_ == DmaMode::RX_ONLY && rx_only_remaining_ > 0U)
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);
650 case DL_SPI_IIDX_DMA_DONE_TX:
651 if (dma_mode_ == DmaMode::TX_ONLY)
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);
661 dma_mode_ = DmaMode::DUPLEX;
671 case DL_SPI_IIDX_TX_UNDERFLOW:
672 case DL_SPI_IIDX_PARITY_ERROR:
675 dma_mode_ = DmaMode::DUPLEX;
680 case DL_SPI_IIDX_RX_OVERFLOW:
681 if (dma_mode_ == DmaMode::TX_ONLY)
683 (void)drain_rx_fifo();
684 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_OVERFLOW);
690 dma_mode_ = DmaMode::DUPLEX;
695 case DL_SPI_IIDX_RX_TIMEOUT:
696 if (dma_mode_ == DmaMode::TX_ONLY)
698 DL_SPI_clearInterruptStatus(res_.instance, DL_SPI_INTERRUPT_RX_TIMEOUT);
704 dma_mode_ = DmaMode::DUPLEX;
714#if defined(SPI0_BASE)
715extern "C" void SPI0_IRQHandler(
void)
717 LibXR::MSPM0SPI::OnInterrupt(0);
721#if defined(SPI1_BASE)
722extern "C" void SPI1_IRQHandler(
void)
724 LibXR::MSPM0SPI::OnInterrupt(1);
728#if defined(SPI2_BASE)
729extern "C" void SPI2_IRQHandler(
void)
731 LibXR::MSPM0SPI::OnInterrupt(2);
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
MSPM0 SPI 控制器 / MSPM0 SPI controller.
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)
按通知方式报告完成结果 / 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).
@ 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.
LibXR 命名空间 / LibXR namespace.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ 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 >
计算两个数的最小值 / 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.
ClockPhase clock_phase
SPI 时钟相位 / SPI clock phase.
Prescaler prescaler
SPI 分频系数 / SPI prescaler.
ClockPolarity clock_polarity
SPI 时钟极性 / SPI clock polarity.