libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
ch32_i2c.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2// ch32_i2c.cpp
3#include "ch32_i2c.hpp"
4
5#include <cstring>
6
7#include "ch32_dma.hpp"
8#include "ch32_gpio.hpp"
9
10using namespace LibXR;
11
12CH32I2C* CH32I2C::map_[CH32_I2C_NUMBER] = {nullptr};
13
14namespace
15{
16
17constexpr uint32_t CH32_I2C_ERROR_FLAGS =
18 ((I2C_FLAG_BERR & 0xFFFFu) | (I2C_FLAG_ARLO & 0xFFFFu) | (I2C_FLAG_AF & 0xFFFFu) |
19 (I2C_FLAG_OVR & 0xFFFFu) | (I2C_FLAG_PECERR & 0xFFFFu) |
20 (I2C_FLAG_TIMEOUT & 0xFFFFu) | (I2C_FLAG_SMBALERT & 0xFFFFu));
21
22} // namespace
23
24static inline void ch32_i2c_enable_clocks(ch32_i2c_id_t id)
25{
26 RCC_APB1PeriphClockCmd(CH32_I2C_RCC_PERIPH_MAP[id], ENABLE);
27 RCC_AHBPeriphClockCmd(CH32_I2C_RCC_PERIPH_MAP_DMA[id], ENABLE);
28}
29
30CH32I2C::CH32I2C(ch32_i2c_id_t id, RawData dma_buff, GPIO_TypeDef* scl_port,
31 uint16_t scl_pin, GPIO_TypeDef* sda_port, uint16_t sda_pin,
32 uint32_t pin_remap, uint32_t dma_enable_min_size,
33 uint32_t default_clock_hz, bool ten_bit_addr)
34 : I2C(),
35 instance_(ch32_i2c_get_instance_id(id)),
36 dma_rx_channel_(CH32_I2C_RX_DMA_CHANNEL_MAP[id]),
37 dma_tx_channel_(CH32_I2C_TX_DMA_CHANNEL_MAP[id]),
38 id_(id),
39 dma_enable_min_size_(dma_enable_min_size),
40 dma_buff_(dma_buff),
41 scl_port_(scl_port),
42 scl_pin_(scl_pin),
43 sda_port_(sda_port),
44 sda_pin_(sda_pin),
45 ten_bit_addr_(ten_bit_addr)
46{
47 ASSERT(instance_ != nullptr);
48 ASSERT(dma_buff_.addr_ != nullptr && dma_buff_.size_ > 0);
49
50 map_[id_] = this;
51
52 // Clock configuration.
53 ch32_i2c_enable_clocks(id_);
54
55 // GPIO configuration (I2C alternate-function open-drain).
56 {
57 GPIO_InitTypeDef gpio = {};
58 gpio.GPIO_Speed = GPIO_Speed_50MHz;
59 gpio.GPIO_Mode = GPIO_Mode_AF_OD;
60
61 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(scl_port_), ENABLE);
62 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(sda_port_), ENABLE);
63
64 GPIO_SetBits(scl_port_, scl_pin_);
65 GPIO_SetBits(sda_port_, sda_pin_);
66
67 gpio.GPIO_Pin = scl_pin_;
68 GPIO_Init(scl_port_, &gpio);
69
70 gpio.GPIO_Pin = sda_pin_;
71 GPIO_Init(sda_port_, &gpio);
72
73 if (pin_remap != 0)
74 {
75 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
76 GPIO_PinRemapConfig(pin_remap, ENABLE);
77 }
78 }
79
80 // DMA configuration.
81 {
82 // RX
83 {
84 ch32_dma_callback_t cb = [](void* arg)
85 { reinterpret_cast<CH32I2C*>(arg)->RxDmaIRQHandler(); };
86 ch32_dma_register_callback(ch32_dma_get_id(dma_rx_channel_), cb, this);
87
88 DMA_InitTypeDef di = {};
89 DMA_DeInit(dma_rx_channel_);
90 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
91 di.DMA_MemoryBaseAddr = (uint32_t)dma_buff_.addr_;
92 di.DMA_DIR = DMA_DIR_PeripheralSRC;
93 di.DMA_BufferSize = 0;
94 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
95 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
96 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
97 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
98 di.DMA_Mode = DMA_Mode_Normal;
99 di.DMA_Priority = DMA_Priority_High;
100 di.DMA_M2M = DMA_M2M_Disable;
101 DMA_Init(dma_rx_channel_, &di);
102 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
103 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_rx_channel_)]);
104 }
105
106 // TX
107 {
108 ch32_dma_callback_t cb = [](void* arg)
109 { reinterpret_cast<CH32I2C*>(arg)->TxDmaIRQHandler(); };
110 ch32_dma_register_callback(ch32_dma_get_id(dma_tx_channel_), cb, this);
111
112 DMA_InitTypeDef di = {};
113 DMA_DeInit(dma_tx_channel_);
114 di.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
115 di.DMA_MemoryBaseAddr = (uint32_t)dma_buff_.addr_;
116 di.DMA_DIR = DMA_DIR_PeripheralDST;
117 di.DMA_BufferSize = 0;
118 di.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
119 di.DMA_MemoryInc = DMA_MemoryInc_Enable;
120 di.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
121 di.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
122 di.DMA_Mode = DMA_Mode_Normal;
123 di.DMA_Priority = DMA_Priority_VeryHigh;
124 di.DMA_M2M = DMA_M2M_Disable;
125 DMA_Init(dma_tx_channel_, &di);
126 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
127 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_tx_channel_)]);
128 }
129 }
130
131 // I2C error interrupt for asynchronous transfer abort handling.
132 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
133 NVIC_EnableIRQ(CH32_I2C_ER_IRQ_MAP[id_]);
134
135 // Default runtime parameters.
136 cfg_.clock_speed = default_clock_hz;
137 (void)SetConfig(cfg_);
138}
139
141{
142 if (instance_ == nullptr || config.clock_speed == 0U)
143 {
144 return ErrorCode::ARG_ERR;
145 }
146 if (config.clock_speed > 400000U)
147 {
149 }
150 if (recovering_ || DmaBusy() || I2C_GetFlagStatus(instance_, I2C_FLAG_BUSY) != RESET)
151 {
152 return ErrorCode::BUSY;
153 }
154
155 RCC_ClocksTypeDef clocks{};
156 RCC_GetClocksFreq(&clocks);
157 const uint64_t denominator =
158 uint64_t(config.clock_speed) * (config.clock_speed <= 100000U ? 2U : 3U);
159 // CKCFGR.CCR is 12 bits; the SDK otherwise silently truncates low-rate dividers.
160 if (clocks.PCLK1_Frequency == 0U ||
161 (uint64_t(clocks.PCLK1_Frequency) + denominator - 1U) / denominator > 0x0FFFU)
162 {
164 }
165
166 ApplyConfig(config);
167 cfg_ = config;
168 return ErrorCode::OK;
169}
170
171void CH32I2C::ApplyConfig(Configuration config)
172{
173 I2C_Cmd(instance_, DISABLE);
174 I2C_DeInit(instance_);
175
176 I2C_InitTypeDef init = {};
177 init.I2C_ClockSpeed = config.clock_speed;
178 init.I2C_Mode = I2C_Mode_I2C;
179 init.I2C_DutyCycle = I2C_DutyCycle_2;
180 init.I2C_OwnAddress1 = 0;
181 init.I2C_Ack = I2C_Ack_Enable;
182 init.I2C_AcknowledgedAddress =
183 ten_bit_addr_ ? I2C_AcknowledgedAddress_10bit : I2C_AcknowledgedAddress_7bit;
184
185 I2C_Init(instance_, &init);
186 I2C_Cmd(instance_, ENABLE);
187
188 // 默认 ACK/NACK 状态
189 I2C_AcknowledgeConfig(instance_, ENABLE);
190 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
191 // I2C_DeInit resets CTLR2, including the asynchronous error interrupt.
192 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
193}
194
195bool CH32I2C::WaitEvent(uint32_t evt, uint32_t timeout_us)
196{
197 const uint64_t START = static_cast<uint64_t>(Timebase::GetMicroseconds());
198 while ((static_cast<uint64_t>(Timebase::GetMicroseconds()) - START) < timeout_us)
199 {
200 if ((instance_->STAR1 & CH32_I2C_ERROR_FLAGS) != 0u)
201 {
202 return false;
203 }
204 if (I2C_CheckEvent(instance_, evt) == READY)
205 {
206 return true;
207 }
208 }
209 return false;
210}
211
212bool CH32I2C::WaitFlag(uint32_t flag, FlagStatus st, uint32_t timeout_us)
213{
214 const uint64_t START = static_cast<uint64_t>(Timebase::GetMicroseconds());
215 while ((static_cast<uint64_t>(Timebase::GetMicroseconds()) - START) < timeout_us)
216 {
217 if ((flag != I2C_FLAG_BUSY) && ((instance_->STAR1 & CH32_I2C_ERROR_FLAGS) != 0u))
218 {
219 return false;
220 }
221 if (I2C_GetFlagStatus(instance_, flag) == st)
222 {
223 return true;
224 }
225 }
226 return false;
227}
228
229ErrorCode CH32I2C::WaitEventOrRecover(uint32_t evt, uint32_t timeout_us)
230{
231 if (WaitEvent(evt, timeout_us))
232 {
233 return ErrorCode::OK;
234 }
235 RecoverAfterImmediateFailure();
236 return ErrorCode::BUSY;
237}
238
239ErrorCode CH32I2C::WaitFlagOrRecover(uint32_t flag, FlagStatus st, uint32_t timeout_us)
240{
241 if (WaitFlag(flag, st, timeout_us))
242 {
243 return ErrorCode::OK;
244 }
245 RecoverAfterImmediateFailure();
246 return ErrorCode::BUSY;
247}
248
249void CH32I2C::ClearAddrFlag()
250{
251 volatile uint16_t tmp1 = instance_->STAR1;
252 volatile uint16_t tmp2 = instance_->STAR2;
253 (void)tmp1;
254 (void)tmp2;
255}
256
257ErrorCode CH32I2C::MasterStartAndAddress10Bit(uint16_t addr10, uint8_t final_dir)
258{
259 addr10 = Addr10Clamp(addr10);
260
261 // 等待 BUSY 释放
262 if (auto ec = WaitFlagOrRecover(I2C_FLAG_BUSY, RESET); ec != ErrorCode::OK)
263 {
264 return ec;
265 }
266
267 // --- 1) START ---
268 I2C_GenerateSTART(instance_, ENABLE);
269 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_MODE_SELECT); ec != ErrorCode::OK)
270 {
271 return ec;
272 }
273
274 // --- 2) 发送 10-bit 头字节(地址阶段固定以写方向发送,R/W=0)---
275 // header (8-bit,left-shifted): 11110 A9 A8 0 => 0xF0/0xF2/0xF4/0xF6
276 const uint8_t HEADER = static_cast<uint8_t>(0xF0 | ((addr10 >> 7) & 0x06));
277 I2C_Send7bitAddress(instance_, HEADER, I2C_Direction_Transmitter);
278
279 // 等待 EVT9(ADD10)
280 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_MODE_ADDRESS10); ec != ErrorCode::OK)
281 {
282 return ec;
283 }
284
285 // --- 3) 发送地址低 8 位 ---
286 I2C_SendData(instance_, static_cast<uint8_t>(addr10 & 0xFF));
287
288 // 等待 EVT6(作为 Transmitter 完成地址阶段)
289 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
290 ec != ErrorCode::OK)
291 {
292 return ec;
293 }
294 ClearAddrFlag();
295
296 if (final_dir == I2C_Direction_Transmitter)
297 {
298 return ErrorCode::OK;
299 }
300
301 // --- 4) 若最终为读:Repeated START + 头字节(R/W=1) ---
302 I2C_GenerateSTART(instance_, ENABLE);
303 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_MODE_SELECT); ec != ErrorCode::OK)
304 {
305 return ec;
306 }
307
308 I2C_Send7bitAddress(instance_, HEADER, I2C_Direction_Receiver);
309 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
310 ec != ErrorCode::OK)
311 {
312 return ec;
313 }
314 ClearAddrFlag();
315
316 return ErrorCode::OK;
317}
318
319ErrorCode CH32I2C::MasterStartAndAddress(uint16_t slave_addr, uint8_t dir)
320{
321 if (!ten_bit_addr_)
322 {
323 // 7-bit:输入为原始 7-bit 地址
324 const uint8_t ADDR8 = Addr7ToAddr8(slave_addr);
325
326 if (auto ec = WaitFlagOrRecover(I2C_FLAG_BUSY, RESET); ec != ErrorCode::OK)
327 {
328 return ec;
329 }
330
331 I2C_GenerateSTART(instance_, ENABLE);
332 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_MODE_SELECT); ec != ErrorCode::OK)
333 {
334 return ec;
335 }
336
337 I2C_Send7bitAddress(instance_, ADDR8, dir);
338
339 if (dir == I2C_Direction_Transmitter)
340 {
341 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
342 ec != ErrorCode::OK)
343 {
344 return ec;
345 }
346 }
347 else
348 {
349 if (auto ec = WaitEventOrRecover(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
350 ec != ErrorCode::OK)
351 {
352 return ec;
353 }
354 }
355
356 ClearAddrFlag();
357 return ErrorCode::OK;
358 }
359
360 // 10-bit:输入为原始 10-bit 地址
361 return MasterStartAndAddress10Bit(slave_addr, dir);
362}
363
364ErrorCode CH32I2C::SendMemAddr(uint16_t mem_addr, MemAddrLength len)
365{
366 if (len == MemAddrLength::BYTE_16)
367 {
368 if (auto ec = WaitFlagOrRecover(I2C_FLAG_TXE, SET); ec != ErrorCode::OK)
369 {
370 return ec;
371 }
372 I2C_SendData(instance_, static_cast<uint8_t>((mem_addr >> 8) & 0xFF));
373 if (auto ec = WaitFlagOrRecover(I2C_FLAG_TXE, SET); ec != ErrorCode::OK)
374 {
375 return ec;
376 }
377 I2C_SendData(instance_, static_cast<uint8_t>(mem_addr & 0xFF));
378 }
379 else
380 {
381 if (auto ec = WaitFlagOrRecover(I2C_FLAG_TXE, SET); ec != ErrorCode::OK)
382 {
383 return ec;
384 }
385 I2C_SendData(instance_, static_cast<uint8_t>(mem_addr & 0xFF));
386 }
387
388 if (auto ec = WaitFlagOrRecover(I2C_FLAG_BTF, SET); ec != ErrorCode::OK)
389 {
390 return ec;
391 }
392 return ErrorCode::OK;
393}
394
395ErrorCode CH32I2C::PollingWriteBytes(const uint8_t* data, uint32_t len)
396{
397 for (uint32_t i = 0; i < len; ++i)
398 {
399 if (auto ec = WaitFlagOrRecover(I2C_FLAG_TXE, SET); ec != ErrorCode::OK)
400 {
401 return ec;
402 }
403 I2C_SendData(instance_, data[i]);
404 }
405 if (auto ec = WaitFlagOrRecover(I2C_FLAG_BTF, SET); ec != ErrorCode::OK)
406 {
407 return ec;
408 }
409 return ErrorCode::OK;
410}
411
412ErrorCode CH32I2C::PollingReadBytes(uint8_t* data, uint32_t len)
413{
414 if (len == 0)
415 {
416 return ErrorCode::OK;
417 }
418
419 // 长度=1
420 if (len == 1)
421 {
422 I2C_AcknowledgeConfig(instance_, DISABLE);
423 I2C_GenerateSTOP(instance_, ENABLE);
424 if (auto ec = WaitFlagOrRecover(I2C_FLAG_RXNE, SET); ec != ErrorCode::OK)
425 {
426 return ec;
427 }
428 data[0] = I2C_ReceiveData(instance_);
429 I2C_AcknowledgeConfig(instance_, ENABLE);
430 return ErrorCode::OK;
431 }
432
433 // 长度=2
434 if (len == 2)
435 {
436 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Next);
437 I2C_AcknowledgeConfig(instance_, DISABLE);
438
439 if (auto ec = WaitFlagOrRecover(I2C_FLAG_BTF, SET); ec != ErrorCode::OK)
440 {
441 return ec;
442 }
443 I2C_GenerateSTOP(instance_, ENABLE);
444
445 data[0] = I2C_ReceiveData(instance_);
446 data[1] = I2C_ReceiveData(instance_);
447
448 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
449 I2C_AcknowledgeConfig(instance_, ENABLE);
450 return ErrorCode::OK;
451 }
452
453 // 长度>=3
454 I2C_AcknowledgeConfig(instance_, ENABLE);
455 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
456
457 uint32_t idx = 0;
458 while (len > 3)
459 {
460 if (auto ec = WaitFlagOrRecover(I2C_FLAG_RXNE, SET); ec != ErrorCode::OK)
461 {
462 return ec;
463 }
464 data[idx++] = I2C_ReceiveData(instance_);
465 --len;
466 }
467
468 // 剩余 3 字节处理
469 if (auto ec = WaitFlagOrRecover(I2C_FLAG_BTF, SET); ec != ErrorCode::OK)
470 {
471 return ec;
472 }
473 I2C_AcknowledgeConfig(instance_, DISABLE);
474 data[idx++] = I2C_ReceiveData(instance_);
475 I2C_GenerateSTOP(instance_, ENABLE);
476 data[idx++] = I2C_ReceiveData(instance_);
477
478 if (auto ec = WaitFlagOrRecover(I2C_FLAG_RXNE, SET); ec != ErrorCode::OK)
479 {
480 return ec;
481 }
482 data[idx++] = I2C_ReceiveData(instance_);
483
484 I2C_AcknowledgeConfig(instance_, ENABLE);
485 return ErrorCode::OK;
486}
487
488void CH32I2C::StartTxDma(uint32_t len)
489{
490 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(dma_buff_.addr_);
491 dma_tx_channel_->CNTR = len;
492
493 I2C_DMACmd(instance_, ENABLE);
494 DMA_Cmd(dma_tx_channel_, ENABLE);
495}
496
497void CH32I2C::StartRxDma(uint32_t len)
498{
499 // DMA 接收需保持 ACK 使能
500 I2C_AcknowledgeConfig(instance_, ENABLE);
501 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
502
503 dma_rx_channel_->MADDR = reinterpret_cast<uint32_t>(dma_buff_.addr_);
504 dma_rx_channel_->CNTR = len;
505
506 I2C_DMALastTransferCmd(instance_, ENABLE);
507 I2C_DMACmd(instance_, ENABLE);
508 DMA_Cmd(dma_rx_channel_, ENABLE);
509}
510
511void CH32I2C::AbortTransfer(ErrorCode ec)
512{
513 I2C_DMACmd(instance_, DISABLE);
514 I2C_DMALastTransferCmd(instance_, DISABLE);
515 DMA_Cmd(dma_tx_channel_, DISABLE);
516 DMA_Cmd(dma_rx_channel_, DISABLE);
517
518 // 恢复默认 ACK/NACK 配置
519 I2C_AcknowledgeConfig(instance_, ENABLE);
520 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
521
522 I2C_GenerateSTOP(instance_, ENABLE);
523
524 busy_ = false;
525
526 if (read_)
527 {
528 if (read_op_.type == ReadOperation::OperationType::BLOCK)
529 {
530 (void)block_wait_.TryPost(true, ec);
531 }
532 else
533 {
534 read_op_.UpdateStatus(true, ec);
535 }
536 }
537 else
538 {
539 if (write_op_.type == WriteOperation::OperationType::BLOCK)
540 {
541 (void)block_wait_.TryPost(true, ec);
542 }
543 else
544 {
545 write_op_.UpdateStatus(true, ec);
546 }
547 }
548}
549
550void CH32I2C::RecoverAfterImmediateFailure()
551{
552 recovering_ = true;
553 I2C_ITConfig(instance_, I2C_IT_ERR, DISABLE);
554 I2C_DMACmd(instance_, DISABLE);
555 I2C_DMALastTransferCmd(instance_, DISABLE);
556 DMA_Cmd(dma_tx_channel_, DISABLE);
557 DMA_Cmd(dma_rx_channel_, DISABLE);
558 dma_tx_channel_->CNTR = 0;
559 dma_rx_channel_->CNTR = 0;
560
561 DMA_ClearITPendingBit(CH32_I2C_TX_DMA_IT_MAP[id_]);
562 DMA_ClearITPendingBit(CH32_I2C_RX_DMA_IT_MAP[id_]);
563
564 const uint32_t err_its[] = {I2C_IT_BERR, I2C_IT_ARLO, I2C_IT_AF, I2C_IT_OVR,
565 I2C_IT_PECERR, I2C_IT_TIMEOUT, I2C_IT_SMBALERT};
566 for (uint32_t it : err_its)
567 {
568 I2C_ClearITPendingBit(instance_, it);
569 }
570
571 I2C_GenerateSTOP(instance_, ENABLE);
572 if (!WaitFlag(I2C_FLAG_BUSY, RESET, K_DEFAULT_TIMEOUT_US))
573 {
574 // DMA is stopped; recovery must not use the public BUSY admission check.
575 ApplyConfig(cfg_);
576 }
577 else
578 {
579 I2C_AcknowledgeConfig(instance_, ENABLE);
580 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
581 }
582
583 busy_ = false;
584 read_ = false;
585 read_op_ = {};
586 write_op_ = {};
587 read_buff_ = {nullptr, 0};
588 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
589 recovering_ = false;
590}
591
592ErrorCode CH32I2C::Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation& op,
593 bool in_isr)
594{
595 if (write_data.size_ == 0)
596 {
597 if (op.type != WriteOperation::OperationType::BLOCK)
598 {
599 op.UpdateStatus(in_isr, ErrorCode::OK);
600 }
601 return ErrorCode::OK;
602 }
603
604 ASSERT(write_data.size_ <= dma_buff_.size_);
605 if (DmaBusy())
606 {
607 return ErrorCode::BUSY;
608 }
609
610 read_ = false;
611 I2C_ITConfig(instance_, I2C_IT_ERR, DISABLE);
612
613 ErrorCode ec = MasterStartAndAddress(slave_addr, I2C_Direction_Transmitter);
614 if (ec != ErrorCode::OK)
615 {
616 return ec;
617 }
618
619 // 短传输:轮询
620 if (write_data.size_ <= dma_enable_min_size_)
621 {
622 ec = PollingWriteBytes(reinterpret_cast<const uint8_t*>(write_data.addr_),
623 write_data.size_);
624 I2C_GenerateSTOP(instance_, ENABLE);
625 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
626
627 if (op.type != WriteOperation::OperationType::BLOCK)
628 {
629 op.UpdateStatus(in_isr, ec);
630 }
631 return ec;
632 }
633
634 // 长传输:DMA
635 Memory::FastCopy(dma_buff_.addr_, write_data.addr_, write_data.size_);
636
637 write_op_ = op;
638 busy_ = true;
639
640 if (op.type == WriteOperation::OperationType::BLOCK)
641 {
642 block_wait_.Start(*op.data.sem_info.sem);
643 }
644 op.MarkAsRunning();
645 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
646 StartTxDma(write_data.size_);
647
648 if (op.type == WriteOperation::OperationType::BLOCK)
649 {
650 return block_wait_.Wait(op.data.sem_info.timeout);
651 }
652 return ErrorCode::OK;
653}
654
655ErrorCode CH32I2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
656 bool in_isr)
657{
658 if (read_data.size_ == 0)
659 {
660 if (op.type != ReadOperation::OperationType::BLOCK)
661 {
662 op.UpdateStatus(in_isr, ErrorCode::OK);
663 }
664 return ErrorCode::OK;
665 }
666
667 ASSERT(read_data.size_ <= dma_buff_.size_);
668 if (DmaBusy())
669 {
670 return ErrorCode::BUSY;
671 }
672
673 read_ = true;
674 I2C_ITConfig(instance_, I2C_IT_ERR, DISABLE);
675
676 ErrorCode ec = MasterStartAndAddress(slave_addr, I2C_Direction_Receiver);
677 if (ec != ErrorCode::OK)
678 {
679 return ec;
680 }
681
682 // 短传输:轮询
683 if (read_data.size_ <= dma_enable_min_size_)
684 {
685 ec = PollingReadBytes(reinterpret_cast<uint8_t*>(read_data.addr_), read_data.size_);
686 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
687 if (op.type != ReadOperation::OperationType::BLOCK)
688 {
689 op.UpdateStatus(in_isr, ec);
690 }
691 return ec;
692 }
693
694 // 长传输:DMA
695 read_op_ = op;
696 read_buff_ = read_data;
697 busy_ = true;
698
699 if (op.type == ReadOperation::OperationType::BLOCK)
700 {
701 block_wait_.Start(*op.data.sem_info.sem);
702 }
703 op.MarkAsRunning();
704 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
705 StartRxDma(read_data.size_);
706
707 if (op.type == ReadOperation::OperationType::BLOCK)
708 {
709 return block_wait_.Wait(op.data.sem_info.timeout);
710 }
711 return ErrorCode::OK;
712}
713
714ErrorCode CH32I2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
715 ConstRawData write_data, WriteOperation& op,
716 MemAddrLength mem_addr_size, bool in_isr)
717{
718 if (write_data.size_ == 0)
719 {
720 if (op.type != WriteOperation::OperationType::BLOCK)
721 {
722 op.UpdateStatus(in_isr, ErrorCode::OK);
723 }
724 return ErrorCode::OK;
725 }
726
727 ASSERT(write_data.size_ <= dma_buff_.size_);
728 if (DmaBusy())
729 {
730 return ErrorCode::BUSY;
731 }
732
733 read_ = false;
734 I2C_ITConfig(instance_, I2C_IT_ERR, DISABLE);
735
736 ErrorCode ec = MasterStartAndAddress(slave_addr, I2C_Direction_Transmitter);
737 if (ec != ErrorCode::OK)
738 {
739 return ec;
740 }
741
742 ec = SendMemAddr(mem_addr, mem_addr_size);
743 if (ec != ErrorCode::OK)
744 {
745 I2C_GenerateSTOP(instance_, ENABLE);
746 if (op.type != WriteOperation::OperationType::BLOCK)
747 {
748 op.UpdateStatus(in_isr, ec);
749 }
750 return ec;
751 }
752
753 if (write_data.size_ <= dma_enable_min_size_)
754 {
755 ec = PollingWriteBytes(reinterpret_cast<const uint8_t*>(write_data.addr_),
756 write_data.size_);
757 I2C_GenerateSTOP(instance_, ENABLE);
758 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
759
760 if (op.type != WriteOperation::OperationType::BLOCK)
761 {
762 op.UpdateStatus(in_isr, ec);
763 }
764 return ec;
765 }
766
767 Memory::FastCopy(dma_buff_.addr_, write_data.addr_, write_data.size_);
768
769 write_op_ = op;
770 busy_ = true;
771
772 if (op.type == WriteOperation::OperationType::BLOCK)
773 {
774 block_wait_.Start(*op.data.sem_info.sem);
775 }
776 op.MarkAsRunning();
777 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
778 StartTxDma(write_data.size_);
779
780 if (op.type == WriteOperation::OperationType::BLOCK)
781 {
782 return block_wait_.Wait(op.data.sem_info.timeout);
783 }
784 return ErrorCode::OK;
785}
786
787ErrorCode CH32I2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
788 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
789{
790 if (read_data.size_ == 0)
791 {
792 if (op.type != ReadOperation::OperationType::BLOCK)
793 {
794 op.UpdateStatus(in_isr, ErrorCode::OK);
795 }
796 return ErrorCode::OK;
797 }
798
799 ASSERT(read_data.size_ <= dma_buff_.size_);
800 if (DmaBusy())
801 {
802 return ErrorCode::BUSY;
803 }
804
805 read_ = true;
806 I2C_ITConfig(instance_, I2C_IT_ERR, DISABLE);
807
808 // 1) 地址阶段:发送写地址 + mem addr
809 ErrorCode ec = MasterStartAndAddress(slave_addr, I2C_Direction_Transmitter);
810 if (ec != ErrorCode::OK)
811 {
812 return ec;
813 }
814
815 ec = SendMemAddr(mem_addr, mem_addr_size);
816 if (ec != ErrorCode::OK)
817 {
818 I2C_GenerateSTOP(instance_, ENABLE);
819 if (op.type != ReadOperation::OperationType::BLOCK)
820 {
821 op.UpdateStatus(in_isr, ec);
822 }
823 return ec;
824 }
825
826 // 2) Repeated START + 读地址阶段
827 if (!ten_bit_addr_)
828 {
829 const uint8_t ADDR8 = Addr7ToAddr8(slave_addr);
830
831 I2C_GenerateSTART(instance_, ENABLE);
832 if (!WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
833 {
834 I2C_GenerateSTOP(instance_, ENABLE);
835 ec = ErrorCode::BUSY;
836 if (op.type != ReadOperation::OperationType::BLOCK)
837 {
838 op.UpdateStatus(in_isr, ec);
839 }
840 return ec;
841 }
842
843 I2C_Send7bitAddress(instance_, ADDR8, I2C_Direction_Receiver);
844 if (!WaitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
845 {
846 I2C_GenerateSTOP(instance_, ENABLE);
847 ec = ErrorCode::BUSY;
848 if (op.type != ReadOperation::OperationType::BLOCK)
849 {
850 op.UpdateStatus(in_isr, ec);
851 }
852 return ec;
853 }
854 ClearAddrFlag();
855 }
856 else
857 {
858 const uint16_t ADDR10 = Addr10Clamp(slave_addr);
859 const uint8_t HEADER = static_cast<uint8_t>(0xF0 | ((ADDR10 >> 7) & 0x06));
860
861 I2C_GenerateSTART(instance_, ENABLE);
862 if (!WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
863 {
864 I2C_GenerateSTOP(instance_, ENABLE);
865 ec = ErrorCode::BUSY;
866 if (op.type != ReadOperation::OperationType::BLOCK)
867 {
868 op.UpdateStatus(in_isr, ec);
869 }
870 return ec;
871 }
872
873 I2C_Send7bitAddress(instance_, HEADER, I2C_Direction_Receiver);
874 if (!WaitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
875 {
876 I2C_GenerateSTOP(instance_, ENABLE);
877 ec = ErrorCode::BUSY;
878 if (op.type != ReadOperation::OperationType::BLOCK)
879 {
880 op.UpdateStatus(in_isr, ec);
881 }
882 return ec;
883 }
884 ClearAddrFlag();
885 }
886
887 // 短传输:轮询
888 if (read_data.size_ <= dma_enable_min_size_)
889 {
890 ec = PollingReadBytes(reinterpret_cast<uint8_t*>(read_data.addr_), read_data.size_);
891 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
892 if (op.type != ReadOperation::OperationType::BLOCK)
893 {
894 op.UpdateStatus(in_isr, ec);
895 }
896 return ec;
897 }
898
899 // 长传输:DMA
900 read_op_ = op;
901 read_buff_ = read_data;
902 busy_ = true;
903
904 if (op.type == ReadOperation::OperationType::BLOCK)
905 {
906 block_wait_.Start(*op.data.sem_info.sem);
907 }
908 op.MarkAsRunning();
909 I2C_ITConfig(instance_, I2C_IT_ERR, ENABLE);
910 StartRxDma(read_data.size_);
911
912 if (op.type == ReadOperation::OperationType::BLOCK)
913 {
914 return block_wait_.Wait(op.data.sem_info.timeout);
915 }
916 return ErrorCode::OK;
917}
918
919void CH32I2C::TxDmaIRQHandler()
920{
921 if (DMA_GetITStatus(CH32_I2C_TX_DMA_IT_MAP[id_]) == RESET)
922 {
923 return;
924 }
925 DMA_ClearITPendingBit(CH32_I2C_TX_DMA_IT_MAP[id_]);
926
927 DMA_Cmd(dma_tx_channel_, DISABLE);
928 I2C_DMACmd(instance_, DISABLE);
929
930 if (recovering_ || !busy_)
931 {
932 return;
933 }
934
935 (void)WaitFlag(I2C_FLAG_BTF, SET, 20000);
936 I2C_GenerateSTOP(instance_, ENABLE);
937
938 busy_ = false;
939 if (write_op_.type == WriteOperation::OperationType::BLOCK)
940 {
941 (void)block_wait_.TryPost(true, ErrorCode::OK);
942 }
943 else
944 {
945 write_op_.UpdateStatus(true, ErrorCode::OK);
946 }
947}
948
950{
951 if (DMA_GetITStatus(CH32_I2C_RX_DMA_IT_MAP[id_]) == RESET)
952 {
953 return;
954 }
955 DMA_ClearITPendingBit(CH32_I2C_RX_DMA_IT_MAP[id_]);
956
957 DMA_Cmd(dma_rx_channel_, DISABLE);
958 I2C_DMACmd(instance_, DISABLE);
959 I2C_DMALastTransferCmd(instance_, DISABLE);
960
961 if (recovering_ || !busy_)
962 {
963 return;
964 }
965
966 I2C_GenerateSTOP(instance_, ENABLE);
967
968 if (read_buff_.size_ > 0)
969 {
970 Memory::FastCopy(read_buff_.addr_, dma_buff_.addr_, read_buff_.size_);
971 read_buff_.size_ = 0;
972 }
973
974 // 恢复默认 ACK/NACK 配置
975 I2C_AcknowledgeConfig(instance_, ENABLE);
976 I2C_NACKPositionConfig(instance_, I2C_NACKPosition_Current);
977
978 busy_ = false;
979 if (read_op_.type == ReadOperation::OperationType::BLOCK)
980 {
981 (void)block_wait_.TryPost(true, ErrorCode::OK);
982 }
983 else
984 {
985 read_op_.UpdateStatus(true, ErrorCode::OK);
986 }
987}
988
990{
991 bool has_err = false;
992
993 const uint32_t ITS[] = {I2C_IT_BERR, I2C_IT_ARLO, I2C_IT_AF, I2C_IT_OVR,
994 I2C_IT_TIMEOUT, I2C_IT_PECERR, I2C_IT_SMBALERT};
995
996 for (uint32_t it : ITS)
997 {
998 if (I2C_GetITStatus(instance_, it) == SET)
999 {
1000 I2C_ClearITPendingBit(instance_, it);
1001 has_err = true;
1002 }
1003 }
1004
1005 if (has_err && busy_ && !recovering_)
1006 {
1007 AbortTransfer(ErrorCode::FAILED);
1008 }
1009}
1010
1011// I2C ER IRQ entry.
1012extern "C"
1013{
1014#if defined(I2C1)
1015 void i2_c1_er_irq_handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
1016 void i2_c1_er_irq_handler(void)
1017 {
1018 auto* p = LibXR::CH32I2C::map_[ch32_i2c_get_id(I2C1)];
1019 if (p)
1020 {
1021 p->ErrorIRQHandler();
1022 }
1023 }
1024#endif
1025
1026#if defined(I2C2)
1027 void i2_c2_er_irq_handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
1028 void i2_c2_er_irq_handler(void)
1029 {
1030 auto* p = LibXR::CH32I2C::map_[ch32_i2c_get_id(I2C2)];
1031 if (p)
1032 {
1033 p->ErrorIRQHandler();
1034 }
1035 }
1036#endif
1037} // extern "C"
1038
1039// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
bool TryPost(bool in_isr, ErrorCode ec)
尝试认领完成并唤醒调用者 / Try to claim completion and wake the caller.
void Start(Semaphore &sem)
绑定信号量并开始等待 / Bind a semaphore and start waiting.
ErrorCode Wait(uint32_t timeout)
等待完成或超时交接 / Wait for completion or a timeout handoff.
ErrorCode MemWrite(uint16_t slave_addr, uint16_t mem_addr, ConstRawData write_data, WriteOperation &op, MemAddrLength mem_addr_size, bool in_isr) override
向 I2C 设备指定寄存器写入数据。 Writes data to a specific register of an I2C device.
Definition ch32_i2c.cpp:714
ErrorCode MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data, ReadOperation &op, MemAddrLength mem_addr_size, bool in_isr) override
从 I2C 设备指定寄存器读取数据。 Reads data from a specific register of an I2C device.
Definition ch32_i2c.cpp:787
void RxDmaIRQHandler()
DMA 回调入口 / DMA callbacks from CH32 DMA driver.
Definition ch32_i2c.cpp:949
void ErrorIRQHandler()
错误中断回调 / I2C error IRQ callback
Definition ch32_i2c.cpp:989
ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation &op, bool in_isr) override
向 I2C 设备写入数据。 Writes data to an I2C device.
Definition ch32_i2c.cpp:592
ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation &op, bool in_isr) override
读取 I2C 设备的数据。 Reads data from an I2C device.
Definition ch32_i2c.cpp:655
CH32I2C(ch32_i2c_id_t id, RawData dma_buff, GPIO_TypeDef *scl_port, uint16_t scl_pin, GPIO_TypeDef *sda_port, uint16_t sda_pin, uint32_t pin_remap=0, uint32_t dma_enable_min_size=3, uint32_t default_clock_hz=400000, bool ten_bit_addr=false)
构造 I2C 驱动对象 / Construct I2C driver object
Definition ch32_i2c.cpp:30
ErrorCode SetConfig(Configuration config) override
配置 I2C 设备参数。 Configures the I2C device settings.
Definition ch32_i2c.cpp:140
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
I2C(Inter-Integrated Circuit)接口类。 I2C (Inter-Integrated Circuit) interface class.
Definition i2c.hpp:17
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
uint32_t timeout
等待超时值 / Wait timeout.
void UpdateStatus(bool in_isr, Status &&status)
按通知方式报告完成结果 / Report completion using the selected mode.
union LibXR::Operation::@6 data
完成通知对象,由 type 选择有效成员 / Notification target selected by type.
void MarkAsRunning()
标记轮询操作正在执行 / Mark a polling operation as running.
Semaphore * sem
借用的信号量 / Borrowed semaphore.
OperationType type
当前通知方式 / Current notification mode.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ BUSY
忙碌 / Busy
@ NOT_SUPPORT
不支持 / Not supported
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.
Definition i2c.hpp:24
uint32_t clock_speed
I2C 通信时钟速率(单位:Hz) / The I2C clock speed (in Hz).
Definition i2c.hpp:26