libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
mspm0_i2c.cpp
1#include "mspm0_i2c.hpp"
2
3#include <ti/driverlib/dl_dma.h>
4
5#include <cstdint>
6#include <cstring>
7
8using namespace LibXR;
9
10namespace
11{
12
13constexpr uint32_t MSPM0_I2C_WAIT_IDLE_TIMEOUT = 300000;
14constexpr uint32_t MSPM0_I2C_WAIT_BUS_TIMEOUT = 300000;
15constexpr uint32_t MSPM0_I2C_WAIT_FIFO_TIMEOUT = 300000;
16constexpr uint32_t MSPM0_I2C_POLLING_ATTEMPTS = 2;
17constexpr uint32_t MSPM0_I2C_MEMREAD_RS_ATTEMPTS = 2;
18constexpr uint32_t MSPM0_I2C_MEMREAD_FALLBACK_ATTEMPTS = 3;
19
20constexpr uint16_t MSPM0_I2C_MAX_TRANSFER_SIZE = 0x0FFF;
21
22// 两个 DMA 绑定都存在时才启用 DMA;未绑定时保留轮询 I2C。
23// Enable DMA only when both channels are bound; otherwise retain polling I2C.
24#if defined(DMA_CH_TX_CHAN_ID) != defined(DMA_CH_RX_CHAN_ID)
25#error "MSPM0I2C requires both TX and RX DMA bindings, or neither."
26#endif
27#if defined(DMA_CH_TX_CHAN_ID) && defined(DMA_CH_RX_CHAN_ID)
28constexpr bool I2C_DMA_CONFIGURED = true;
29constexpr uint8_t I2C_DMA_TX_CHANNEL = DMA_CH_TX_CHAN_ID;
30constexpr uint8_t I2C_DMA_RX_CHANNEL = DMA_CH_RX_CHAN_ID;
31static_assert(DMA_CH_TX_CHAN_ID < DMA_SYS_N_DMA_CHANNEL);
32static_assert(DMA_CH_RX_CHAN_ID < DMA_SYS_N_DMA_CHANNEL);
33static_assert(DMA_CH_TX_CHAN_ID != DMA_CH_RX_CHAN_ID);
34#else
35constexpr bool I2C_DMA_CONFIGURED = false;
36// Unused placeholders: no DMA register may be accessed in polling-only mode.
37constexpr uint8_t I2C_DMA_TX_CHANNEL = 0U;
38constexpr uint8_t I2C_DMA_RX_CHANNEL = 0U;
39#endif
40
41constexpr DL_DMA_Config MSPM0_I2C_DMA_TX_CONFIG_BASE = {
42 .trigger = 0U,
43 .triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL,
44 .transferMode = DL_DMA_SINGLE_TRANSFER_MODE,
45 .extendedMode = DL_DMA_NORMAL_MODE,
46 .srcWidth = DL_DMA_WIDTH_BYTE,
47 .destWidth = DL_DMA_WIDTH_BYTE,
48 .srcIncrement = DL_DMA_ADDR_INCREMENT,
49 .destIncrement = DL_DMA_ADDR_UNCHANGED,
50};
51
52constexpr DL_DMA_Config MSPM0_I2C_DMA_RX_CONFIG_BASE = {
53 .trigger = 0U,
54 .triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL,
55 .transferMode = DL_DMA_SINGLE_TRANSFER_MODE,
56 .extendedMode = DL_DMA_NORMAL_MODE,
57 .srcWidth = DL_DMA_WIDTH_BYTE,
58 .destWidth = DL_DMA_WIDTH_BYTE,
59 .srcIncrement = DL_DMA_ADDR_UNCHANGED,
60 .destIncrement = DL_DMA_ADDR_INCREMENT,
61};
62
63constexpr uint32_t mspm0_i2c_dma_channel_mask(uint8_t channel_id)
64{
65 return (1UL << channel_id);
66}
67
68bool mspm0_i2c_resolve_dma_triggers(I2C_Regs* instance, uint8_t& tx_trigger,
69 uint8_t& rx_trigger)
70{
71#if defined(I2C0_BASE) && defined(DMA_I2C0_TX_TRIG) && defined(DMA_I2C0_RX_TRIG)
72 if (instance == I2C0)
73 {
74 tx_trigger = DMA_I2C0_TX_TRIG;
75 rx_trigger = DMA_I2C0_RX_TRIG;
76 return true;
77 }
78#endif
79#if defined(I2C1_BASE) && defined(DMA_I2C1_TX_TRIG) && defined(DMA_I2C1_RX_TRIG)
80 if (instance == I2C1)
81 {
82 tx_trigger = DMA_I2C1_TX_TRIG;
83 rx_trigger = DMA_I2C1_RX_TRIG;
84 return true;
85 }
86#endif
87#if defined(I2C2_BASE) && defined(DMA_I2C2_TX_TRIG) && defined(DMA_I2C2_RX_TRIG)
88 if (instance == I2C2)
89 {
90 tx_trigger = DMA_I2C2_TX_TRIG;
91 rx_trigger = DMA_I2C2_RX_TRIG;
92 return true;
93 }
94#endif
95#if defined(I2C3_BASE) && defined(DMA_I2C3_TX_TRIG) && defined(DMA_I2C3_RX_TRIG)
96 if (instance == I2C3)
97 {
98 tx_trigger = DMA_I2C3_TX_TRIG;
99 rx_trigger = DMA_I2C3_RX_TRIG;
100 return true;
101 }
102#endif
103 return false;
104}
105
106constexpr bool mspm0_i2c_is_valid_addr7(uint16_t slave_addr)
107{
108 return slave_addr <= 0x7FU;
109}
110
111void mspm0_i2c_recover_controller(I2C_Regs* instance)
112{
113 DL_I2C_disableInterrupt(instance, 0xFFFFFFFFU);
114 DL_I2C_clearInterruptStatus(instance, 0xFFFFFFFFU);
115 DL_I2C_disableControllerReadOnTXEmpty(instance);
116 DL_I2C_resetControllerTransfer(instance);
117 DL_I2C_enableController(instance);
118}
119
120} // namespace
121
122MSPM0I2C::MSPM0I2C(Resources res, RawData stage_buffer, uint32_t dma_enable_min_size,
123 I2C::Configuration config)
124 : I2C(),
125 res_(res),
126 stage_buffer_(stage_buffer),
127 dma_enable_min_size_(dma_enable_min_size)
128{
129 ASSERT(res_.instance != nullptr);
130 ASSERT(res_.clock_freq > 0);
131 ASSERT(res_.index < MAX_I2C_INSTANCES);
132 ASSERT(stage_buffer_.addr_ != nullptr);
133 ASSERT(stage_buffer_.size_ > 0);
134
135 if (config.clock_speed == 0)
136 {
137 config.clock_speed = res_.default_bus_speed_hz;
138 }
139 const ErrorCode SET_CFG_ANS = SetConfig(config);
140 REQUIRE(SET_CFG_ANS == ErrorCode::OK);
141}
142
143ErrorCode MSPM0I2C::CheckControllerError() const
144{
145 const uint32_t STATUS = DL_I2C_getControllerStatus(res_.instance);
146 if ((STATUS & DL_I2C_CONTROLLER_STATUS_ERROR) != 0 ||
147 (STATUS & DL_I2C_CONTROLLER_STATUS_ARBITRATION_LOST) != 0)
148 {
149 return ErrorCode::FAILED;
150 }
151 return ErrorCode::OK;
152}
153
154ErrorCode MSPM0I2C::WaitControllerIdle() const
155{
156 uint32_t timeout = MSPM0_I2C_WAIT_IDLE_TIMEOUT;
157 while (timeout-- > 0)
158 {
159 if ((DL_I2C_getControllerStatus(res_.instance) & DL_I2C_CONTROLLER_STATUS_IDLE) != 0)
160 {
161 return ErrorCode::OK;
162 }
163 if (CheckControllerError() != ErrorCode::OK)
164 {
165 return ErrorCode::FAILED;
166 }
167 }
168 return ErrorCode::BUSY;
169}
170
171ErrorCode MSPM0I2C::WaitTransactionDone() const
172{
173 uint32_t timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
174 while (timeout-- > 0)
175 {
176 if (DL_I2C_getTransactionCount(res_.instance) == 0)
177 {
178 return ErrorCode::OK;
179 }
180 if (CheckControllerError() != ErrorCode::OK)
181 {
182 return ErrorCode::FAILED;
183 }
184 }
185 return ErrorCode::BUSY;
186}
187
188ErrorCode MSPM0I2C::WaitBusIdle() const
189{
190 uint32_t timeout = MSPM0_I2C_WAIT_BUS_TIMEOUT;
191 while (timeout-- > 0)
192 {
193 if ((DL_I2C_getControllerStatus(res_.instance) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS) ==
194 0)
195 {
196 return ErrorCode::OK;
197 }
198 if (CheckControllerError() != ErrorCode::OK)
199 {
200 return ErrorCode::FAILED;
201 }
202 }
203 return ErrorCode::BUSY;
204}
205
207{
208 if (res_.instance == nullptr || res_.clock_freq == 0U || config.clock_speed == 0U)
209 {
210 return ErrorCode::ARG_ERR;
211 }
212 if (config.clock_speed > 1000000U)
213 {
215 }
216
217 // SCL = BUSCLK / (10 * (TPR + 1)); round up to avoid exceeding the request.
218 const uint64_t PERIOD_DEN = uint64_t(config.clock_speed) * 10U;
219 const uint64_t period_factor =
220 (uint64_t(res_.clock_freq) + PERIOD_DEN - 1U) / PERIOD_DEN;
221 if (period_factor == 0)
222 {
224 }
225 if (period_factor > 128U)
226 {
228 }
229
230 if ((DL_I2C_getControllerStatus(res_.instance) &
231 (DL_I2C_CONTROLLER_STATUS_BUSY | DL_I2C_CONTROLLER_STATUS_BUSY_BUS)) != 0U)
232 {
233 return ErrorCode::BUSY;
234 }
235
236 const uint8_t TIMER_PERIOD = static_cast<uint8_t>(period_factor - 1U);
237 const DL_I2C_ClockConfig CLOCK_CONFIG = {
238 .clockSel = DL_I2C_CLOCK_BUSCLK,
239 .divideRatio = DL_I2C_CLOCK_DIVIDE_1,
240 };
241
242 uint8_t dma_tx_trigger = 0U;
243 uint8_t dma_rx_trigger = 0U;
244 const bool USE_DMA =
245 I2C_DMA_CONFIGURED &&
246 mspm0_i2c_resolve_dma_triggers(res_.instance, dma_tx_trigger, dma_rx_trigger);
247 dma_enabled_ = USE_DMA;
248
249 DL_I2C_disableController(res_.instance);
250 DL_I2C_setClockConfig(res_.instance, &CLOCK_CONFIG);
251 DL_I2C_resetControllerTransfer(res_.instance);
252 DL_I2C_setTimerPeriod(res_.instance, TIMER_PERIOD);
253 DL_I2C_setControllerTXFIFOThreshold(
254 res_.instance, USE_DMA ? DL_I2C_TX_FIFO_LEVEL_EMPTY : DL_I2C_TX_FIFO_LEVEL_BYTES_1);
255 DL_I2C_setControllerRXFIFOThreshold(res_.instance, DL_I2C_RX_FIFO_LEVEL_BYTES_1);
256 DL_I2C_enableControllerClockStretching(res_.instance);
257 DL_I2C_disableInterrupt(res_.instance, 0xFFFFFFFFU);
258 DL_I2C_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
259
260 DL_I2C_disableDMAEvent(res_.instance, DL_I2C_EVENT_ROUTE_1,
261 DL_I2C_DMA_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
262 DL_I2C_disableDMAEvent(res_.instance, DL_I2C_EVENT_ROUTE_2,
263 DL_I2C_DMA_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER);
264 if (USE_DMA)
265 {
266 DL_DMA_disableChannel(DMA, I2C_DMA_TX_CHANNEL);
267 DL_DMA_disableChannel(DMA, I2C_DMA_RX_CHANNEL);
268 DL_DMA_clearInterruptStatus(DMA, mspm0_i2c_dma_channel_mask(I2C_DMA_TX_CHANNEL) |
269 mspm0_i2c_dma_channel_mask(I2C_DMA_RX_CHANNEL));
270 }
271
272 if (USE_DMA)
273 {
274 DL_DMA_Config dma_tx_config = MSPM0_I2C_DMA_TX_CONFIG_BASE;
275 DL_DMA_Config dma_rx_config = MSPM0_I2C_DMA_RX_CONFIG_BASE;
276 dma_tx_config.trigger = dma_tx_trigger;
277 dma_rx_config.trigger = dma_rx_trigger;
278
279 DL_I2C_enableDMAEvent(res_.instance, DL_I2C_EVENT_ROUTE_1,
280 DL_I2C_DMA_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
281 DL_I2C_enableDMAEvent(res_.instance, DL_I2C_EVENT_ROUTE_2,
282 DL_I2C_DMA_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER);
283 DL_DMA_initChannel(DMA, I2C_DMA_TX_CHANNEL, &dma_tx_config);
284 DL_DMA_initChannel(DMA, I2C_DMA_RX_CHANNEL, &dma_rx_config);
285 }
286
287 DL_I2C_enableController(res_.instance);
288
289 return ErrorCode::OK;
290}
291
292ErrorCode MSPM0I2C::PollingWrite7(uint16_t addr7, const uint8_t* data, size_t size)
293{
294 if (size == 0)
295 {
296 return ErrorCode::OK;
297 }
298 if (size > MSPM0_I2C_MAX_TRANSFER_SIZE)
299 {
300 return ErrorCode::ARG_ERR;
301 }
302
303 auto attempt_once = [&]() -> ErrorCode
304 {
305 ErrorCode ans = WaitControllerIdle();
306 if (ans != ErrorCode::OK)
307 {
308 return ans;
309 }
310
311 DL_I2C_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
312
313 size_t sent =
314 DL_I2C_fillControllerTXFIFO(res_.instance, data, static_cast<uint16_t>(size));
315 DL_I2C_startControllerTransfer(res_.instance, addr7, DL_I2C_CONTROLLER_DIRECTION_TX,
316 static_cast<uint16_t>(size));
317
318 while (sent < size)
319 {
320 uint32_t timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
321 while (DL_I2C_getRawInterruptStatus(
322 res_.instance, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER) == 0U)
323 {
324 if (CheckControllerError() != ErrorCode::OK)
325 {
326 return ErrorCode::FAILED;
327 }
328 if (timeout-- == 0)
329 {
330 return ErrorCode::BUSY;
331 }
332 }
333
334 sent += DL_I2C_fillControllerTXFIFO(res_.instance, data + sent,
335 static_cast<uint16_t>(size - sent));
336 }
337
338 ans = WaitBusIdle();
339 if (ans != ErrorCode::OK)
340 {
341 return ans;
342 }
343
344 return CheckControllerError();
345 };
346
347 ErrorCode last_error = ErrorCode::FAILED;
348 for (uint32_t attempt = 0; attempt < MSPM0_I2C_POLLING_ATTEMPTS; ++attempt)
349 {
350 last_error = attempt_once();
351 if (last_error == ErrorCode::OK)
352 {
353 return ErrorCode::OK;
354 }
355 mspm0_i2c_recover_controller(res_.instance);
356 }
357
358 return last_error;
359}
360
361ErrorCode MSPM0I2C::PollingRead7(uint16_t addr7, uint8_t* data, size_t size)
362{
363 if (size == 0)
364 {
365 return ErrorCode::OK;
366 }
367 if (size > MSPM0_I2C_MAX_TRANSFER_SIZE)
368 {
369 return ErrorCode::ARG_ERR;
370 }
371
372 auto attempt_once = [&]() -> ErrorCode
373 {
374 ErrorCode ans = WaitControllerIdle();
375 if (ans != ErrorCode::OK)
376 {
377 return ans;
378 }
379
380 DL_I2C_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
381 DL_I2C_startControllerTransfer(res_.instance, addr7, DL_I2C_CONTROLLER_DIRECTION_RX,
382 static_cast<uint16_t>(size));
383
384 size_t received = 0;
385 while (received < size)
386 {
387 uint32_t timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
388 while (DL_I2C_isControllerRXFIFOEmpty(res_.instance))
389 {
390 if (CheckControllerError() != ErrorCode::OK)
391 {
392 return ErrorCode::FAILED;
393 }
394 if (timeout-- == 0)
395 {
396 return ErrorCode::BUSY;
397 }
398 }
399
400 while (!DL_I2C_isControllerRXFIFOEmpty(res_.instance) && received < size)
401 {
402 data[received++] = DL_I2C_receiveControllerData(res_.instance);
403 }
404 }
405
406 ans = WaitBusIdle();
407 if (ans != ErrorCode::OK)
408 {
409 return ans;
410 }
411
412 return CheckControllerError();
413 };
414
415 ErrorCode last_error = ErrorCode::FAILED;
416 for (uint32_t attempt = 0; attempt < MSPM0_I2C_POLLING_ATTEMPTS; ++attempt)
417 {
418 last_error = attempt_once();
419 if (last_error == ErrorCode::OK)
420 {
421 return ErrorCode::OK;
422 }
423 mspm0_i2c_recover_controller(res_.instance);
424 }
425
426 return last_error;
427}
428
429ErrorCode MSPM0I2C::WaitDmaTransferDone(uint8_t channel_id) const
430{
431 uint32_t timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
432 while (DL_DMA_getTransferSize(DMA, channel_id) != 0U)
433 {
434 if (CheckControllerError() != ErrorCode::OK)
435 {
436 return ErrorCode::FAILED;
437 }
438 if (timeout-- == 0U)
439 {
440 return ErrorCode::BUSY;
441 }
442 }
443 return ErrorCode::OK;
444}
445
446ErrorCode MSPM0I2C::DmaWrite7(uint16_t addr7, ConstRawData write_data)
447{
448 if (write_data.size_ == 0)
449 {
450 return ErrorCode::OK;
451 }
452 if (write_data.size_ > MSPM0_I2C_MAX_TRANSFER_SIZE)
453 {
454 return ErrorCode::ARG_ERR;
455 }
456
457 auto stop_dma = [&]()
458 {
459 const uint32_t DMA_TX_MASK = mspm0_i2c_dma_channel_mask(I2C_DMA_TX_CHANNEL);
460 DL_DMA_disableChannel(DMA, I2C_DMA_TX_CHANNEL);
461 DL_DMA_clearInterruptStatus(DMA, DMA_TX_MASK);
462 };
463
464 auto attempt_once = [&]() -> ErrorCode
465 {
466 ErrorCode ans = WaitControllerIdle();
467 if (ans != ErrorCode::OK)
468 {
469 return ans;
470 }
471
472 DL_I2C_disableInterrupt(res_.instance, 0xFFFFFFFFU);
473 DL_I2C_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
474
475 const uint32_t DMA_TX_MASK = mspm0_i2c_dma_channel_mask(I2C_DMA_TX_CHANNEL);
476 DL_DMA_disableChannel(DMA, I2C_DMA_TX_CHANNEL);
477 DL_DMA_clearInterruptStatus(DMA, DMA_TX_MASK);
478 DL_DMA_setSrcAddr(
479 DMA, I2C_DMA_TX_CHANNEL,
480 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(write_data.addr_)));
481 DL_DMA_setDestAddr(DMA, I2C_DMA_TX_CHANNEL,
482 static_cast<uint32_t>(
483 reinterpret_cast<uintptr_t>(&res_.instance->MASTER.MTXDATA)));
484 DL_DMA_setTransferSize(DMA, I2C_DMA_TX_CHANNEL,
485 static_cast<uint16_t>(write_data.size_));
486 DL_DMA_enableChannel(DMA, I2C_DMA_TX_CHANNEL);
487
488 DL_I2C_startControllerTransfer(res_.instance, addr7, DL_I2C_CONTROLLER_DIRECTION_TX,
489 static_cast<uint16_t>(write_data.size_));
490
491 ans = WaitDmaTransferDone(I2C_DMA_TX_CHANNEL);
492 if (ans != ErrorCode::OK)
493 {
494 stop_dma();
495 return ans;
496 }
497
498 ans = WaitTransactionDone();
499 if (ans != ErrorCode::OK)
500 {
501 stop_dma();
502 return ans;
503 }
504
505 ans = WaitBusIdle();
506 if (ans != ErrorCode::OK)
507 {
508 stop_dma();
509 return ans;
510 }
511
512 stop_dma();
513 return CheckControllerError();
514 };
515
516 ErrorCode last_error = ErrorCode::FAILED;
517 for (uint32_t attempt = 0; attempt < MSPM0_I2C_POLLING_ATTEMPTS; ++attempt)
518 {
519 last_error = attempt_once();
520 if (last_error == ErrorCode::OK)
521 {
522 return ErrorCode::OK;
523 }
524 mspm0_i2c_recover_controller(res_.instance);
525 }
526
527 return last_error;
528}
529
530ErrorCode MSPM0I2C::DmaRead7(uint16_t addr7, RawData read_data)
531{
532 if (read_data.size_ == 0)
533 {
534 return ErrorCode::OK;
535 }
536 if (read_data.size_ > MSPM0_I2C_MAX_TRANSFER_SIZE)
537 {
538 return ErrorCode::ARG_ERR;
539 }
540
541 auto stop_dma = [&]()
542 {
543 const uint32_t DMA_RX_MASK = mspm0_i2c_dma_channel_mask(I2C_DMA_RX_CHANNEL);
544 DL_DMA_disableChannel(DMA, I2C_DMA_RX_CHANNEL);
545 DL_DMA_clearInterruptStatus(DMA, DMA_RX_MASK);
546 };
547
548 auto attempt_once = [&]() -> ErrorCode
549 {
550 ErrorCode ans = WaitControllerIdle();
551 if (ans != ErrorCode::OK)
552 {
553 return ans;
554 }
555
556 DL_I2C_disableInterrupt(res_.instance, 0xFFFFFFFFU);
557 DL_I2C_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
558
559 const uint32_t DMA_RX_MASK = mspm0_i2c_dma_channel_mask(I2C_DMA_RX_CHANNEL);
560 DL_DMA_disableChannel(DMA, I2C_DMA_RX_CHANNEL);
561 DL_DMA_clearInterruptStatus(DMA, DMA_RX_MASK);
562 DL_DMA_setSrcAddr(DMA, I2C_DMA_RX_CHANNEL,
563 static_cast<uint32_t>(
564 reinterpret_cast<uintptr_t>(&res_.instance->MASTER.MRXDATA)));
565 DL_DMA_setDestAddr(
566 DMA, I2C_DMA_RX_CHANNEL,
567 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(read_data.addr_)));
568 DL_DMA_setTransferSize(DMA, I2C_DMA_RX_CHANNEL,
569 static_cast<uint16_t>(read_data.size_));
570 DL_DMA_enableChannel(DMA, I2C_DMA_RX_CHANNEL);
571
572 DL_I2C_startControllerTransfer(res_.instance, addr7, DL_I2C_CONTROLLER_DIRECTION_RX,
573 static_cast<uint16_t>(read_data.size_));
574
575 ans = WaitDmaTransferDone(I2C_DMA_RX_CHANNEL);
576 if (ans != ErrorCode::OK)
577 {
578 stop_dma();
579 return ans;
580 }
581
582 ans = WaitTransactionDone();
583 if (ans != ErrorCode::OK)
584 {
585 stop_dma();
586 return ans;
587 }
588
589 ans = WaitBusIdle();
590 if (ans != ErrorCode::OK)
591 {
592 stop_dma();
593 return ans;
594 }
595
596 stop_dma();
597 return CheckControllerError();
598 };
599
600 ErrorCode last_error = ErrorCode::FAILED;
601 for (uint32_t attempt = 0; attempt < MSPM0_I2C_POLLING_ATTEMPTS; ++attempt)
602 {
603 last_error = attempt_once();
604 if (last_error == ErrorCode::OK)
605 {
606 return ErrorCode::OK;
607 }
608 mspm0_i2c_recover_controller(res_.instance);
609 }
610
611 return last_error;
612}
613
614ErrorCode MSPM0I2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
615 bool in_isr)
616{
617 if (read_data.size_ == 0)
618 {
619 if (op.type != ReadOperation::OperationType::BLOCK)
620 {
621 op.UpdateStatus(in_isr, ErrorCode::OK);
622 }
623 return ErrorCode::OK;
624 }
625
626 if (!mspm0_i2c_is_valid_addr7(slave_addr))
627 {
628 if (op.type != ReadOperation::OperationType::BLOCK)
629 {
631 }
632 return ErrorCode::ARG_ERR;
633 }
634
635 const uint16_t ADDR7 = slave_addr;
637 if (dma_enabled_ && read_data.size_ > dma_enable_min_size_)
638 {
639 ans = DmaRead7(ADDR7, read_data);
640 }
641 else
642 {
643 ans = PollingRead7(ADDR7, static_cast<uint8_t*>(read_data.addr_), read_data.size_);
644 }
645
646 if (op.type != ReadOperation::OperationType::BLOCK)
647 {
648 op.UpdateStatus(in_isr, ans);
649 }
650 return ans;
651}
652
653ErrorCode MSPM0I2C::Write(uint16_t slave_addr, ConstRawData write_data,
654 WriteOperation& op, bool in_isr)
655{
656 if (write_data.size_ == 0)
657 {
658 if (op.type != WriteOperation::OperationType::BLOCK)
659 {
660 op.UpdateStatus(in_isr, ErrorCode::OK);
661 }
662 return ErrorCode::OK;
663 }
664
665 if (!mspm0_i2c_is_valid_addr7(slave_addr))
666 {
667 if (op.type != WriteOperation::OperationType::BLOCK)
668 {
670 }
671 return ErrorCode::ARG_ERR;
672 }
673
674 const uint16_t ADDR7 = slave_addr;
676 if (dma_enabled_ && write_data.size_ > dma_enable_min_size_)
677 {
678 ans = DmaWrite7(ADDR7, write_data);
679 }
680 else
681 {
682 ans = PollingWrite7(ADDR7, static_cast<const uint8_t*>(write_data.addr_),
683 write_data.size_);
684 }
685
686 if (op.type != WriteOperation::OperationType::BLOCK)
687 {
688 op.UpdateStatus(in_isr, ans);
689 }
690 return ans;
691}
692
693ErrorCode MSPM0I2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
694 ConstRawData write_data, WriteOperation& op,
695 MemAddrLength mem_addr_size, bool in_isr)
696{
697 if (!mspm0_i2c_is_valid_addr7(slave_addr))
698 {
699 if (op.type != WriteOperation::OperationType::BLOCK)
700 {
702 }
703 return ErrorCode::ARG_ERR;
704 }
705 const size_t ADDR_SIZE = (mem_addr_size == MemAddrLength::BYTE_8) ? 1 : 2;
706 const size_t TOTAL_SIZE = ADDR_SIZE + write_data.size_;
707 if (TOTAL_SIZE > MSPM0_I2C_MAX_TRANSFER_SIZE)
708 {
709 return ErrorCode::ARG_ERR;
710 }
711 if (TOTAL_SIZE > stage_buffer_.size_)
712 {
713 return ErrorCode::ARG_ERR;
714 }
715
716 auto* tx = static_cast<uint8_t*>(stage_buffer_.addr_);
717 if (ADDR_SIZE == 1)
718 {
719 tx[0] = static_cast<uint8_t>(mem_addr & 0xFF);
720 }
721 else
722 {
723 tx[0] = static_cast<uint8_t>((mem_addr >> 8) & 0xFF);
724 tx[1] = static_cast<uint8_t>(mem_addr & 0xFF);
725 }
726 if (write_data.size_ > 0)
727 {
728 memcpy(tx + ADDR_SIZE, write_data.addr_, write_data.size_);
729 }
730
731 return Write(slave_addr, ConstRawData(tx, TOTAL_SIZE), op, in_isr);
732}
733
734ErrorCode MSPM0I2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
735 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
736{
737 if (read_data.size_ > MSPM0_I2C_MAX_TRANSFER_SIZE)
738 {
739 return ErrorCode::ARG_ERR;
740 }
741 if (read_data.size_ == 0)
742 {
743 if (op.type != ReadOperation::OperationType::BLOCK)
744 {
745 op.UpdateStatus(in_isr, ErrorCode::OK);
746 }
747 return ErrorCode::OK;
748 }
749
750 if (!mspm0_i2c_is_valid_addr7(slave_addr))
751 {
752 if (op.type != ReadOperation::OperationType::BLOCK)
753 {
755 }
756 return ErrorCode::ARG_ERR;
757 }
758
759 const uint16_t ADDR7 = slave_addr;
760 const size_t ADDR_SIZE = (mem_addr_size == MemAddrLength::BYTE_8) ? 1 : 2;
761 auto* addr_bytes = static_cast<uint8_t*>(stage_buffer_.addr_);
762 if (stage_buffer_.size_ < ADDR_SIZE)
763 {
764 return ErrorCode::ARG_ERR;
765 }
766
767 if (ADDR_SIZE == 1)
768 {
769 addr_bytes[0] = static_cast<uint8_t>(mem_addr & 0xFF);
770 }
771 else
772 {
773 addr_bytes[0] = static_cast<uint8_t>((mem_addr >> 8) & 0xFF);
774 addr_bytes[1] = static_cast<uint8_t>(mem_addr & 0xFF);
775 }
776
777 auto finalize = [&](ErrorCode code)
778 {
779 if (op.type != ReadOperation::OperationType::BLOCK)
780 {
781 op.UpdateStatus(in_isr, code);
782 }
783 return code;
784 };
785
786 auto try_repeated_start = [&]() -> ErrorCode
787 {
788 ErrorCode ans = WaitControllerIdle();
789 if (ans != ErrorCode::OK)
790 {
791 return ans;
792 }
793
794 DL_I2C_clearInterruptStatus(res_.instance, 0xFFFFFFFFU);
795
796 const uint16_t ADDR_SENT = DL_I2C_fillControllerTXFIFO(
797 res_.instance, addr_bytes, static_cast<uint16_t>(ADDR_SIZE));
798 if (ADDR_SENT != ADDR_SIZE)
799 {
800 return ErrorCode::FAILED;
801 }
802
803 DL_I2C_startControllerTransferAdvanced(
804 res_.instance, ADDR7, DL_I2C_CONTROLLER_DIRECTION_TX,
805 static_cast<uint16_t>(ADDR_SIZE), DL_I2C_CONTROLLER_START_ENABLE,
806 DL_I2C_CONTROLLER_STOP_DISABLE, DL_I2C_CONTROLLER_ACK_ENABLE);
807
808 uint32_t tx_done_timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
809 while (DL_I2C_getRawInterruptStatus(res_.instance,
810 DL_I2C_INTERRUPT_CONTROLLER_TX_DONE) == 0U)
811 {
812 if (CheckControllerError() != ErrorCode::OK)
813 {
814 return ErrorCode::FAILED;
815 }
816 if (tx_done_timeout-- == 0U)
817 {
818 return ErrorCode::BUSY;
819 }
820 }
821 DL_I2C_clearInterruptStatus(res_.instance, DL_I2C_INTERRUPT_CONTROLLER_TX_DONE);
822
823 if (CheckControllerError() != ErrorCode::OK)
824 {
825 return ErrorCode::FAILED;
826 }
827
828 DL_I2C_startControllerTransferAdvanced(
829 res_.instance, ADDR7, DL_I2C_CONTROLLER_DIRECTION_RX,
830 static_cast<uint16_t>(read_data.size_), DL_I2C_CONTROLLER_START_ENABLE,
831 DL_I2C_CONTROLLER_STOP_ENABLE, DL_I2C_CONTROLLER_ACK_DISABLE);
832
833 size_t received = 0;
834 auto* read_ptr = static_cast<uint8_t*>(read_data.addr_);
835 while (received < read_data.size_)
836 {
837 uint32_t timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
838 while (DL_I2C_isControllerRXFIFOEmpty(res_.instance))
839 {
840 if (CheckControllerError() != ErrorCode::OK)
841 {
842 return ErrorCode::FAILED;
843 }
844 if (timeout-- == 0)
845 {
846 return ErrorCode::BUSY;
847 }
848 }
849
850 while (!DL_I2C_isControllerRXFIFOEmpty(res_.instance) && received < read_data.size_)
851 {
852 read_ptr[received++] = DL_I2C_receiveControllerData(res_.instance);
853 }
854 }
855
856 uint32_t rx_done_timeout = MSPM0_I2C_WAIT_FIFO_TIMEOUT;
857 while (DL_I2C_getRawInterruptStatus(res_.instance,
858 DL_I2C_INTERRUPT_CONTROLLER_RX_DONE) == 0U)
859 {
860 if (CheckControllerError() != ErrorCode::OK)
861 {
862 return ErrorCode::FAILED;
863 }
864 if (rx_done_timeout-- == 0U)
865 {
866 return ErrorCode::BUSY;
867 }
868 }
869 DL_I2C_clearInterruptStatus(res_.instance, DL_I2C_INTERRUPT_CONTROLLER_RX_DONE);
870
871 ans = WaitBusIdle();
872 if (ans != ErrorCode::OK)
873 {
874 return ans;
875 }
876
877 return CheckControllerError();
878 };
879
880 ErrorCode last_error = ErrorCode::FAILED;
881 for (uint32_t attempt = 0; attempt < MSPM0_I2C_MEMREAD_RS_ATTEMPTS; ++attempt)
882 {
883 last_error = try_repeated_start();
884 if (last_error == ErrorCode::OK)
885 {
886 return finalize(ErrorCode::OK);
887 }
888 mspm0_i2c_recover_controller(res_.instance);
889 }
890
891 for (uint32_t attempt = 0; attempt < MSPM0_I2C_MEMREAD_FALLBACK_ATTEMPTS; ++attempt)
892 {
893 last_error = PollingWrite7(ADDR7, addr_bytes, ADDR_SIZE);
894 if (last_error == ErrorCode::OK)
895 {
896 last_error =
897 PollingRead7(ADDR7, static_cast<uint8_t*>(read_data.addr_), read_data.size_);
898 if (last_error == ErrorCode::OK)
899 {
900 return finalize(ErrorCode::OK);
901 }
902 }
903 mspm0_i2c_recover_controller(res_.instance);
904 }
905
906 return finalize(last_error);
907}
只读原始数据视图 / 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
ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation &op, bool in_isr=false) override
读取 I2C 设备的数据。 Reads data from an I2C device.
ErrorCode MemWrite(uint16_t slave_addr, uint16_t mem_addr, ConstRawData write_data, WriteOperation &op, MemAddrLength mem_addr_size=MemAddrLength::BYTE_8, bool in_isr=false) override
向 I2C 设备指定寄存器写入数据。 Writes data to a specific register of an I2C device.
ErrorCode MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data, ReadOperation &op, MemAddrLength mem_addr_size=MemAddrLength::BYTE_8, bool in_isr=false) override
从 I2C 设备指定寄存器读取数据。 Reads data from a specific register of an I2C device.
ErrorCode SetConfig(Configuration config) override
配置 I2C 设备参数。 Configures the I2C device settings.
ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation &op, bool in_isr=false) override
向 I2C 设备写入数据。 Writes data to an I2C device.
void UpdateStatus(bool in_isr, Status &&status)
按通知方式报告完成结果 / Report completion using the selected mode.
OperationType type
当前通知方式 / Current notification mode.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
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