libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::CH32SPI Class Reference
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})
 
ErrorCode ReadAndWrite (RawData read_data, ConstRawData write_data, OperationRW &op) override
 进行 SPI 读写操作。Performs SPI read and write operations.
 
ErrorCode SetConfig (SPI::Configuration config) override
 设置 SPI 配置参数。Sets SPI configuration parameters.
 
ErrorCode MemRead (uint16_t reg, RawData read_data, OperationRW &op) override
 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
 
ErrorCode MemWrite (uint16_t reg, ConstRawData write_data, OperationRW &op) override
 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
 
ErrorCode Transfer (size_t size, OperationRW &op) 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 ()
 
void TxDmaIRQHandler ()
 
ErrorCode PollingTransfer (uint8_t *rx, const uint8_t *tx, uint32_t len)
 
- Public Member Functions inherited from LibXR::SPI
 SPI (RawData rx_buffer, RawData tx_buffer)
 构造函数。Constructor.
 
virtual ErrorCode Read (RawData read_data, OperationRW &op)
 进行 SPI 读取操作。Performs SPI read operation.
 
virtual ErrorCode Write (ConstRawData write_data, OperationRW &op)
 进行 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_
 
RawData read_buff_
 
bool mem_read_ = false
 
bool busy_ = false
 
uint16_t mode_
 
uint16_t datasize_
 
uint16_t firstbit_
 
uint16_t prescaler_
 
uint16_t nss_ = SPI_NSS_Soft
 
GPIO_TypeDef * sck_port_
 
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

Definition at line 16 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} )

Definition at line 61 of file ch32_spi.cpp.

66 : SPI(dma_rx, dma_tx),
67 instance_(CH32_SPI_GetInstanceID(id)),
68 dma_rx_channel_(CH32_SPI_RX_DMA_CHANNEL_MAP[id]),
69 dma_tx_channel_(CH32_SPI_TX_DMA_CHANNEL_MAP[id]),
70 id_(id),
71 dma_enable_min_size_(dma_enable_min_size),
72 mode_(master_mode ? SPI_Mode_Master : SPI_Mode_Slave),
73 datasize_(SPI_DataSize_8b),
74 firstbit_(firstbit_msb ? SPI_FirstBit_MSB : SPI_FirstBit_LSB),
75 prescaler_(prescaler),
76 sck_port_(sck_port),
77 sck_pin_(sck_pin),
78 miso_port_(miso_port),
79 miso_pin_(miso_pin),
80 mosi_port_(mosi_port),
81 mosi_pin_(mosi_pin)
82{
83 ASSERT(instance_ != nullptr);
84
85 map[id] = this;
86
87 // === 时钟 ===
88 if (CH32_SPI_APB_MAP[id] == 1)
89 {
90 RCC_APB1PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
91 }
92 else if (CH32_SPI_APB_MAP[id] == 2)
93 {
94 RCC_APB2PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
95 }
96 else
97 {
98 ASSERT(false);
99 }
100 RCC_AHBPeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP_DMA[id], ENABLE);
101
102 // === GPIO ===
103 {
104 GPIO_InitTypeDef gpio = {};
105 gpio.GPIO_Speed = GPIO_Speed_50MHz;
106
107 // SCK
108 RCC_APB2PeriphClockCmd(CH32GetGPIOPeriph(sck_port_), ENABLE);
109 if (mode_ == SPI_Mode_Master)
110 {
111 gpio.GPIO_Pin = sck_pin_;
112 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
113 }
114 else
115 {
116 gpio.GPIO_Pin = sck_pin_;
117 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
118 }
119 GPIO_Init(sck_port_, &gpio);
120
121 // MISO
122 RCC_APB2PeriphClockCmd(CH32GetGPIOPeriph(miso_port_), ENABLE);
123 if (mode_ == SPI_Mode_Master)
124 {
125 gpio.GPIO_Pin = miso_pin_;
126 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
127 }
128 else
129 {
130 gpio.GPIO_Pin = miso_pin_;
131 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
132 }
133 GPIO_Init(miso_port_, &gpio);
134
135 // MOSI
136 RCC_APB2PeriphClockCmd(CH32GetGPIOPeriph(mosi_port_), ENABLE);
137 if (mode_ == SPI_Mode_Master)
138 {
139 gpio.GPIO_Pin = mosi_pin_;
140 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
141 }
142 else
143 {
144 gpio.GPIO_Pin = mosi_pin_;
145 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
146 }
147 GPIO_Init(mosi_port_, &gpio);
148
149 if (pin_remap != 0)
150 {
151 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
152 GPIO_PinRemapConfig(pin_remap, ENABLE);
153 }
154 }
155
156 // === SPI 基本配置 ===
157 {
158 SPI_InitTypeDef init = {};
159 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
160 init.SPI_Mode = mode_;
161 init.SPI_DataSize = datasize_;
162 init.SPI_CPOL =
163 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
164 init.SPI_CPHA =
165 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
166 init.SPI_NSS = nss_;
167 init.SPI_BaudRatePrescaler = prescaler_;
168 init.SPI_FirstBit = firstbit_;
169 init.SPI_CRCPolynomial = 7;
170
171 SPI_Init(instance_, &init);
172 SPI_Cmd(instance_, ENABLE);
173 }
174
175 // === DMA 通道基础配置(MADDR/CNTR 运行时再设) ===
176 {
177 // RX
178 {
179 ch32_dma_callback_t cb = [](void* arg)
180 { reinterpret_cast<CH32SPI*>(arg)->RxDmaIRQHandler(); };
181 CH32_DMA_RegisterCallback(CH32_DMA_GetID(dma_rx_channel_), cb, this);
182
183 DMA_InitTypeDef di = {};
184 DMA_DeInit(dma_rx_channel_);
185 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
186 di.DMA_MemoryBaseAddr = (uint32_t)dma_rx.addr_;
187 di.DMA_DIR = DMA_DIR_PeripheralSRC;
188 di.DMA_BufferSize = 0;
189 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
190 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
191 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
192 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
193 di.DMA_Mode = DMA_Mode_Normal;
194 di.DMA_Priority = DMA_Priority_High;
195 di.DMA_M2M = DMA_M2M_Disable;
196 DMA_Init(dma_rx_channel_, &di);
197 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
198 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[CH32_DMA_GetID(dma_rx_channel_)]);
199 }
200 // TX
201 {
202 ch32_dma_callback_t cb = [](void* arg)
203 { reinterpret_cast<CH32SPI*>(arg)->TxDmaIRQHandler(); };
204 CH32_DMA_RegisterCallback(CH32_DMA_GetID(dma_tx_channel_), cb, this);
205
206 DMA_InitTypeDef di = {};
207 DMA_DeInit(dma_tx_channel_);
208 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
209 di.DMA_MemoryBaseAddr = 0;
210 di.DMA_DIR = DMA_DIR_PeripheralDST;
211 di.DMA_BufferSize = 0;
212 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
213 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
214 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
215 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
216 di.DMA_Mode = DMA_Mode_Normal;
217 di.DMA_Priority = DMA_Priority_VeryHigh;
218 di.DMA_M2M = DMA_M2M_Disable;
219 DMA_Init(dma_tx_channel_, &di);
220 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
221 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[CH32_DMA_GetID(dma_tx_channel_)]);
222 }
223 }
224
225 // === 同步基类配置用于速率查询 ===
226 GetConfig() = config;
227 GetConfig().prescaler = MapCH32PrescalerToEnum(prescaler_);
228}
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:388
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 47 of file ch32_spi.hpp.

48 {
49 return (dma_rx_channel_->CNTR != 0) || (dma_tx_channel_->CNTR != 0) || busy_;
50 }

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

604{
605 RCC_ClocksTypeDef clocks{};
606 RCC_GetClocksFreq(&clocks);
607
608 if (CH32_SPI_APB_MAP[id_] == 2)
609 {
610 return clocks.PCLK2_Frequency;
611 }
612 else if (CH32_SPI_APB_MAP[id_] == 1)
613 {
614 return clocks.PCLK1_Frequency;
615 }
616 return 0u;
617}

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

621{
622#if defined(SPI_BaudRatePrescaler_1024)
624#elif defined(SPI_BaudRatePrescaler_512)
626#elif defined(SPI_BaudRatePrescaler_256)
628#elif defined(SPI_BaudRatePrescaler_128)
630#elif defined(SPI_BaudRatePrescaler_64)
632#elif defined(SPI_BaudRatePrescaler_32)
634#elif defined(SPI_BaudRatePrescaler_16)
636#elif defined(SPI_BaudRatePrescaler_8)
638#elif defined(SPI_BaudRatePrescaler_4)
640#elif defined(SPI_BaudRatePrescaler_2)
642#else
644#endif
645}
@ 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 647 of file ch32_spi.cpp.

648{
649 switch (p)
650 {
651#if defined(SPI_BaudRatePrescaler_2)
652 case SPI_BaudRatePrescaler_2:
654#endif
655#if defined(SPI_BaudRatePrescaler_4)
656 case SPI_BaudRatePrescaler_4:
658#endif
659#if defined(SPI_BaudRatePrescaler_8)
660 case SPI_BaudRatePrescaler_8:
662#endif
663#if defined(SPI_BaudRatePrescaler_16)
664 case SPI_BaudRatePrescaler_16:
666#endif
667#if defined(SPI_BaudRatePrescaler_32)
668 case SPI_BaudRatePrescaler_32:
670#endif
671#if defined(SPI_BaudRatePrescaler_64)
672 case SPI_BaudRatePrescaler_64:
674#endif
675#if defined(SPI_BaudRatePrescaler_128)
676 case SPI_BaudRatePrescaler_128:
678#endif
679#if defined(SPI_BaudRatePrescaler_256)
680 case SPI_BaudRatePrescaler_256:
682#endif
683 default:
685 }
686}

◆ MapEnumToCH32Prescaler()

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

Definition at line 12 of file ch32_spi.cpp.

13{
14 switch (p)
15 {
16#if defined(SPI_BaudRatePrescaler_2)
18 out = SPI_BaudRatePrescaler_2;
19 return true;
20#endif
21#if defined(SPI_BaudRatePrescaler_4)
23 out = SPI_BaudRatePrescaler_4;
24 return true;
25#endif
26#if defined(SPI_BaudRatePrescaler_8)
28 out = SPI_BaudRatePrescaler_8;
29 return true;
30#endif
31#if defined(SPI_BaudRatePrescaler_16)
33 out = SPI_BaudRatePrescaler_16;
34 return true;
35#endif
36#if defined(SPI_BaudRatePrescaler_32)
38 out = SPI_BaudRatePrescaler_32;
39 return true;
40#endif
41#if defined(SPI_BaudRatePrescaler_64)
43 out = SPI_BaudRatePrescaler_64;
44 return true;
45#endif
46#if defined(SPI_BaudRatePrescaler_128)
48 out = SPI_BaudRatePrescaler_128;
49 return true;
50#endif
51#if defined(SPI_BaudRatePrescaler_256)
53 out = SPI_BaudRatePrescaler_256;
54 return true;
55#endif
56 default:
57 return false; // 不支持 DIV_1 或 >256 的枚举
58 }
59}

◆ MemRead()

ErrorCode CH32SPI::MemRead ( uint16_t reg,
RawData read_data,
OperationRW & op )
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).
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 356 of file ch32_spi.cpp.

357{
358 const uint32_t n = read_data.size_;
359 if (n == 0)
360 {
361 if (op.type != OperationRW::OperationType::BLOCK)
362 op.UpdateStatus(false, ErrorCode::OK);
363 return ErrorCode::OK;
364 }
365
366 if (DmaBusy()) return ErrorCode::BUSY;
367
368 RawData rx = GetRxBuffer();
369 RawData tx = GetTxBuffer();
370
371 ASSERT(rx.size_ >= n + 1);
372 ASSERT(tx.size_ >= n + 1);
373
374 const uint32_t total = n + 1;
375
376 if (total > dma_enable_min_size_)
377 {
378 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
379 txp[0] = static_cast<uint8_t>(reg | 0x80);
380 memset(txp + 1, 0x00, n);
381
382 mem_read_ = true;
383 read_buff_ = read_data;
384 rw_op_ = op;
385 busy_ = true;
386
387 StartDmaDuplex(total);
388
389 op.MarkAsRunning();
390 if (op.type == OperationRW::OperationType::BLOCK)
391 {
392 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
393 }
394 return ErrorCode::OK;
395 }
396 else
397 {
398 // 轮询
399 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
400 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
401 txp[0] = static_cast<uint8_t>(reg | 0x80);
402 memset(txp + 1, 0x00, n);
403
404 ErrorCode ec = PollingTransfer(rxp, txp, total);
405 memcpy(read_data.addr_, rxp + 1, n);
406
407 SwitchBuffer();
408
409 if (op.type != OperationRW::OperationType::BLOCK) op.UpdateStatus(false, ec);
410 return ec;
411 }
412}
原始数据封装类。 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:303
void SwitchBuffer()
切换缓冲区。Switches the buffer.
Definition spi.hpp:334
RawData GetTxBuffer()
获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
Definition spi.hpp:319

◆ MemWrite()

ErrorCode CH32SPI::MemWrite ( uint16_t reg,
ConstRawData write_data,
OperationRW & op )
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).
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 414 of file ch32_spi.cpp.

415{
416 const uint32_t n = write_data.size_;
417 if (n == 0)
418 {
419 if (op.type != OperationRW::OperationType::BLOCK)
420 op.UpdateStatus(false, ErrorCode::OK);
421 return ErrorCode::OK;
422 }
423
424 if (DmaBusy()) return ErrorCode::BUSY;
425
426 RawData rx = GetRxBuffer();
427 RawData tx = GetTxBuffer();
428 (void)rx; // RX 仅用于丢弃
429
430 ASSERT(tx.size_ >= n + 1);
431
432 const uint32_t total = n + 1;
433
434 if (total > dma_enable_min_size_)
435 {
436 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
437 txp[0] = static_cast<uint8_t>(reg & 0x7F);
438 memcpy(txp + 1, write_data.addr_, n);
439
440 mem_read_ = false;
441 read_buff_ = {nullptr, 0};
442 rw_op_ = op;
443 busy_ = true;
444
445 StartDmaDuplex(total);
446
447 op.MarkAsRunning();
448 if (op.type == OperationRW::OperationType::BLOCK)
449 {
450 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
451 }
452 return ErrorCode::OK;
453 }
454 else
455 {
456 // 轮询
457 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
458 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
459 txp[0] = static_cast<uint8_t>(reg & 0x7F);
460 memcpy(txp + 1, write_data.addr_, n);
461
462 ErrorCode ec = PollingTransfer(rxp, txp, total);
463
464 SwitchBuffer();
465
466 if (op.type != OperationRW::OperationType::BLOCK) op.UpdateStatus(false, ec);
467 return ec;
468 }
469}
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 )

Definition at line 267 of file ch32_spi.cpp.

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

◆ PrepareTxBuffer()

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

Definition at line 471 of file ch32_spi.cpp.

473{
474 RawData tx = GetTxBuffer();
475 uint8_t* txp = static_cast<uint8_t*>(tx.addr_);
476
477 if (write_data.size_ > 0)
478 {
479 const uint32_t copy =
480 (write_data.size_ > need_len - prefix) ? (need_len - prefix) : write_data.size_;
481 memcpy(txp + prefix, write_data.addr_, copy);
482 if (prefix + copy < need_len)
483 {
484 memset(txp + prefix + copy, dummy, need_len - prefix - copy);
485 }
486 }
487 else
488 {
489 memset(txp + prefix, dummy, need_len - prefix);
490 }
491}

◆ ReadAndWrite()

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

进行 SPI 读写操作。Performs SPI read and write operations.

Parameters
read_data存储读取数据的缓冲区。Buffer to store the read data.
write_data需要写入的数据缓冲区。Buffer containing the data to be written.
op读写操作类型。Type of read/write operation.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 285 of file ch32_spi.cpp.

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

◆ RxDmaIRQHandler()

void CH32SPI::RxDmaIRQHandler ( )

Definition at line 517 of file ch32_spi.cpp.

518{
519 if (DMA_GetITStatus(CH32_SPI_RX_DMA_IT_MAP[id_]) == RESET) return;
520
521 DMA_ClearITPendingBit(CH32_SPI_RX_DMA_IT_MAP[id_]);
522
523 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, DISABLE);
524 DMA_Cmd(dma_rx_channel_, DISABLE);
525
526 // 拷贝读数据(若有)
527 if (read_buff_.size_ > 0)
528 {
529 RawData rx = GetRxBuffer();
530 uint8_t* rxp = static_cast<uint8_t*>(rx.addr_);
531 if (mem_read_)
532 {
533 memcpy(read_buff_.addr_, rxp + 1, read_buff_.size_);
534 }
535 else
536 {
537 memcpy(read_buff_.addr_, rxp, read_buff_.size_);
538 }
539 read_buff_.size_ = 0;
540 }
541
542 // 双缓冲切换与状态更新
543 SwitchBuffer();
544 busy_ = false;
545 rw_op_.UpdateStatus(true, ErrorCode::OK);
546}
void UpdateStatus(bool in_isr, Status &&...status)
Updates operation status based on type.
Definition libxr_rw.hpp:171

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

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

◆ StartDmaDuplex()

void CH32SPI::StartDmaDuplex ( uint32_t count)
private

Definition at line 493 of file ch32_spi.cpp.

494{
495 RawData rx = GetRxBuffer();
496 RawData tx = GetTxBuffer();
497
498 dma_rx_channel_->MADDR = reinterpret_cast<uint32_t>(rx.addr_);
499 dma_rx_channel_->CNTR = count;
500
501 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(tx.addr_);
502 dma_tx_channel_->CNTR = count;
503
504 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, ENABLE);
505 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, ENABLE);
506
507 DMA_Cmd(dma_rx_channel_, ENABLE);
508 DMA_Cmd(dma_tx_channel_, ENABLE);
509}

◆ StopDma()

void CH32SPI::StopDma ( )
private

Definition at line 511 of file ch32_spi.cpp.

512{
513 DMA_Cmd(dma_tx_channel_, DISABLE);
514 DMA_Cmd(dma_rx_channel_, DISABLE);
515}

◆ Transfer()

ErrorCode CH32SPI::Transfer ( size_t size,
OperationRW & op )
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.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 558 of file ch32_spi.cpp.

559{
560 if (DmaBusy()) return ErrorCode::BUSY;
561
562 if (size == 0)
563 {
564 if (op.type != OperationRW::OperationType::BLOCK)
565 op.UpdateStatus(false, ErrorCode::OK);
566 return ErrorCode::OK;
567 }
568
569 RawData rx = GetRxBuffer();
570 RawData tx = GetTxBuffer();
571 ASSERT(rx.size_ >= size);
572 ASSERT(tx.size_ >= size);
573
574 if (size > dma_enable_min_size_)
575 {
576 rw_op_ = op;
577 read_buff_ = {nullptr, 0};
578 mem_read_ = false;
579 busy_ = true;
580
581 StartDmaDuplex(static_cast<uint32_t>(size));
582
583 op.MarkAsRunning();
584 if (op.type == OperationRW::OperationType::BLOCK)
585 {
586 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
587 }
588 return ErrorCode::OK;
589 }
590
591 // 小包轮询
592 ErrorCode ec =
593 PollingTransfer(static_cast<uint8_t*>(rx.addr_),
594 static_cast<const uint8_t*>(tx.addr_), static_cast<uint32_t>(size));
595
596 SwitchBuffer();
597
598 if (op.type != OperationRW::OperationType::BLOCK) op.UpdateStatus(false, ec);
599 return ec;
600}

◆ TxDmaIRQHandler()

void CH32SPI::TxDmaIRQHandler ( )

Definition at line 548 of file ch32_spi.cpp.

549{
550 if (DMA_GetITStatus(CH32_SPI_TX_DMA_IT_MAP[id_]) == RESET) return;
551 DMA_ClearITPendingBit(CH32_SPI_TX_DMA_IT_MAP[id_]);
552
553 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, DISABLE);
554 DMA_Cmd(dma_tx_channel_, DISABLE);
555}

Field Documentation

◆ busy_

bool LibXR::CH32SPI::busy_ = false

Definition at line 72 of file ch32_spi.hpp.

◆ datasize_

uint16_t LibXR::CH32SPI::datasize_

Definition at line 76 of file ch32_spi.hpp.

◆ dma_enable_min_size_

uint32_t LibXR::CH32SPI::dma_enable_min_size_

Definition at line 66 of file ch32_spi.hpp.

◆ dma_rx_channel_

DMA_Channel_TypeDef* LibXR::CH32SPI::dma_rx_channel_

Definition at line 63 of file ch32_spi.hpp.

◆ dma_tx_channel_

DMA_Channel_TypeDef* LibXR::CH32SPI::dma_tx_channel_

Definition at line 64 of file ch32_spi.hpp.

◆ firstbit_

uint16_t LibXR::CH32SPI::firstbit_

Definition at line 77 of file ch32_spi.hpp.

◆ id_

ch32_spi_id_t LibXR::CH32SPI::id_

Definition at line 65 of file ch32_spi.hpp.

◆ instance_

SPI_TypeDef* LibXR::CH32SPI::instance_

Definition at line 62 of file ch32_spi.hpp.

◆ map

CH32SPI * CH32SPI::map = {nullptr}
static

Definition at line 44 of file ch32_spi.hpp.

◆ mem_read_

bool LibXR::CH32SPI::mem_read_ = false

Definition at line 71 of file ch32_spi.hpp.

◆ miso_pin_

uint16_t LibXR::CH32SPI::miso_pin_

Definition at line 85 of file ch32_spi.hpp.

◆ miso_port_

GPIO_TypeDef* LibXR::CH32SPI::miso_port_

Definition at line 84 of file ch32_spi.hpp.

◆ mode_

uint16_t LibXR::CH32SPI::mode_

Definition at line 75 of file ch32_spi.hpp.

◆ mosi_pin_

uint16_t LibXR::CH32SPI::mosi_pin_

Definition at line 87 of file ch32_spi.hpp.

◆ mosi_port_

GPIO_TypeDef* LibXR::CH32SPI::mosi_port_

Definition at line 86 of file ch32_spi.hpp.

◆ nss_

uint16_t LibXR::CH32SPI::nss_ = SPI_NSS_Soft

Definition at line 79 of file ch32_spi.hpp.

◆ prescaler_

uint16_t LibXR::CH32SPI::prescaler_

Definition at line 78 of file ch32_spi.hpp.

◆ read_buff_

RawData LibXR::CH32SPI::read_buff_

Definition at line 70 of file ch32_spi.hpp.

◆ rw_op_

OperationRW LibXR::CH32SPI::rw_op_

Definition at line 69 of file ch32_spi.hpp.

◆ sck_pin_

uint16_t LibXR::CH32SPI::sck_pin_

Definition at line 83 of file ch32_spi.hpp.

◆ sck_port_

GPIO_TypeDef* LibXR::CH32SPI::sck_port_

Definition at line 82 of file ch32_spi.hpp.


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