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_
 
AsyncBlockWait block_wait_ {}
 

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 // 时钟配置。
89 // Clock configuration.
90 if (CH32_SPI_APB_MAP[id] == 1)
91 {
92 RCC_APB1PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
93 }
94 else if (CH32_SPI_APB_MAP[id] == 2)
95 {
96 RCC_APB2PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
97 }
98 else
99 {
100 ASSERT(false);
101 }
102 RCC_AHBPeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP_DMA[id], ENABLE);
103
104 // GPIO 配置。
105 // GPIO configuration.
106 {
107 GPIO_InitTypeDef gpio = {};
108 gpio.GPIO_Speed = GPIO_Speed_50MHz;
109
110 // SCK 引脚。
111 // SCK.
112 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(sck_port_), ENABLE);
113 if (mode_ == SPI_Mode_Master)
114 {
115 gpio.GPIO_Pin = sck_pin_;
116 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
117 }
118 else
119 {
120 gpio.GPIO_Pin = sck_pin_;
121 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
122 }
123 GPIO_Init(sck_port_, &gpio);
124
125 // MISO 引脚。
126 // MISO.
127 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(miso_port_), ENABLE);
128 if (mode_ == SPI_Mode_Master)
129 {
130 gpio.GPIO_Pin = miso_pin_;
131 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
132 }
133 else
134 {
135 gpio.GPIO_Pin = miso_pin_;
136 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
137 }
138 GPIO_Init(miso_port_, &gpio);
139
140 // MOSI 引脚。
141 // MOSI.
142 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(mosi_port_), ENABLE);
143 if (mode_ == SPI_Mode_Master)
144 {
145 gpio.GPIO_Pin = mosi_pin_;
146 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
147 }
148 else
149 {
150 gpio.GPIO_Pin = mosi_pin_;
151 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
152 }
153 GPIO_Init(mosi_port_, &gpio);
154
155 if (pin_remap != 0)
156 {
157 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
158 GPIO_PinRemapConfig(pin_remap, ENABLE);
159 }
160 }
161
162 // SPI 基础配置。
163 // SPI base configuration.
164 {
165 SPI_InitTypeDef init = {};
166 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
167 init.SPI_Mode = mode_;
168 init.SPI_DataSize = datasize_;
169 init.SPI_CPOL =
170 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
171 init.SPI_CPHA =
172 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
173 init.SPI_NSS = nss_;
174 init.SPI_BaudRatePrescaler = prescaler_;
175 init.SPI_FirstBit = firstbit_;
176 init.SPI_CRCPolynomial = 7;
177
178 SPI_Init(instance_, &init);
179 SPI_Cmd(instance_, ENABLE);
180 }
181
182 // DMA 通道基础配置(MADDR/CNTR 在运行时设置)。
183 // DMA channel base configuration (MADDR/CNTR set at runtime).
184 {
185 // RX 通道。
186 // RX.
187 {
188 ch32_dma_callback_t cb = [](void* arg)
189 { reinterpret_cast<CH32SPI*>(arg)->RxDmaIRQHandler(); };
190 ch32_dma_register_callback(ch32_dma_get_id(dma_rx_channel_), cb, this);
191
192 DMA_InitTypeDef di = {};
193 DMA_DeInit(dma_rx_channel_);
194 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
195 di.DMA_MemoryBaseAddr = (uint32_t)dma_rx.addr_;
196 di.DMA_DIR = DMA_DIR_PeripheralSRC;
197 di.DMA_BufferSize = 0;
198 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
199 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
200 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
201 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
202 di.DMA_Mode = DMA_Mode_Normal;
203 di.DMA_Priority = DMA_Priority_High;
204 di.DMA_M2M = DMA_M2M_Disable;
205 DMA_Init(dma_rx_channel_, &di);
206 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
207 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_rx_channel_)]);
208 }
209 // TX 通道。
210 // TX.
211 {
212 ch32_dma_callback_t cb = [](void* arg)
213 { reinterpret_cast<CH32SPI*>(arg)->TxDmaIRQHandler(); };
214 ch32_dma_register_callback(ch32_dma_get_id(dma_tx_channel_), cb, this);
215
216 DMA_InitTypeDef di = {};
217 DMA_DeInit(dma_tx_channel_);
218 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
219 di.DMA_MemoryBaseAddr = 0;
220 di.DMA_DIR = DMA_DIR_PeripheralDST;
221 di.DMA_BufferSize = 0;
222 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
223 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
224 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
225 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
226 di.DMA_Mode = DMA_Mode_Normal;
227 di.DMA_Priority = DMA_Priority_VeryHigh;
228 di.DMA_M2M = DMA_M2M_Disable;
229 DMA_Init(dma_tx_channel_, &di);
230 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
231 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_tx_channel_)]);
232 }
233 }
234
235 // 同步基类配置,供速率查询辅助逻辑使用。
236 // Sync the base-class configuration for rate-query helpers.
237 GetConfig() = config;
238 GetConfig().prescaler = MapCH32PrescalerToEnum(prescaler_);
239}
CH32 SPI 驱动实现 / CH32 SPI driver implementation.
Definition ch32_spi.hpp:20
void RxDmaIRQHandler()
DMA 中断回调 / DMA interrupt callbacks.
Definition ch32_spi.cpp:571
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 695 of file ch32_spi.cpp.

696{
697 RCC_ClocksTypeDef clocks{};
698 RCC_GetClocksFreq(&clocks);
699
700 if (CH32_SPI_APB_MAP[id_] == 2)
701 {
702 return clocks.PCLK2_Frequency;
703 }
704 else if (CH32_SPI_APB_MAP[id_] == 1)
705 {
706 return clocks.PCLK1_Frequency;
707 }
708 return 0u;
709}

◆ 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 713 of file ch32_spi.cpp.

714{
715#if defined(SPI_BaudRatePrescaler_1024)
717#elif defined(SPI_BaudRatePrescaler_512)
719#elif defined(SPI_BaudRatePrescaler_256)
721#elif defined(SPI_BaudRatePrescaler_128)
723#elif defined(SPI_BaudRatePrescaler_64)
725#elif defined(SPI_BaudRatePrescaler_32)
727#elif defined(SPI_BaudRatePrescaler_16)
729#elif defined(SPI_BaudRatePrescaler_8)
731#elif defined(SPI_BaudRatePrescaler_4)
733#elif defined(SPI_BaudRatePrescaler_2)
735#else
737#endif
738}
@ 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 740 of file ch32_spi.cpp.

741{
742 switch (p)
743 {
744#if defined(SPI_BaudRatePrescaler_2)
745 case SPI_BaudRatePrescaler_2:
747#endif
748#if defined(SPI_BaudRatePrescaler_4)
749 case SPI_BaudRatePrescaler_4:
751#endif
752#if defined(SPI_BaudRatePrescaler_8)
753 case SPI_BaudRatePrescaler_8:
755#endif
756#if defined(SPI_BaudRatePrescaler_16)
757 case SPI_BaudRatePrescaler_16:
759#endif
760#if defined(SPI_BaudRatePrescaler_32)
761 case SPI_BaudRatePrescaler_32:
763#endif
764#if defined(SPI_BaudRatePrescaler_64)
765 case SPI_BaudRatePrescaler_64:
767#endif
768#if defined(SPI_BaudRatePrescaler_128)
769 case SPI_BaudRatePrescaler_128:
771#endif
772#if defined(SPI_BaudRatePrescaler_256)
773 case SPI_BaudRatePrescaler_256:
775#endif
776 default:
778 }
779}

◆ 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 386 of file ch32_spi.cpp.

387{
388 const uint32_t N = read_data.size_;
389 if (N == 0)
390 {
391 if (op.type != OperationRW::OperationType::BLOCK)
392 {
393 op.UpdateStatus(in_isr, ErrorCode::OK);
394 }
395 return ErrorCode::OK;
396 }
397
398 if (DmaBusy())
399 {
400 return ErrorCode::BUSY;
401 }
402
403 RawData rx = GetRxBuffer();
404 RawData tx = GetTxBuffer();
405
406 ASSERT(rx.size_ >= N + 1);
407 ASSERT(tx.size_ >= N + 1);
408
409 const uint32_t TOTAL = N + 1;
410
411 if (TOTAL > dma_enable_min_size_)
412 {
413 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
414 txp[0] = static_cast<uint8_t>(reg | 0x80);
415 Memory::FastSet(txp + 1, 0x00, N);
416
417 mem_read_ = true;
418 read_buff_ = read_data;
419 rw_op_ = op;
420 busy_ = true;
421
422 if (op.type == OperationRW::OperationType::BLOCK)
423 {
424 block_wait_.Start(*op.data.sem_info.sem);
425 }
426 StartDmaDuplex(TOTAL);
427 op.MarkAsRunning();
428 if (op.type == OperationRW::OperationType::BLOCK)
429 {
430 return block_wait_.Wait(op.data.sem_info.timeout);
431 }
432 return ErrorCode::OK;
433 }
434 else
435 {
436 // 轮询
437 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
438 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
439 txp[0] = static_cast<uint8_t>(reg | 0x80);
440 Memory::FastSet(txp + 1, 0x00, N);
441
442 ErrorCode ec = PollingTransfer(rxp, txp, TOTAL);
443 Memory::FastCopy(read_data.addr_, rxp + 1, N);
444
445 SwitchBuffer();
446
447 if (op.type != OperationRW::OperationType::BLOCK)
448 {
449 op.UpdateStatus(in_isr, ec);
450 }
451 return ec;
452 }
453}
ErrorCode PollingTransfer(uint8_t *rx, const uint8_t *tx, uint32_t len)
轮询传输辅助函数 / Polling transfer helper
Definition ch32_spi.cpp:279
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:5
原始数据封装类。 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
ErrorCode
定义错误码枚举
Definition libxr_def.hpp:64
@ BUSY
忙碌 | Busy
@ OK
操作成功 | Operation successful

◆ 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 455 of file ch32_spi.cpp.

457{
458 const uint32_t N = write_data.size_;
459 if (N == 0)
460 {
461 if (op.type != OperationRW::OperationType::BLOCK)
462 {
463 op.UpdateStatus(in_isr, ErrorCode::OK);
464 }
465 return ErrorCode::OK;
466 }
467
468 if (DmaBusy())
469 {
470 return ErrorCode::BUSY;
471 }
472
473 RawData rx = GetRxBuffer();
474 RawData tx = GetTxBuffer();
475 (void)rx; // RX 仅用于丢弃
476
477 ASSERT(tx.size_ >= N + 1);
478
479 const uint32_t TOTAL = N + 1;
480
481 if (TOTAL > dma_enable_min_size_)
482 {
483 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
484 txp[0] = static_cast<uint8_t>(reg & 0x7F);
485 Memory::FastCopy(txp + 1, write_data.addr_, N);
486
487 mem_read_ = false;
488 read_buff_ = {nullptr, 0};
489 rw_op_ = op;
490 busy_ = true;
491
492 if (op.type == OperationRW::OperationType::BLOCK)
493 {
494 block_wait_.Start(*op.data.sem_info.sem);
495 }
496 StartDmaDuplex(TOTAL);
497
498 op.MarkAsRunning();
499 if (op.type == OperationRW::OperationType::BLOCK)
500 {
501 return block_wait_.Wait(op.data.sem_info.timeout);
502 }
503 return ErrorCode::OK;
504 }
505 else
506 {
507 // 轮询
508 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
509 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
510 txp[0] = static_cast<uint8_t>(reg & 0x7F);
511 Memory::FastCopy(txp + 1, write_data.addr_, N);
512
513 ErrorCode ec = PollingTransfer(rxp, txp, TOTAL);
514
515 SwitchBuffer();
516
517 if (op.type != OperationRW::OperationType::BLOCK)
518 {
519 op.UpdateStatus(in_isr, ec);
520 }
521 return ec;
522 }
523}
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 279 of file ch32_spi.cpp.

280{
281 for (uint32_t i = 0; i < len; ++i)
282 {
283 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_TXE) == RESET)
284 {
285 }
286 SPI_I2S_SendData(instance_, tx ? tx[i] : 0x00);
287
288 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_RXNE) == RESET)
289 {
290 }
291 uint16_t d = SPI_I2S_ReceiveData(instance_);
292 if (rx)
293 {
294 rx[i] = static_cast<uint8_t>(d & 0xff);
295 }
296 }
297 return ErrorCode::OK;
298}

◆ PrepareTxBuffer()

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

Definition at line 525 of file ch32_spi.cpp.

527{
528 RawData tx = GetTxBuffer();
529 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
530
531 if (write_data.size_ > 0)
532 {
533 const uint32_t COPY =
534 (write_data.size_ > need_len - prefix) ? (need_len - prefix) : write_data.size_;
535 Memory::FastCopy(txp + prefix, write_data.addr_, COPY);
536 if (prefix + COPY < need_len)
537 {
538 Memory::FastSet(txp + prefix + COPY, dummy, need_len - prefix - COPY);
539 }
540 }
541 else
542 {
543 Memory::FastSet(txp + prefix, dummy, need_len - prefix);
544 }
545}

◆ 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 300 of file ch32_spi.cpp.

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

◆ RxDmaIRQHandler()

void CH32SPI::RxDmaIRQHandler ( )

DMA 中断回调 / DMA interrupt callbacks.

Definition at line 571 of file ch32_spi.cpp.

572{
573 if (DMA_GetITStatus(CH32_SPI_RX_DMA_IT_MAP[id_]) == RESET)
574 {
575 return;
576 }
577
578 DMA_ClearITPendingBit(CH32_SPI_RX_DMA_IT_MAP[id_]);
579
580 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, DISABLE);
581 DMA_Cmd(dma_rx_channel_, DISABLE);
582
583 if (!busy_)
584 {
585 return;
586 }
587
588 // 拷贝读数据(若有)
589 const bool has_user_read_copy = (read_buff_.size_ > 0);
590 if (has_user_read_copy)
591 {
592 RawData rx = GetRxBuffer();
593 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
594 if (mem_read_)
595 {
596 Memory::FastCopy(read_buff_.addr_, rxp + 1, read_buff_.size_);
597 }
598 else
599 {
600 Memory::FastCopy(read_buff_.addr_, rxp, read_buff_.size_);
601 }
602 read_buff_.size_ = 0;
603 }
604
605 // 双缓冲切换与状态更新
606 SwitchBuffer();
607 busy_ = false;
608 if (rw_op_.type == OperationRW::OperationType::BLOCK)
609 {
610 (void)block_wait_.TryPost(true, ErrorCode::OK);
611 }
612 else
613 {
615 }
616}
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:178
OperationType type
Definition libxr_rw.hpp:237

◆ 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 243 of file ch32_spi.cpp.

244{
245 // 1) 把 SPI::Prescaler → CH32 Prescaler 宏
246 uint16_t ch32_presc = 0;
247 if (!MapEnumToCH32Prescaler(config.prescaler, ch32_presc))
248 {
250 }
251
252 // 2) 关 / 复位 / 重新初始化
253 SPI_Cmd(instance_, DISABLE);
254 SPI_I2S_DeInit(instance_);
255
256 SPI_InitTypeDef init = {};
257 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
258 init.SPI_Mode = mode_;
259 init.SPI_DataSize = datasize_;
260 init.SPI_CPOL =
261 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
262 init.SPI_CPHA =
263 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
264 init.SPI_NSS = nss_;
265 init.SPI_BaudRatePrescaler = ch32_presc;
266 init.SPI_FirstBit = firstbit_;
267 init.SPI_CRCPolynomial = 7;
268
269 SPI_Init(instance_, &init);
270 SPI_Cmd(instance_, ENABLE);
271
272 // 3) 同步本地缓存与基类配置(影响 GetBusSpeed/IsDoubleBuffer)
273 prescaler_ = ch32_presc;
274 GetConfig() = config;
275
276 return ErrorCode::OK;
277}
@ NOT_SUPPORT
不支持 | Not supported

◆ StartDmaDuplex()

void CH32SPI::StartDmaDuplex ( uint32_t count)
private

Definition at line 547 of file ch32_spi.cpp.

548{
549 RawData rx = GetRxBuffer();
550 RawData tx = GetTxBuffer();
551
552 dma_rx_channel_->MADDR = reinterpret_cast<uint32_t>(rx.addr_);
553 dma_rx_channel_->CNTR = count;
554
555 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(tx.addr_);
556 dma_tx_channel_->CNTR = count;
557
558 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, ENABLE);
559 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, ENABLE);
560
561 DMA_Cmd(dma_rx_channel_, ENABLE);
562 DMA_Cmd(dma_tx_channel_, ENABLE);
563}

◆ StopDma()

void CH32SPI::StopDma ( )
private

Definition at line 565 of file ch32_spi.cpp.

566{
567 DMA_Cmd(dma_tx_channel_, DISABLE);
568 DMA_Cmd(dma_rx_channel_, DISABLE);
569}

◆ 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 637 of file ch32_spi.cpp.

638{
639 if (DmaBusy())
640 {
641 return ErrorCode::BUSY;
642 }
643
644 if (size == 0)
645 {
646 if (op.type != OperationRW::OperationType::BLOCK)
647 {
648 op.UpdateStatus(in_isr, ErrorCode::OK);
649 }
650 return ErrorCode::OK;
651 }
652
653 RawData rx = GetRxBuffer();
654 RawData tx = GetTxBuffer();
655 ASSERT(rx.size_ >= size);
656 ASSERT(tx.size_ >= size);
657
658 if (size > dma_enable_min_size_)
659 {
660 rw_op_ = op;
661 read_buff_ = {nullptr, 0};
662 mem_read_ = false;
663 busy_ = true;
664
665 if (op.type == OperationRW::OperationType::BLOCK)
666 {
667 block_wait_.Start(*op.data.sem_info.sem);
668 }
669 StartDmaDuplex(static_cast<uint32_t>(size));
670
671 op.MarkAsRunning();
672 if (op.type == OperationRW::OperationType::BLOCK)
673 {
674 return block_wait_.Wait(op.data.sem_info.timeout);
675 }
676 return ErrorCode::OK;
677 }
678
679 // 小包轮询
680 ErrorCode ec =
681 PollingTransfer(static_cast<uint8_t*>(rx.addr_),
682 static_cast<const uint8_t*>(tx.addr_), static_cast<uint32_t>(size));
683
684 SwitchBuffer();
685
686 if (op.type != OperationRW::OperationType::BLOCK)
687 {
688 op.UpdateStatus(in_isr, ec);
689 }
690 return ec;
691}

◆ TxDmaIRQHandler()

void CH32SPI::TxDmaIRQHandler ( )

Definition at line 618 of file ch32_spi.cpp.

619{
620 if (DMA_GetITStatus(CH32_SPI_TX_DMA_IT_MAP[id_]) == RESET)
621 {
622 return;
623 }
624 DMA_ClearITPendingBit(CH32_SPI_TX_DMA_IT_MAP[id_]);
625
626 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, DISABLE);
627 DMA_Cmd(dma_tx_channel_, DISABLE);
628
629 if (!busy_)
630 {
631 return;
632 }
633}

Field Documentation

◆ block_wait_

AsyncBlockWait LibXR::CH32SPI::block_wait_ {}

Definition at line 97 of file ch32_spi.hpp.

97{};

◆ 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: