libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::CH32SPI Class Reference

CH32 SPI 驱动实现 / CH32 SPI driver implementation. More...

#include <ch32_spi.hpp>

Inheritance diagram for LibXR::CH32SPI:
[legend]
Collaboration diagram for LibXR::CH32SPI:
[legend]

Public Member Functions

 CH32SPI (ch32_spi_id_t id, RawData dma_rx, RawData dma_tx, GPIO_TypeDef *sck_port, uint16_t sck_pin, GPIO_TypeDef *miso_port, uint16_t miso_pin, GPIO_TypeDef *mosi_port, uint16_t mosi_pin, uint32_t pin_remap=0, bool master_mode=true, bool firstbit_msb=true, uint16_t prescaler=SPI_BaudRatePrescaler_64, uint32_t dma_enable_min_size=3, SPI::Configuration config={SPI::ClockPolarity::LOW, SPI::ClockPhase::EDGE_1})
 构造 SPI 对象 / Construct SPI object
 
ErrorCode ReadAndWrite (RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr) override
 SPI 接口实现 / SPI interface overrides.
 
ErrorCode SetConfig (SPI::Configuration config) override
 设置 SPI 配置参数。Sets SPI configuration parameters.
 
ErrorCode MemRead (uint16_t reg, RawData read_data, OperationRW &op, bool in_isr) 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) override
 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
 
ErrorCode Transfer (size_t size, OperationRW &op, bool in_isr) override
 进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).
 
uint32_t GetMaxBusSpeed () const override
 获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.
 
SPI::Prescaler GetMaxPrescaler () const override
 获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.
 
void RxDmaIRQHandler ()
 DMA 中断回调 / DMA interrupt callbacks.
 
void TxDmaIRQHandler ()
 
ErrorCode PollingTransfer (uint8_t *rx, const uint8_t *tx, uint32_t len)
 轮询传输辅助函数 / Polling transfer helper
 
- 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.
 

Data Fields

SPI_TypeDef * instance_
 
DMA_Channel_TypeDef * dma_rx_channel_
 
DMA_Channel_TypeDef * dma_tx_channel_
 
ch32_spi_id_t id_
 
uint32_t dma_enable_min_size_
 
OperationRW rw_op_
 运行时状态 / Runtime state
 
RawData read_buff_
 
bool mem_read_ = false
 
bool busy_ = false
 
uint16_t mode_
 SPI 寄存器配置缓存 / Cached SPI register configuration.
 
uint16_t datasize_
 SPI_DataSize_8b by default.
 
uint16_t firstbit_
 SPI_FirstBit_MSB / SPI_FirstBit_LSB.
 
uint16_t prescaler_
 SPI_BaudRatePrescaler_x.
 
uint16_t nss_ = SPI_NSS_Soft
 
GPIO_TypeDef * sck_port_
 GPIO 配置 / GPIO configuration.
 
uint16_t sck_pin_
 
GPIO_TypeDef * miso_port_
 
uint16_t miso_pin_
 
GPIO_TypeDef * mosi_port_
 
uint16_t mosi_pin_
 

Static Public Attributes

static CH32SPImap_ [CH32_SPI_NUMBER] = {nullptr}
 

Private Member Functions

bool DmaBusy () const
 
void StartDmaDuplex (uint32_t count)
 
void StopDma ()
 
void PrepareTxBuffer (ConstRawData write_data, uint32_t need_len, uint32_t prefix=0, uint8_t dummy=0x00)
 

Static Private Member Functions

static SPI::Prescaler MapCH32PrescalerToEnum (uint16_t p)
 
static bool MapEnumToCH32Prescaler (SPI::Prescaler p, uint16_t &out)
 

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.
 
- Static Public Member Functions inherited from LibXR::SPI
static constexpr uint32_t PrescalerToDiv (Prescaler prescaler)
 将分频系数转换为除数。Converts a prescaler to a divisor.
 

Detailed Description

CH32 SPI 驱动实现 / CH32 SPI driver implementation.

Definition at line 19 of file ch32_spi.hpp.

Constructor & Destructor Documentation

◆ CH32SPI()

CH32SPI::CH32SPI ( ch32_spi_id_t id,
RawData dma_rx,
RawData dma_tx,
GPIO_TypeDef * sck_port,
uint16_t sck_pin,
GPIO_TypeDef * miso_port,
uint16_t miso_pin,
GPIO_TypeDef * mosi_port,
uint16_t mosi_pin,
uint32_t pin_remap = 0,
bool master_mode = true,
bool firstbit_msb = true,
uint16_t prescaler = SPI_BaudRatePrescaler_64,
uint32_t dma_enable_min_size = 3,
SPI::Configuration config = {SPI::ClockPolarity::LOWSPI::ClockPhase::EDGE_1} )

构造 SPI 对象 / Construct SPI object

Definition at line 62 of file ch32_spi.cpp.

67 : SPI(dma_rx, dma_tx),
68 instance_(ch32_spi_get_instance_id(id)),
69 dma_rx_channel_(CH32_SPI_RX_DMA_CHANNEL_MAP[id]),
70 dma_tx_channel_(CH32_SPI_TX_DMA_CHANNEL_MAP[id]),
71 id_(id),
72 dma_enable_min_size_(dma_enable_min_size),
73 mode_(master_mode ? SPI_Mode_Master : SPI_Mode_Slave),
74 datasize_(SPI_DataSize_8b),
75 firstbit_(firstbit_msb ? SPI_FirstBit_MSB : SPI_FirstBit_LSB),
76 prescaler_(prescaler),
77 sck_port_(sck_port),
78 sck_pin_(sck_pin),
79 miso_port_(miso_port),
80 miso_pin_(miso_pin),
81 mosi_port_(mosi_port),
82 mosi_pin_(mosi_pin)
83{
84 ASSERT(instance_ != nullptr);
85
86 map_[id] = this;
87
88 // Clock configuration.
89 if (CH32_SPI_APB_MAP[id] == 1)
90 {
91 RCC_APB1PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
92 }
93 else if (CH32_SPI_APB_MAP[id] == 2)
94 {
95 RCC_APB2PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
96 }
97 else
98 {
99 ASSERT(false);
100 }
101 RCC_AHBPeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP_DMA[id], ENABLE);
102
103 // GPIO configuration.
104 {
105 GPIO_InitTypeDef gpio = {};
106 gpio.GPIO_Speed = GPIO_Speed_50MHz;
107
108 // SCK
109 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(sck_port_), ENABLE);
110 if (mode_ == SPI_Mode_Master)
111 {
112 gpio.GPIO_Pin = sck_pin_;
113 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
114 }
115 else
116 {
117 gpio.GPIO_Pin = sck_pin_;
118 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
119 }
120 GPIO_Init(sck_port_, &gpio);
121
122 // MISO
123 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(miso_port_), ENABLE);
124 if (mode_ == SPI_Mode_Master)
125 {
126 gpio.GPIO_Pin = miso_pin_;
127 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
128 }
129 else
130 {
131 gpio.GPIO_Pin = miso_pin_;
132 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
133 }
134 GPIO_Init(miso_port_, &gpio);
135
136 // MOSI
137 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(mosi_port_), ENABLE);
138 if (mode_ == SPI_Mode_Master)
139 {
140 gpio.GPIO_Pin = mosi_pin_;
141 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
142 }
143 else
144 {
145 gpio.GPIO_Pin = mosi_pin_;
146 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
147 }
148 GPIO_Init(mosi_port_, &gpio);
149
150 if (pin_remap != 0)
151 {
152 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
153 GPIO_PinRemapConfig(pin_remap, ENABLE);
154 }
155 }
156
157 // SPI base configuration.
158 {
159 SPI_InitTypeDef init = {};
160 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
161 init.SPI_Mode = mode_;
162 init.SPI_DataSize = datasize_;
163 init.SPI_CPOL =
164 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
165 init.SPI_CPHA =
166 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
167 init.SPI_NSS = nss_;
168 init.SPI_BaudRatePrescaler = prescaler_;
169 init.SPI_FirstBit = firstbit_;
170 init.SPI_CRCPolynomial = 7;
171
172 SPI_Init(instance_, &init);
173 SPI_Cmd(instance_, ENABLE);
174 }
175
176 // DMA channel base configuration (MADDR/CNTR set at runtime).
177 {
178 // RX
179 {
180 ch32_dma_callback_t cb = [](void* arg)
181 { reinterpret_cast<CH32SPI*>(arg)->RxDmaIRQHandler(); };
182 ch32_dma_register_callback(ch32_dma_get_id(dma_rx_channel_), cb, this);
183
184 DMA_InitTypeDef di = {};
185 DMA_DeInit(dma_rx_channel_);
186 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
187 di.DMA_MemoryBaseAddr = (uint32_t)dma_rx.addr_;
188 di.DMA_DIR = DMA_DIR_PeripheralSRC;
189 di.DMA_BufferSize = 0;
190 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
191 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
192 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
193 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
194 di.DMA_Mode = DMA_Mode_Normal;
195 di.DMA_Priority = DMA_Priority_High;
196 di.DMA_M2M = DMA_M2M_Disable;
197 DMA_Init(dma_rx_channel_, &di);
198 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
199 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_rx_channel_)]);
200 }
201 // TX
202 {
203 ch32_dma_callback_t cb = [](void* arg)
204 { reinterpret_cast<CH32SPI*>(arg)->TxDmaIRQHandler(); };
205 ch32_dma_register_callback(ch32_dma_get_id(dma_tx_channel_), cb, this);
206
207 DMA_InitTypeDef di = {};
208 DMA_DeInit(dma_tx_channel_);
209 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
210 di.DMA_MemoryBaseAddr = 0;
211 di.DMA_DIR = DMA_DIR_PeripheralDST;
212 di.DMA_BufferSize = 0;
213 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
214 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
215 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
216 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
217 di.DMA_Mode = DMA_Mode_Normal;
218 di.DMA_Priority = DMA_Priority_VeryHigh;
219 di.DMA_M2M = DMA_M2M_Disable;
220 DMA_Init(dma_tx_channel_, &di);
221 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
222 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_tx_channel_)]);
223 }
224 }
225
226 // Sync base-class configuration for rate query helpers.
227 GetConfig() = config;
228 GetConfig().prescaler = MapCH32PrescalerToEnum(prescaler_);
229}
CH32 SPI 驱动实现 / CH32 SPI driver implementation.
Definition ch32_spi.hpp:20
void RxDmaIRQHandler()
DMA 中断回调 / DMA interrupt callbacks.
Definition ch32_spi.cpp:549
uint16_t mode_
SPI 寄存器配置缓存 / Cached SPI register configuration.
Definition ch32_spi.hpp:83
uint16_t prescaler_
SPI_BaudRatePrescaler_x.
Definition ch32_spi.hpp:86
uint16_t datasize_
SPI_DataSize_8b by default.
Definition ch32_spi.hpp:84
uint16_t firstbit_
SPI_FirstBit_MSB / SPI_FirstBit_LSB.
Definition ch32_spi.hpp:85
GPIO_TypeDef * sck_port_
GPIO 配置 / GPIO configuration.
Definition ch32_spi.hpp:90
void * addr_
数据存储地址。 The storage address of the data.
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
SPI(RawData rx_buffer, RawData tx_buffer)
构造函数。Constructor.
Definition spi.hpp:110
@ LOW
时钟空闲时为低电平。Clock idle low.
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
Definition spi.hpp:396
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

Member Function Documentation

◆ DmaBusy()

bool LibXR::CH32SPI::DmaBusy ( ) const
inlineprivate

Definition at line 55 of file ch32_spi.hpp.

56 {
57 return (dma_rx_channel_->CNTR != 0) || (dma_tx_channel_->CNTR != 0) || busy_;
58 }

◆ GetMaxBusSpeed()

uint32_t CH32SPI::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 649 of file ch32_spi.cpp.

650{
651 RCC_ClocksTypeDef clocks{};
652 RCC_GetClocksFreq(&clocks);
653
654 if (CH32_SPI_APB_MAP[id_] == 2)
655 {
656 return clocks.PCLK2_Frequency;
657 }
658 else if (CH32_SPI_APB_MAP[id_] == 1)
659 {
660 return clocks.PCLK1_Frequency;
661 }
662 return 0u;
663}

◆ GetMaxPrescaler()

SPI::Prescaler CH32SPI::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 666 of file ch32_spi.cpp.

667{
668#if defined(SPI_BaudRatePrescaler_1024)
670#elif defined(SPI_BaudRatePrescaler_512)
672#elif defined(SPI_BaudRatePrescaler_256)
674#elif defined(SPI_BaudRatePrescaler_128)
676#elif defined(SPI_BaudRatePrescaler_64)
678#elif defined(SPI_BaudRatePrescaler_32)
680#elif defined(SPI_BaudRatePrescaler_16)
682#elif defined(SPI_BaudRatePrescaler_8)
684#elif defined(SPI_BaudRatePrescaler_4)
686#elif defined(SPI_BaudRatePrescaler_2)
688#else
690#endif
691}
@ DIV_16
分频系数为 16。Division factor is 16.
@ DIV_2
分频系数为 2。Division factor is 2.
@ DIV_64
分频系数为 64。Division factor is 64.
@ UNKNOWN
未知分频系数。Unknown prescaler.
@ DIV_256
分频系数为 256。Division factor is 256.
@ DIV_128
分频系数为 128。Division factor is 128.
@ DIV_4
分频系数为 4。Division factor is 4.
@ DIV_32
分频系数为 32。Division factor is 32.
@ DIV_512
分频系数为 512。Division factor is 512.
@ DIV_8
分频系数为 8。Division factor is 8.
@ DIV_1024
分频系数为 1024。Division factor is 1024.

◆ MapCH32PrescalerToEnum()

SPI::Prescaler CH32SPI::MapCH32PrescalerToEnum ( uint16_t p)
staticprivate

Definition at line 693 of file ch32_spi.cpp.

694{
695 switch (p)
696 {
697#if defined(SPI_BaudRatePrescaler_2)
698 case SPI_BaudRatePrescaler_2:
700#endif
701#if defined(SPI_BaudRatePrescaler_4)
702 case SPI_BaudRatePrescaler_4:
704#endif
705#if defined(SPI_BaudRatePrescaler_8)
706 case SPI_BaudRatePrescaler_8:
708#endif
709#if defined(SPI_BaudRatePrescaler_16)
710 case SPI_BaudRatePrescaler_16:
712#endif
713#if defined(SPI_BaudRatePrescaler_32)
714 case SPI_BaudRatePrescaler_32:
716#endif
717#if defined(SPI_BaudRatePrescaler_64)
718 case SPI_BaudRatePrescaler_64:
720#endif
721#if defined(SPI_BaudRatePrescaler_128)
722 case SPI_BaudRatePrescaler_128:
724#endif
725#if defined(SPI_BaudRatePrescaler_256)
726 case SPI_BaudRatePrescaler_256:
728#endif
729 default:
731 }
732}

◆ MapEnumToCH32Prescaler()

bool CH32SPI::MapEnumToCH32Prescaler ( SPI::Prescaler p,
uint16_t & out )
staticprivate

Definition at line 13 of file ch32_spi.cpp.

14{
15 switch (p)
16 {
17#if defined(SPI_BaudRatePrescaler_2)
19 out = SPI_BaudRatePrescaler_2;
20 return true;
21#endif
22#if defined(SPI_BaudRatePrescaler_4)
24 out = SPI_BaudRatePrescaler_4;
25 return true;
26#endif
27#if defined(SPI_BaudRatePrescaler_8)
29 out = SPI_BaudRatePrescaler_8;
30 return true;
31#endif
32#if defined(SPI_BaudRatePrescaler_16)
34 out = SPI_BaudRatePrescaler_16;
35 return true;
36#endif
37#if defined(SPI_BaudRatePrescaler_32)
39 out = SPI_BaudRatePrescaler_32;
40 return true;
41#endif
42#if defined(SPI_BaudRatePrescaler_64)
44 out = SPI_BaudRatePrescaler_64;
45 return true;
46#endif
47#if defined(SPI_BaudRatePrescaler_128)
49 out = SPI_BaudRatePrescaler_128;
50 return true;
51#endif
52#if defined(SPI_BaudRatePrescaler_256)
54 out = SPI_BaudRatePrescaler_256;
55 return true;
56#endif
57 default:
58 return false; // 不支持 DIV_1 或 >256 的枚举
59 }
60}

◆ MemRead()

ErrorCode CH32SPI::MemRead ( uint16_t reg,
RawData read_data,
OperationRW & op,
bool in_isr )
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 371 of file ch32_spi.cpp.

372{
373 const uint32_t N = read_data.size_;
374 if (N == 0)
375 {
376 if (op.type != OperationRW::OperationType::BLOCK)
377 {
378 op.UpdateStatus(in_isr, ErrorCode::OK);
379 }
380 return ErrorCode::OK;
381 }
382
383 if (DmaBusy())
384 {
385 return ErrorCode::BUSY;
386 }
387
388 RawData rx = GetRxBuffer();
389 RawData tx = GetTxBuffer();
390
391 ASSERT(rx.size_ >= N + 1);
392 ASSERT(tx.size_ >= N + 1);
393
394 const uint32_t TOTAL = N + 1;
395
396 if (TOTAL > dma_enable_min_size_)
397 {
398 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
399 txp[0] = static_cast<uint8_t>(reg | 0x80);
400 Memory::FastSet(txp + 1, 0x00, N);
401
402 mem_read_ = true;
403 read_buff_ = read_data;
404 rw_op_ = op;
405 busy_ = true;
406
407 StartDmaDuplex(TOTAL);
408
409 op.MarkAsRunning();
410 if (op.type == OperationRW::OperationType::BLOCK)
411 {
412 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
413 }
414 return ErrorCode::OK;
415 }
416 else
417 {
418 // 轮询
419 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
420 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
421 txp[0] = static_cast<uint8_t>(reg | 0x80);
422 Memory::FastSet(txp + 1, 0x00, N);
423
424 ErrorCode ec = PollingTransfer(rxp, txp, TOTAL);
425 Memory::FastCopy(read_data.addr_, rxp + 1, N);
426
427 SwitchBuffer();
428
429 if (op.type != OperationRW::OperationType::BLOCK)
430 {
431 op.UpdateStatus(in_isr, ec);
432 }
433 return ec;
434 }
435}
ErrorCode PollingTransfer(uint8_t *rx, const uint8_t *tx, uint32_t len)
轮询传输辅助函数 / Polling transfer helper
Definition ch32_spi.cpp:268
OperationRW rw_op_
运行时状态 / Runtime state
Definition ch32_spi.hpp:77
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
Definition libxr_mem.cpp:3
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
RawData GetRxBuffer()
获取接收数据的缓冲区。Gets the buffer for storing received data.
Definition spi.hpp:306
void SwitchBuffer()
切换缓冲区。Switches the buffer.
Definition spi.hpp:337
RawData GetTxBuffer()
获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
Definition spi.hpp:322

◆ MemWrite()

ErrorCode CH32SPI::MemWrite ( uint16_t reg,
ConstRawData write_data,
OperationRW & op,
bool in_isr )
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 437 of file ch32_spi.cpp.

439{
440 const uint32_t N = write_data.size_;
441 if (N == 0)
442 {
443 if (op.type != OperationRW::OperationType::BLOCK)
444 {
445 op.UpdateStatus(in_isr, ErrorCode::OK);
446 }
447 return ErrorCode::OK;
448 }
449
450 if (DmaBusy())
451 {
452 return ErrorCode::BUSY;
453 }
454
455 RawData rx = GetRxBuffer();
456 RawData tx = GetTxBuffer();
457 (void)rx; // RX 仅用于丢弃
458
459 ASSERT(tx.size_ >= N + 1);
460
461 const uint32_t TOTAL = N + 1;
462
463 if (TOTAL > dma_enable_min_size_)
464 {
465 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
466 txp[0] = static_cast<uint8_t>(reg & 0x7F);
467 Memory::FastCopy(txp + 1, write_data.addr_, N);
468
469 mem_read_ = false;
470 read_buff_ = {nullptr, 0};
471 rw_op_ = op;
472 busy_ = true;
473
474 StartDmaDuplex(TOTAL);
475
476 op.MarkAsRunning();
477 if (op.type == OperationRW::OperationType::BLOCK)
478 {
479 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
480 }
481 return ErrorCode::OK;
482 }
483 else
484 {
485 // 轮询
486 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
487 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
488 txp[0] = static_cast<uint8_t>(reg & 0x7F);
489 Memory::FastCopy(txp + 1, write_data.addr_, N);
490
491 ErrorCode ec = PollingTransfer(rxp, txp, TOTAL);
492
493 SwitchBuffer();
494
495 if (op.type != OperationRW::OperationType::BLOCK)
496 {
497 op.UpdateStatus(in_isr, ec);
498 }
499 return ec;
500 }
501}
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).

◆ PollingTransfer()

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

轮询传输辅助函数 / Polling transfer helper

Definition at line 268 of file ch32_spi.cpp.

269{
270 for (uint32_t i = 0; i < len; ++i)
271 {
272 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_TXE) == RESET)
273 {
274 }
275 SPI_I2S_SendData(instance_, tx ? tx[i] : 0x00);
276
277 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_RXNE) == RESET)
278 {
279 }
280 uint16_t d = SPI_I2S_ReceiveData(instance_);
281 if (rx)
282 {
283 rx[i] = static_cast<uint8_t>(d & 0xff);
284 }
285 }
286 return ErrorCode::OK;
287}

◆ PrepareTxBuffer()

void CH32SPI::PrepareTxBuffer ( ConstRawData write_data,
uint32_t need_len,
uint32_t prefix = 0,
uint8_t dummy = 0x00 )
private

Definition at line 503 of file ch32_spi.cpp.

505{
506 RawData tx = GetTxBuffer();
507 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
508
509 if (write_data.size_ > 0)
510 {
511 const uint32_t COPY =
512 (write_data.size_ > need_len - prefix) ? (need_len - prefix) : write_data.size_;
513 Memory::FastCopy(txp + prefix, write_data.addr_, COPY);
514 if (prefix + COPY < need_len)
515 {
516 Memory::FastSet(txp + prefix + COPY, dummy, need_len - prefix - COPY);
517 }
518 }
519 else
520 {
521 Memory::FastSet(txp + prefix, dummy, need_len - prefix);
522 }
523}

◆ ReadAndWrite()

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

SPI 接口实现 / SPI interface overrides.

Implements LibXR::SPI.

Definition at line 289 of file ch32_spi.cpp.

291{
292 const uint32_t RSZ = read_data.size_;
293 const uint32_t WSZ = write_data.size_;
294 const uint32_t NEED = (RSZ > WSZ) ? RSZ : WSZ;
295
296 if (NEED == 0)
297 {
298 if (op.type != OperationRW::OperationType::BLOCK)
299 {
300 op.UpdateStatus(in_isr, ErrorCode::OK);
301 }
302 return ErrorCode::OK;
303 }
304
305 if (DmaBusy())
306 {
307 return ErrorCode::BUSY;
308 }
309
310 RawData rx = GetRxBuffer();
311 RawData tx = GetTxBuffer();
312
313 ASSERT(rx.size_ >= NEED);
314 ASSERT(tx.size_ >= NEED);
315
316 if (NEED > dma_enable_min_size_)
317 {
318 mem_read_ = false;
319 read_buff_ = read_data;
320 rw_op_ = op;
321 busy_ = true;
322
323 PrepareTxBuffer(write_data, NEED);
324
325 StartDmaDuplex(NEED);
326
327 op.MarkAsRunning();
328 if (op.type == OperationRW::OperationType::BLOCK)
329 {
330 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
331 }
332 return ErrorCode::OK;
333 }
334 else
335 {
336 // 轮询路径(使用活动缓冲)
337 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
338 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
339
340 // 准备 tx
341 if (WSZ)
342 {
343 Memory::FastCopy(txp, write_data.addr_, WSZ);
344 if (NEED > WSZ)
345 {
346 Memory::FastSet(txp + WSZ, 0x00, NEED - WSZ);
347 }
348 }
349 else
350 {
351 Memory::FastSet(txp, 0x00, NEED);
352 }
353
354 ErrorCode ec = PollingTransfer(rxp, txp, NEED);
355
356 if (RSZ)
357 {
358 Memory::FastCopy(read_data.addr_, rxp, RSZ);
359 }
360
361 SwitchBuffer();
362
363 if (op.type != OperationRW::OperationType::BLOCK)
364 {
365 op.UpdateStatus(in_isr, ec);
366 }
367 return ec;
368 }
369}

◆ RxDmaIRQHandler()

void CH32SPI::RxDmaIRQHandler ( )

DMA 中断回调 / DMA interrupt callbacks.

Definition at line 549 of file ch32_spi.cpp.

550{
551 if (DMA_GetITStatus(CH32_SPI_RX_DMA_IT_MAP[id_]) == RESET)
552 {
553 return;
554 }
555
556 DMA_ClearITPendingBit(CH32_SPI_RX_DMA_IT_MAP[id_]);
557
558 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, DISABLE);
559 DMA_Cmd(dma_rx_channel_, DISABLE);
560
561 // 拷贝读数据(若有)
562 if (read_buff_.size_ > 0)
563 {
564 RawData rx = GetRxBuffer();
565 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
566 if (mem_read_)
567 {
568 Memory::FastCopy(read_buff_.addr_, rxp + 1, read_buff_.size_);
569 }
570 else
571 {
572 Memory::FastCopy(read_buff_.addr_, rxp, read_buff_.size_);
573 }
574 read_buff_.size_ = 0;
575 }
576
577 // 双缓冲切换与状态更新
578 SwitchBuffer();
579 busy_ = false;
580 rw_op_.UpdateStatus(true, ErrorCode::OK);
581}
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:172

◆ SetConfig()

ErrorCode CH32SPI::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 232 of file ch32_spi.cpp.

233{
234 // 1) 把 SPI::Prescaler → CH32 Prescaler 宏
235 uint16_t ch32_presc = 0;
236 if (!MapEnumToCH32Prescaler(config.prescaler, ch32_presc))
237 {
238 return ErrorCode::NOT_SUPPORT;
239 }
240
241 // 2) 关 / 复位 / 重新初始化
242 SPI_Cmd(instance_, DISABLE);
243 SPI_I2S_DeInit(instance_);
244
245 SPI_InitTypeDef init = {};
246 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
247 init.SPI_Mode = mode_;
248 init.SPI_DataSize = datasize_;
249 init.SPI_CPOL =
250 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
251 init.SPI_CPHA =
252 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
253 init.SPI_NSS = nss_;
254 init.SPI_BaudRatePrescaler = ch32_presc;
255 init.SPI_FirstBit = firstbit_;
256 init.SPI_CRCPolynomial = 7;
257
258 SPI_Init(instance_, &init);
259 SPI_Cmd(instance_, ENABLE);
260
261 // 3) 同步本地缓存与基类配置(影响 GetBusSpeed/IsDoubleBuffer)
262 prescaler_ = ch32_presc;
263 GetConfig() = config;
264
265 return ErrorCode::OK;
266}

◆ StartDmaDuplex()

void CH32SPI::StartDmaDuplex ( uint32_t count)
private

Definition at line 525 of file ch32_spi.cpp.

526{
527 RawData rx = GetRxBuffer();
528 RawData tx = GetTxBuffer();
529
530 dma_rx_channel_->MADDR = reinterpret_cast<uint32_t>(rx.addr_);
531 dma_rx_channel_->CNTR = count;
532
533 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(tx.addr_);
534 dma_tx_channel_->CNTR = count;
535
536 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, ENABLE);
537 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, ENABLE);
538
539 DMA_Cmd(dma_rx_channel_, ENABLE);
540 DMA_Cmd(dma_tx_channel_, ENABLE);
541}

◆ StopDma()

void CH32SPI::StopDma ( )
private

Definition at line 543 of file ch32_spi.cpp.

544{
545 DMA_Cmd(dma_tx_channel_, DISABLE);
546 DMA_Cmd(dma_rx_channel_, DISABLE);
547}

◆ Transfer()

ErrorCode CH32SPI::Transfer ( size_t size,
OperationRW & op,
bool in_isr )
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 596 of file ch32_spi.cpp.

597{
598 if (DmaBusy())
599 {
600 return ErrorCode::BUSY;
601 }
602
603 if (size == 0)
604 {
605 if (op.type != OperationRW::OperationType::BLOCK)
606 {
607 op.UpdateStatus(in_isr, ErrorCode::OK);
608 }
609 return ErrorCode::OK;
610 }
611
612 RawData rx = GetRxBuffer();
613 RawData tx = GetTxBuffer();
614 ASSERT(rx.size_ >= size);
615 ASSERT(tx.size_ >= size);
616
617 if (size > dma_enable_min_size_)
618 {
619 rw_op_ = op;
620 read_buff_ = {nullptr, 0};
621 mem_read_ = false;
622 busy_ = true;
623
624 StartDmaDuplex(static_cast<uint32_t>(size));
625
626 op.MarkAsRunning();
627 if (op.type == OperationRW::OperationType::BLOCK)
628 {
629 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
630 }
631 return ErrorCode::OK;
632 }
633
634 // 小包轮询
635 ErrorCode ec =
636 PollingTransfer(static_cast<uint8_t*>(rx.addr_),
637 static_cast<const uint8_t*>(tx.addr_), static_cast<uint32_t>(size));
638
639 SwitchBuffer();
640
641 if (op.type != OperationRW::OperationType::BLOCK)
642 {
643 op.UpdateStatus(in_isr, ec);
644 }
645 return ec;
646}

◆ TxDmaIRQHandler()

void CH32SPI::TxDmaIRQHandler ( )

Definition at line 583 of file ch32_spi.cpp.

584{
585 if (DMA_GetITStatus(CH32_SPI_TX_DMA_IT_MAP[id_]) == RESET)
586 {
587 return;
588 }
589 DMA_ClearITPendingBit(CH32_SPI_TX_DMA_IT_MAP[id_]);
590
591 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, DISABLE);
592 DMA_Cmd(dma_tx_channel_, DISABLE);
593}

Field Documentation

◆ busy_

bool LibXR::CH32SPI::busy_ = false

Definition at line 80 of file ch32_spi.hpp.

◆ datasize_

uint16_t LibXR::CH32SPI::datasize_

SPI_DataSize_8b by default.

Definition at line 84 of file ch32_spi.hpp.

◆ dma_enable_min_size_

uint32_t LibXR::CH32SPI::dma_enable_min_size_

Definition at line 74 of file ch32_spi.hpp.

◆ dma_rx_channel_

DMA_Channel_TypeDef* LibXR::CH32SPI::dma_rx_channel_

Definition at line 71 of file ch32_spi.hpp.

◆ dma_tx_channel_

DMA_Channel_TypeDef* LibXR::CH32SPI::dma_tx_channel_

Definition at line 72 of file ch32_spi.hpp.

◆ firstbit_

uint16_t LibXR::CH32SPI::firstbit_

SPI_FirstBit_MSB / SPI_FirstBit_LSB.

Definition at line 85 of file ch32_spi.hpp.

◆ id_

ch32_spi_id_t LibXR::CH32SPI::id_

Definition at line 73 of file ch32_spi.hpp.

◆ instance_

SPI_TypeDef* LibXR::CH32SPI::instance_

Definition at line 70 of file ch32_spi.hpp.

◆ map_

CH32SPI * CH32SPI::map_ = {nullptr}
static

Definition at line 52 of file ch32_spi.hpp.

◆ mem_read_

bool LibXR::CH32SPI::mem_read_ = false

Definition at line 79 of file ch32_spi.hpp.

◆ miso_pin_

uint16_t LibXR::CH32SPI::miso_pin_

Definition at line 93 of file ch32_spi.hpp.

◆ miso_port_

GPIO_TypeDef* LibXR::CH32SPI::miso_port_

Definition at line 92 of file ch32_spi.hpp.

◆ mode_

uint16_t LibXR::CH32SPI::mode_

SPI 寄存器配置缓存 / Cached SPI register configuration.

SPI_Mode_Master / SPI_Mode_Slave

Definition at line 83 of file ch32_spi.hpp.

◆ mosi_pin_

uint16_t LibXR::CH32SPI::mosi_pin_

Definition at line 95 of file ch32_spi.hpp.

◆ mosi_port_

GPIO_TypeDef* LibXR::CH32SPI::mosi_port_

Definition at line 94 of file ch32_spi.hpp.

◆ nss_

uint16_t LibXR::CH32SPI::nss_ = SPI_NSS_Soft

Definition at line 87 of file ch32_spi.hpp.

◆ prescaler_

uint16_t LibXR::CH32SPI::prescaler_

SPI_BaudRatePrescaler_x.

Definition at line 86 of file ch32_spi.hpp.

◆ read_buff_

RawData LibXR::CH32SPI::read_buff_

Definition at line 78 of file ch32_spi.hpp.

◆ rw_op_

OperationRW LibXR::CH32SPI::rw_op_

运行时状态 / Runtime state

Definition at line 77 of file ch32_spi.hpp.

◆ sck_pin_

uint16_t LibXR::CH32SPI::sck_pin_

Definition at line 91 of file ch32_spi.hpp.

◆ sck_port_

GPIO_TypeDef* LibXR::CH32SPI::sck_port_

GPIO 配置 / GPIO configuration.

Definition at line 90 of file ch32_spi.hpp.


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