7#include "ch32_gpio.hpp"
11CH32SPI* CH32SPI::map_[CH32_SPI_NUMBER] = {
nullptr};
13bool CH32SPI::MapEnumToCH32Prescaler(
SPI::Prescaler p, uint16_t& out)
17#if defined(SPI_BaudRatePrescaler_2)
19 out = SPI_BaudRatePrescaler_2;
22#if defined(SPI_BaudRatePrescaler_4)
24 out = SPI_BaudRatePrescaler_4;
27#if defined(SPI_BaudRatePrescaler_8)
29 out = SPI_BaudRatePrescaler_8;
32#if defined(SPI_BaudRatePrescaler_16)
34 out = SPI_BaudRatePrescaler_16;
37#if defined(SPI_BaudRatePrescaler_32)
39 out = SPI_BaudRatePrescaler_32;
42#if defined(SPI_BaudRatePrescaler_64)
44 out = SPI_BaudRatePrescaler_64;
47#if defined(SPI_BaudRatePrescaler_128)
49 out = SPI_BaudRatePrescaler_128;
52#if defined(SPI_BaudRatePrescaler_256)
54 out = SPI_BaudRatePrescaler_256;
63 uint16_t sck_pin, GPIO_TypeDef* miso_port, uint16_t miso_pin,
64 GPIO_TypeDef* mosi_port, uint16_t mosi_pin, uint32_t pin_remap,
65 bool master_mode,
bool firstbit_msb, uint16_t prescaler,
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]),
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),
79 miso_port_(miso_port),
81 mosi_port_(mosi_port),
84 ASSERT(instance_ !=
nullptr);
89 if (CH32_SPI_APB_MAP[
id] == 1)
91 RCC_APB1PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[
id], ENABLE);
93 else if (CH32_SPI_APB_MAP[
id] == 2)
95 RCC_APB2PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[
id], ENABLE);
101 RCC_AHBPeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP_DMA[
id], ENABLE);
105 GPIO_InitTypeDef gpio = {};
106 gpio.GPIO_Speed = GPIO_Speed_50MHz;
109 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(
sck_port_), ENABLE);
110 if (
mode_ == SPI_Mode_Master)
112 gpio.GPIO_Pin = sck_pin_;
113 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
117 gpio.GPIO_Pin = sck_pin_;
118 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
123 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(miso_port_), ENABLE);
124 if (
mode_ == SPI_Mode_Master)
126 gpio.GPIO_Pin = miso_pin_;
127 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
131 gpio.GPIO_Pin = miso_pin_;
132 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
134 GPIO_Init(miso_port_, &gpio);
137 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(mosi_port_), ENABLE);
138 if (
mode_ == SPI_Mode_Master)
140 gpio.GPIO_Pin = mosi_pin_;
141 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
145 gpio.GPIO_Pin = mosi_pin_;
146 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
148 GPIO_Init(mosi_port_, &gpio);
152 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
153 GPIO_PinRemapConfig(pin_remap, ENABLE);
159 SPI_InitTypeDef init = {};
160 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
161 init.SPI_Mode =
mode_;
170 init.SPI_CRCPolynomial = 7;
172 SPI_Init(instance_, &init);
173 SPI_Cmd(instance_, ENABLE);
180 ch32_dma_callback_t cb = [](
void* arg)
182 ch32_dma_register_callback(ch32_dma_get_id(dma_rx_channel_), cb,
this);
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_)]);
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);
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_)]);
235 uint16_t ch32_presc = 0;
236 if (!MapEnumToCH32Prescaler(config.
prescaler, ch32_presc))
238 return ErrorCode::NOT_SUPPORT;
242 SPI_Cmd(instance_, DISABLE);
243 SPI_I2S_DeInit(instance_);
245 SPI_InitTypeDef init = {};
246 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
247 init.SPI_Mode =
mode_;
254 init.SPI_BaudRatePrescaler = ch32_presc;
256 init.SPI_CRCPolynomial = 7;
258 SPI_Init(instance_, &init);
259 SPI_Cmd(instance_, ENABLE);
265 return ErrorCode::OK;
270 for (uint32_t i = 0; i < len; ++i)
272 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_TXE) == RESET)
275 SPI_I2S_SendData(instance_, tx ? tx[i] : 0x00);
277 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_RXNE) == RESET)
280 uint16_t d = SPI_I2S_ReceiveData(instance_);
283 rx[i] =
static_cast<uint8_t
>(d & 0xff);
286 return ErrorCode::OK;
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;
298 if (op.
type != OperationRW::OperationType::BLOCK)
302 return ErrorCode::OK;
307 return ErrorCode::BUSY;
313 ASSERT(rx.
size_ >= NEED);
314 ASSERT(tx.
size_ >= NEED);
316 if (NEED > dma_enable_min_size_)
319 read_buff_ = read_data;
323 PrepareTxBuffer(write_data, NEED);
325 StartDmaDuplex(NEED);
328 if (op.
type == OperationRW::OperationType::BLOCK)
330 return op.
data.sem_info.sem->
Wait(op.
data.sem_info.timeout);
332 return ErrorCode::OK;
337 uint8_t* rxp =
static_cast<uint8_t*
>(rx.
addr_);
338 uint8_t* txp =
static_cast<uint8_t*
>(tx.
addr_);
363 if (op.
type != OperationRW::OperationType::BLOCK)
373 const uint32_t N = read_data.
size_;
376 if (op.
type != OperationRW::OperationType::BLOCK)
380 return ErrorCode::OK;
385 return ErrorCode::BUSY;
391 ASSERT(rx.
size_ >= N + 1);
392 ASSERT(tx.
size_ >= N + 1);
394 const uint32_t TOTAL = N + 1;
396 if (TOTAL > dma_enable_min_size_)
398 uint8_t* txp =
static_cast<uint8_t*
>(tx.
addr_);
399 txp[0] =
static_cast<uint8_t
>(reg | 0x80);
403 read_buff_ = read_data;
407 StartDmaDuplex(TOTAL);
410 if (op.
type == OperationRW::OperationType::BLOCK)
412 return op.
data.sem_info.sem->
Wait(op.
data.sem_info.timeout);
414 return ErrorCode::OK;
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);
429 if (op.
type != OperationRW::OperationType::BLOCK)
440 const uint32_t N = write_data.
size_;
443 if (op.
type != OperationRW::OperationType::BLOCK)
447 return ErrorCode::OK;
452 return ErrorCode::BUSY;
459 ASSERT(tx.
size_ >= N + 1);
461 const uint32_t TOTAL = N + 1;
463 if (TOTAL > dma_enable_min_size_)
465 uint8_t* txp =
static_cast<uint8_t*
>(tx.
addr_);
466 txp[0] =
static_cast<uint8_t
>(reg & 0x7F);
470 read_buff_ = {
nullptr, 0};
474 StartDmaDuplex(TOTAL);
477 if (op.
type == OperationRW::OperationType::BLOCK)
479 return op.
data.sem_info.sem->
Wait(op.
data.sem_info.timeout);
481 return ErrorCode::OK;
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);
495 if (op.
type != OperationRW::OperationType::BLOCK)
503void CH32SPI::PrepareTxBuffer(
ConstRawData write_data, uint32_t need_len, uint32_t prefix,
507 uint8_t* txp =
static_cast<uint8_t*
>(tx.
addr_);
509 if (write_data.
size_ > 0)
511 const uint32_t COPY =
512 (write_data.
size_ > need_len - prefix) ? (need_len - prefix) : write_data.
size_;
514 if (prefix + COPY < need_len)
525void CH32SPI::StartDmaDuplex(uint32_t count)
530 dma_rx_channel_->MADDR =
reinterpret_cast<uint32_t
>(rx.
addr_);
531 dma_rx_channel_->CNTR = count;
533 dma_tx_channel_->MADDR =
reinterpret_cast<uint32_t
>(tx.
addr_);
534 dma_tx_channel_->CNTR = count;
536 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, ENABLE);
537 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, ENABLE);
539 DMA_Cmd(dma_rx_channel_, ENABLE);
540 DMA_Cmd(dma_tx_channel_, ENABLE);
543void CH32SPI::StopDma()
545 DMA_Cmd(dma_tx_channel_, DISABLE);
546 DMA_Cmd(dma_rx_channel_, DISABLE);
551 if (DMA_GetITStatus(CH32_SPI_RX_DMA_IT_MAP[id_]) == RESET)
556 DMA_ClearITPendingBit(CH32_SPI_RX_DMA_IT_MAP[id_]);
558 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, DISABLE);
559 DMA_Cmd(dma_rx_channel_, DISABLE);
562 if (read_buff_.
size_ > 0)
565 uint8_t* rxp =
static_cast<uint8_t*
>(rx.
addr_);
574 read_buff_.
size_ = 0;
583void CH32SPI::TxDmaIRQHandler()
585 if (DMA_GetITStatus(CH32_SPI_TX_DMA_IT_MAP[id_]) == RESET)
589 DMA_ClearITPendingBit(CH32_SPI_TX_DMA_IT_MAP[id_]);
591 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, DISABLE);
592 DMA_Cmd(dma_tx_channel_, DISABLE);
600 return ErrorCode::BUSY;
605 if (op.
type != OperationRW::OperationType::BLOCK)
609 return ErrorCode::OK;
614 ASSERT(rx.
size_ >= size);
615 ASSERT(tx.
size_ >= size);
617 if (size > dma_enable_min_size_)
620 read_buff_ = {
nullptr, 0};
624 StartDmaDuplex(
static_cast<uint32_t
>(size));
627 if (op.
type == OperationRW::OperationType::BLOCK)
629 return op.
data.sem_info.sem->
Wait(op.
data.sem_info.timeout);
631 return ErrorCode::OK;
637 static_cast<const uint8_t*
>(tx.
addr_),
static_cast<uint32_t
>(size));
641 if (op.
type != OperationRW::OperationType::BLOCK)
651 RCC_ClocksTypeDef clocks{};
652 RCC_GetClocksFreq(&clocks);
654 if (CH32_SPI_APB_MAP[id_] == 2)
656 return clocks.PCLK2_Frequency;
658 else if (CH32_SPI_APB_MAP[id_] == 1)
660 return clocks.PCLK1_Frequency;
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)
697#if defined(SPI_BaudRatePrescaler_2)
698 case SPI_BaudRatePrescaler_2:
701#if defined(SPI_BaudRatePrescaler_4)
702 case SPI_BaudRatePrescaler_4:
705#if defined(SPI_BaudRatePrescaler_8)
706 case SPI_BaudRatePrescaler_8:
709#if defined(SPI_BaudRatePrescaler_16)
710 case SPI_BaudRatePrescaler_16:
713#if defined(SPI_BaudRatePrescaler_32)
714 case SPI_BaudRatePrescaler_32:
717#if defined(SPI_BaudRatePrescaler_64)
718 case SPI_BaudRatePrescaler_64:
721#if defined(SPI_BaudRatePrescaler_128)
722 case SPI_BaudRatePrescaler_128:
725#if defined(SPI_BaudRatePrescaler_256)
726 case SPI_BaudRatePrescaler_256:
CH32 SPI 驱动实现 / CH32 SPI driver implementation.
void RxDmaIRQHandler()
DMA 中断回调 / DMA interrupt callbacks.
ErrorCode PollingTransfer(uint8_t *rx, const uint8_t *tx, uint32_t len)
轮询传输辅助函数 / Polling transfer helper
OperationRW rw_op_
运行时状态 / Runtime state
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 SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
SPI::Prescaler GetMaxPrescaler() const override
获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.
ErrorCode ReadAndWrite(RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr) override
SPI 接口实现 / SPI interface overrides.
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.
uint32_t GetMaxBusSpeed() const override
获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.
uint16_t mode_
SPI 寄存器配置缓存 / Cached SPI register configuration.
uint16_t prescaler_
SPI_BaudRatePrescaler_x.
uint16_t datasize_
SPI_DataSize_8b by default.
uint16_t firstbit_
SPI_FirstBit_MSB / SPI_FirstBit_LSB.
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 Transfer(size_t size, OperationRW &op, bool in_isr) override
进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).
GPIO_TypeDef * sck_port_
GPIO 配置 / GPIO configuration.
常量原始数据封装类。 A class for encapsulating constant raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).
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
union LibXR::Operation::@5 data
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
串行外设接口(SPI)抽象类。Abstract class for Serial Peripheral Interface (SPI).
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
@ 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.
RawData GetRxBuffer()
获取接收数据的缓冲区。Gets the buffer for storing received data.
void SwitchBuffer()
切换缓冲区。Switches the buffer.
RawData GetTxBuffer()
获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
@ LOW
时钟空闲时为低电平。Clock idle low.
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
存储 SPI 配置参数的结构体。Structure for storing SPI configuration parameters.
ClockPhase clock_phase
SPI 时钟相位。SPI clock phase.
Prescaler prescaler
SPI 分频系数。SPI prescaler.
ClockPolarity clock_polarity
SPI 时钟极性。SPI clock polarity.