libxr
Embedded C++ framework for bare-metal, RTOS and Linux
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.
 
Configuration & GetConfig ()
 获取 SPI 配置参数 / Gets the SPI configuration parameters.
 
bool IsDoubleBuffer () const
 检查是否使用双缓冲区 / Checks if double buffering is enabled.
 

Public Attributes

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 CH32SPI * map_ [CH32_SPI_NUMBER] = {nullptr}
 

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::LOW, SPI::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 DEV_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_
数据起始地址 / Data start address
@ EDGE_1
在第一个时钟边沿采样数据 / Data sampled on the first clock edge.
SPI(RawData rx_buffer, RawData tx_buffer)
构造函数 / Constructor.
Definition spi.hpp:111
@ LOW
时钟空闲时为低电平 / Clock idle low.
Configuration & GetConfig()
获取 SPI 配置参数 / Gets the SPI configuration parameters.
Definition spi.hpp:397
ClockPhase clock_phase
SPI 时钟相位 / SPI clock phase.
Definition spi.hpp:89
Prescaler prescaler
SPI 分频系数 / SPI prescaler.
Definition spi.hpp:90
ClockPolarity clock_polarity
SPI 时钟极性 / SPI clock polarity.
Definition spi.hpp:87

Member Function Documentation

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

◆ 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}
void Start(Semaphore &sem)
绑定信号量并开始等待 / Bind a semaphore and start waiting.
ErrorCode Wait(uint32_t timeout)
等待完成或超时交接 / Wait for completion or a timeout handoff.
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
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
RawData GetRxBuffer()
获取接收数据的缓冲区 / Gets the buffer for storing received data.
Definition spi.hpp:307
void SwitchBuffer()
切换缓冲区 / Switches the buffer.
Definition spi.hpp:338
RawData GetTxBuffer()
获取发送数据的缓冲区 / Gets the buffer for storing data to be sent.
Definition spi.hpp:323
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ 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_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address

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

◆ 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}
bool TryPost(bool in_isr, ErrorCode ec)
尝试认领完成并唤醒调用者 / Try to claim completion and wake the caller.
void UpdateStatus(bool in_isr, Status &&status)
按通知方式报告完成结果 / Report completion using the selected mode.
OperationType type
当前通知方式 / Current notification mode.

◆ 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

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

Member Data 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: