libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_spi.cpp
1#include "ch32_spi.hpp"
2
3#include <cstring>
4
5#include "ch32_dma.hpp"
6#include "ch32_gpio.hpp"
7
8using namespace LibXR;
9
10CH32SPI *CH32SPI::map[ch32_spi_id_t::CH32_SPI_NUMBER] = {nullptr};
11
12CH32SPI::CH32SPI(ch32_spi_id_t id, RawData dma_rx, RawData dma_tx, GPIO_TypeDef *sck_port,
13 uint16_t sck_pin, GPIO_TypeDef *miso_port, uint16_t miso_pin,
14 GPIO_TypeDef *mosi_port, uint16_t mosi_pin, uint32_t pin_remap,
15 bool master_mode, bool firstbit_msb, uint16_t prescaler,
16 uint32_t dma_enable_min_size, SPI::Configuration config)
17 : SPI(),
18 dma_buff_rx_(dma_rx),
19 dma_buff_tx_(dma_tx),
20 instance_(CH32_SPI_GetInstanceID(id)),
21 dma_rx_channel_(CH32_SPI_RX_DMA_CHANNEL_MAP[id]),
22 dma_tx_channel_(CH32_SPI_TX_DMA_CHANNEL_MAP[id]),
23 id_(id),
24 dma_enable_min_size_(dma_enable_min_size),
25 mode_(master_mode ? SPI_Mode_Master : SPI_Mode_Slave),
26 datasize_(SPI_DataSize_8b),
27 firstbit_(firstbit_msb ? SPI_FirstBit_MSB : SPI_FirstBit_LSB),
28 prescaler_(prescaler),
29 sck_port_(sck_port),
30 sck_pin_(sck_pin),
31 miso_port_(miso_port),
32 miso_pin_(miso_pin),
33 mosi_port_(mosi_port),
34 mosi_pin_(mosi_pin)
35{
36 ASSERT(instance_ != nullptr);
37 ASSERT(dma_buff_tx_.size_ >= 1);
38 // 读至少给 1 字节,便于 MemRead 的“命令 + N 字节” DMA 长度
39 ASSERT(dma_buff_rx_.size_ >= 1);
40
41 map[id] = this;
42
43 // === 时钟 ===
44 if (CH32_SPI_APB_MAP[id] == 1)
45 {
46 RCC_APB1PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
47 }
48 else if (CH32_SPI_APB_MAP[id] == 2)
49 {
50 RCC_APB2PeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP[id], ENABLE);
51 }
52 else
53 {
54 ASSERT(false);
55 }
56 RCC_AHBPeriphClockCmd(CH32_SPI_RCC_PERIPH_MAP_DMA[id], ENABLE);
57
58 // === GPIO ===
59 {
60 GPIO_InitTypeDef gpio = {};
61 gpio.GPIO_Speed = GPIO_Speed_50MHz;
62
63 // SCK
64 RCC_APB2PeriphClockCmd(CH32GetGPIOPeriph(sck_port_), ENABLE);
65 if (mode_ == SPI_Mode_Master)
66 {
67 gpio.GPIO_Pin = sck_pin_;
68 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
69 }
70 else
71 {
72 gpio.GPIO_Pin = sck_pin_;
73 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
74 }
75 GPIO_Init(sck_port_, &gpio);
76
77 // MISO
78 RCC_APB2PeriphClockCmd(CH32GetGPIOPeriph(miso_port_), ENABLE);
79 if (mode_ == SPI_Mode_Master)
80 {
81 gpio.GPIO_Pin = miso_pin_;
82 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
83 }
84 else
85 {
86 gpio.GPIO_Pin = miso_pin_;
87 gpio.GPIO_Mode = GPIO_Mode_AF_PP; // 从机输出
88 }
89 GPIO_Init(miso_port_, &gpio);
90
91 // MOSI
92 RCC_APB2PeriphClockCmd(CH32GetGPIOPeriph(mosi_port_), ENABLE);
93 if (mode_ == SPI_Mode_Master)
94 {
95 gpio.GPIO_Pin = mosi_pin_;
96 gpio.GPIO_Mode = GPIO_Mode_AF_PP;
97 }
98 else
99 {
100 gpio.GPIO_Pin = mosi_pin_;
101 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
102 }
103 GPIO_Init(mosi_port_, &gpio);
104
105 if (pin_remap != 0)
106 {
107 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
108 GPIO_PinRemapConfig(pin_remap, ENABLE);
109 }
110 }
111
112 // === SPI 基本配置 ===
113 {
114 SPI_InitTypeDef init = {};
115 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
116 init.SPI_Mode = mode_;
117 init.SPI_DataSize = datasize_;
118 init.SPI_CPOL =
119 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
120 init.SPI_CPHA =
121 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
122 init.SPI_NSS = nss_;
123 init.SPI_BaudRatePrescaler = prescaler_;
124 init.SPI_FirstBit = firstbit_;
125 init.SPI_CRCPolynomial = 7;
126
127 SPI_Init(instance_, &init);
128 SPI_Cmd(instance_, ENABLE);
129 }
130
131 // === DMA 通道基础配置 & 回调注册(启动传输时再设定 MADDR/CNTR) ===
132 {
133 // RX
134 {
135 ch32_dma_callback_t cb = [](void *arg)
136 { reinterpret_cast<CH32SPI *>(arg)->RxDmaIRQHandler(); };
137 CH32_DMA_RegisterCallback(CH32_DMA_GetID(dma_rx_channel_), cb, this);
138
139 DMA_InitTypeDef di = {};
140 DMA_DeInit(dma_rx_channel_);
141 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
142 di.DMA_MemoryBaseAddr = (uint32_t)dma_buff_rx_.addr_;
143 di.DMA_DIR = DMA_DIR_PeripheralSRC;
144 di.DMA_BufferSize = 0; // run-time 填
145 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
146 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
147 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
148 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
149 di.DMA_Mode = DMA_Mode_Normal;
150 di.DMA_Priority = DMA_Priority_High;
151 di.DMA_M2M = DMA_M2M_Disable;
152 DMA_Init(dma_rx_channel_, &di);
153 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
154 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[CH32_DMA_GetID(dma_rx_channel_)]);
155 }
156 // TX
157 {
158 ch32_dma_callback_t cb = [](void *arg)
159 { reinterpret_cast<CH32SPI *>(arg)->TxDmaIRQHandler(); };
160 CH32_DMA_RegisterCallback(CH32_DMA_GetID(dma_tx_channel_), cb, this);
161
162 DMA_InitTypeDef di = {};
163 DMA_DeInit(dma_tx_channel_);
164 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
165 di.DMA_MemoryBaseAddr = 0; // run-time 填
166 di.DMA_DIR = DMA_DIR_PeripheralDST;
167 di.DMA_BufferSize = 0; // run-time 填
168 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
169 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
170 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
171 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
172 di.DMA_Mode = DMA_Mode_Normal;
173 di.DMA_Priority = DMA_Priority_VeryHigh;
174 di.DMA_M2M = DMA_M2M_Disable;
175 DMA_Init(dma_tx_channel_, &di);
176 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
177 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[CH32_DMA_GetID(dma_tx_channel_)]);
178 }
179 }
180}
181
182// === SetConfig:仅更新极性/相位,保持其它参数 ===
184{
185 SPI_Cmd(instance_, DISABLE);
186 SPI_I2S_DeInit(instance_);
187
188 SPI_InitTypeDef init = {};
189 init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
190 init.SPI_Mode = mode_;
191 init.SPI_DataSize = datasize_;
192 init.SPI_CPOL =
193 (config.clock_polarity == SPI::ClockPolarity::LOW) ? SPI_CPOL_Low : SPI_CPOL_High;
194 init.SPI_CPHA =
195 (config.clock_phase == SPI::ClockPhase::EDGE_1) ? SPI_CPHA_1Edge : SPI_CPHA_2Edge;
196 init.SPI_NSS = nss_;
197 init.SPI_BaudRatePrescaler = prescaler_;
198 init.SPI_FirstBit = firstbit_;
199 init.SPI_CRCPolynomial = 7;
200 SPI_Init(instance_, &init);
201 SPI_Cmd(instance_, ENABLE);
202 return ErrorCode::OK;
203}
204
205ErrorCode CH32SPI::PollingTransfer(uint8_t *rx, const uint8_t *tx, uint32_t len)
206{
207 for (uint32_t i = 0; i < len; ++i)
208 {
209 // 等待 TXE
210 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_TXE) == RESET)
211 {
212 }
213 SPI_I2S_SendData(instance_, tx ? tx[i] : 0xFF);
214
215 // 等待 RXNE
216 while (SPI_I2S_GetFlagStatus(instance_, SPI_I2S_FLAG_RXNE) == RESET)
217 {
218 }
219 uint16_t d = SPI_I2S_ReceiveData(instance_);
220 if (rx) rx[i] = static_cast<uint8_t>(d & 0xFF);
221 }
222 return ErrorCode::OK;
223}
224
225ErrorCode CH32SPI::ReadAndWrite(RawData read_data, ConstRawData write_data,
226 OperationRW &op)
227{
228 const uint32_t rsz = read_data.size_;
229 const uint32_t wsz = write_data.size_;
230 const uint32_t need = (rsz > wsz) ? rsz : wsz;
231
232 if (need == 0)
233 {
234 if (op.type != OperationRW::OperationType::BLOCK)
235 op.UpdateStatus(false, ErrorCode::OK);
236 return ErrorCode::OK;
237 }
238
239 if (DmaBusy()) return ErrorCode::BUSY;
240
241 if (need > dma_enable_min_size_)
242 {
243 ASSERT(dma_buff_tx_.size_ >= need);
244 ASSERT(dma_buff_rx_.size_ >= need);
245
246 mem_read_ = false;
247 read_buff_ = read_data;
248 rw_op_ = op;
249 busy_ = true;
250
251 PrepareTxBuffer(write_data, need);
252
253 // 配置 DMA 长度与地址并启动
254 StartDmaDuplex(need);
255
256 op.MarkAsRunning();
257 if (op.type == OperationRW::OperationType::BLOCK)
258 {
259 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
260 }
261 return ErrorCode::OK;
262 }
263 else
264 {
265 // 轮询路径
266 uint8_t *rx = static_cast<uint8_t *>(dma_buff_rx_.addr_);
267 uint8_t *tx = static_cast<uint8_t *>(dma_buff_tx_.addr_);
268
269 // 准备 tx
270 if (wsz)
271 {
272 memcpy(tx, write_data.addr_, wsz);
273 if (need > wsz) memset(tx + wsz, 0xFF, need - wsz);
274 }
275 else
276 {
277 memset(tx, 0xFF, need);
278 }
279
280 ErrorCode ec = PollingTransfer(rsz ? rx : nullptr, tx, need);
281
282 if (rsz)
283 {
284 memcpy(read_data.addr_, rx, rsz);
285 }
286
287 if (op.type == OperationRW::OperationType::BLOCK)
288 {
289 return ec;
290 }
291
292 op.UpdateStatus(false, ec);
293
294 return ec;
295 }
296}
297
298ErrorCode CH32SPI::MemRead(uint16_t reg, RawData read_data, OperationRW &op)
299{
300 const uint32_t n = read_data.size_;
301 if (n == 0)
302 {
303 if (op.type != OperationRW::OperationType::BLOCK)
304 op.UpdateStatus(false, ErrorCode::OK);
305 return ErrorCode::OK;
306 }
307
308 if (DmaBusy()) return ErrorCode::BUSY;
309
310 const uint32_t total = n + 1; // 含首字节命令
311 if (total > dma_enable_min_size_)
312 {
313 ASSERT(dma_buff_tx_.size_ >= total);
314 ASSERT(dma_buff_rx_.size_ >= total);
315
316 uint8_t *tx = static_cast<uint8_t *>(dma_buff_tx_.addr_);
317 tx[0] = static_cast<uint8_t>(reg | 0x80);
318 memset(tx + 1, 0xFF, n);
319
320 mem_read_ = true;
321 read_buff_ = read_data;
322 rw_op_ = op;
323 busy_ = true;
324
325 StartDmaDuplex(total);
326
327 op.MarkAsRunning();
328 if (op.type == OperationRW::OperationType::BLOCK)
329 {
330 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
331 }
332 return ErrorCode::OK;
333 }
334 else
335 {
336 // 轮询
337 uint8_t *rx = static_cast<uint8_t *>(dma_buff_rx_.addr_);
338 uint8_t *tx = static_cast<uint8_t *>(dma_buff_tx_.addr_);
339 tx[0] = static_cast<uint8_t>(reg | 0x80);
340 memset(tx + 1, 0xFF, n);
341
342 ErrorCode ec = PollingTransfer(rx, tx, n + 1);
343 memcpy(read_data.addr_, rx + 1, n);
344
345 if (op.type == OperationRW::OperationType::BLOCK)
346 {
347 return ec;
348 }
349
350 op.UpdateStatus(false, ec);
351
352 return ec;
353 }
354}
355
356ErrorCode CH32SPI::MemWrite(uint16_t reg, ConstRawData write_data, OperationRW &op)
357{
358 const uint32_t n = write_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 const uint32_t total = n + 1;
369 if (total > dma_enable_min_size_)
370 {
371 ASSERT(dma_buff_tx_.size_ >= total);
372 ASSERT(dma_buff_rx_.size_ >= total); // RX 用于丢弃
373
374 uint8_t *tx = static_cast<uint8_t *>(dma_buff_tx_.addr_);
375 tx[0] = static_cast<uint8_t>(reg & 0x7F);
376 memcpy(tx + 1, write_data.addr_, n);
377
378 mem_read_ = false;
379 read_buff_ = {nullptr, 0};
380 rw_op_ = op;
381 busy_ = true;
382
383 StartDmaDuplex(total);
384
385 op.MarkAsRunning();
386 if (op.type == OperationRW::OperationType::BLOCK)
387 {
388 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
389 }
390 return ErrorCode::OK;
391 }
392 else
393 {
394 // 轮询
395 uint8_t *rx = static_cast<uint8_t *>(dma_buff_rx_.addr_);
396 uint8_t *tx = static_cast<uint8_t *>(dma_buff_tx_.addr_);
397 tx[0] = static_cast<uint8_t>(reg & 0x7F);
398 memcpy(tx + 1, write_data.addr_, n);
399
400 ErrorCode ec = PollingTransfer(rx, tx, n + 1);
401
402 if (op.type == OperationRW::OperationType::BLOCK)
403 {
404 return ec;
405 }
406
407 op.UpdateStatus(false, ec);
408
409 return ec;
410 }
411}
412
413void CH32SPI::PrepareTxBuffer(ConstRawData write_data, uint32_t need_len, uint32_t prefix,
414 uint8_t dummy)
415{
416 uint8_t *tx = static_cast<uint8_t *>(dma_buff_tx_.addr_);
417 if (write_data.size_ > 0)
418 {
419 const uint32_t copy =
420 (write_data.size_ > need_len - prefix) ? (need_len - prefix) : write_data.size_;
421 memcpy(tx + prefix, write_data.addr_, copy);
422 if (prefix + copy < need_len)
423 {
424 memset(tx + prefix + copy, dummy, need_len - prefix - copy);
425 }
426 }
427 else
428 {
429 memset(tx + prefix, dummy, need_len - prefix);
430 }
431}
432
433void CH32SPI::StartDmaDuplex(uint32_t count)
434{
435 // 配置长度与地址
436 dma_rx_channel_->MADDR = reinterpret_cast<uint32_t>(dma_buff_rx_.addr_);
437 dma_rx_channel_->CNTR = count;
438
439 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(dma_buff_tx_.addr_);
440 dma_tx_channel_->CNTR = count;
441
442 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, ENABLE);
443 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, ENABLE);
444
445 DMA_Cmd(dma_rx_channel_, ENABLE);
446 DMA_Cmd(dma_tx_channel_, ENABLE);
447}
448
449void CH32SPI::StopDma()
450{
451 DMA_Cmd(dma_tx_channel_, DISABLE);
452 DMA_Cmd(dma_rx_channel_, DISABLE);
453}
454
455void CH32SPI::RxDmaIRQHandler()
456{
457 // 只在 TC 时处理
458 if (DMA_GetITStatus(CH32_SPI_RX_DMA_IT_MAP[id_]) == RESET) return;
459
460 DMA_ClearITPendingBit(CH32_SPI_RX_DMA_IT_MAP[id_]);
461
462 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Rx, DISABLE);
463 DMA_Cmd(dma_rx_channel_, DISABLE);
464
465 // 拷贝读数据(若有)
466 if (read_buff_.size_ > 0)
467 {
468 uint8_t *rx = static_cast<uint8_t *>(dma_buff_rx_.addr_);
469 if (mem_read_)
470 {
471 // 丢首字节命令
472 memcpy(read_buff_.addr_, rx + 1, read_buff_.size_);
473 }
474 else
475 {
476 memcpy(read_buff_.addr_, rx, read_buff_.size_);
477 }
478 }
479
480 busy_ = false;
481 rw_op_.UpdateStatus(true, ErrorCode::OK);
482}
483
484void CH32SPI::TxDmaIRQHandler()
485{
486 if (DMA_GetITStatus(CH32_SPI_TX_DMA_IT_MAP[id_]) == RESET) return;
487 DMA_ClearITPendingBit(CH32_SPI_TX_DMA_IT_MAP[id_]);
488
489 SPI_I2S_DMACmd(instance_, SPI_I2S_DMAReq_Tx, DISABLE);
490 DMA_Cmd(dma_tx_channel_, DISABLE);
491}
ErrorCode MemWrite(uint16_t reg, ConstRawData write_data, OperationRW &op) override
向 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
Definition ch32_spi.cpp:356
ErrorCode SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
Definition ch32_spi.cpp:183
ErrorCode ReadAndWrite(RawData read_data, ConstRawData write_data, OperationRW &op) override
进行 SPI 读写操作。Performs SPI read and write operations.
Definition ch32_spi.cpp:225
ErrorCode MemRead(uint16_t reg, RawData read_data, OperationRW &op) override
从 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
Definition ch32_spi.cpp:298
常量原始数据封装类。 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).
union LibXR::Operation::@5 data
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
Definition libxr_rw.hpp:202
void UpdateStatus(bool in_isr, Status &&...status)
Updates operation status based on type.
Definition libxr_rw.hpp:171
OperationType type
Definition libxr_rw.hpp:226
原始数据封装类。 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).
Definition spi.hpp:13
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
@ LOW
时钟空闲时为低电平。Clock idle low.
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:25
LibXR 命名空间
存储 SPI 配置参数的结构体。Structure for storing SPI configuration parameters.
Definition spi.hpp:46
ClockPhase clock_phase
SPI 时钟相位。SPI clock phase.
Definition spi.hpp:48
ClockPolarity clock_polarity
SPI 时钟极性。SPI clock polarity.
Definition spi.hpp:47