libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
stm32_i2c.cpp
1#include "stm32_i2c.hpp"
2
3#include "stm32_dcache.hpp"
4#include "stm32_i2c_timing.hpp"
5#if defined(STM32F7)
6#include "stm32f7xx_ll_rcc.h"
7#endif
8#if defined(STM32H7)
9#include "stm32h7xx_ll_rcc.h"
10#endif
11#ifdef HAL_I2C_MODULE_ENABLED
12
13using namespace LibXR;
14
15STM32I2C* STM32I2C::map[STM32_I2C_NUMBER] = {nullptr};
16
17stm32_i2c_id_t STM32_I2C_GetID(I2C_TypeDef* hi2c)
18{ // NOLINT
19 if (hi2c == nullptr)
20 {
21 return stm32_i2c_id_t::STM32_I2C_ID_ERROR;
22 }
23#ifdef I2C1
24 else if (hi2c == I2C1)
25 { // NOLINT
26 return stm32_i2c_id_t::STM32_I2C1;
27 }
28#endif
29#ifdef I2C2
30 else if (hi2c == I2C2)
31 { // NOLINT
32 return stm32_i2c_id_t::STM32_I2C2;
33 }
34#endif
35#ifdef I2C3
36 else if (hi2c == I2C3)
37 { // NOLINT
38 return stm32_i2c_id_t::STM32_I2C3;
39 }
40#endif
41#ifdef I2C4
42 else if (hi2c == I2C4)
43 { // NOLINT
44 return stm32_i2c_id_t::STM32_I2C4;
45 }
46#endif
47#ifdef I2C5
48 else if (hi2c == I2C5)
49 { // NOLINT
50 return stm32_i2c_id_t::STM32_I2C5;
51 }
52#endif
53#ifdef I2C6
54 else if (hi2c == I2C6)
55 { // NOLINT
56 return stm32_i2c_id_t::STM32_I2C6;
57 }
58#endif
59#ifdef I2C7
60 else if (hi2c == I2C7)
61 { // NOLINT
62 return stm32_i2c_id_t::STM32_I2C7;
63 }
64#endif
65#ifdef I2C8
66 else if (hi2c == I2C8)
67 { // NOLINT
68 return stm32_i2c_id_t::STM32_I2C8;
69 }
70#endif
71 return stm32_i2c_id_t::STM32_I2C_ID_ERROR;
72}
73
74namespace
75{
76
77// 统一输入:
78// - 7-bit 模式:传 0x00~0x7F(不带 R/W 位),内部左移 1 给 HAL
79// - 10-bit 模式:传 0x000~0x3FF(不带 R/W 位),内部直接给 HAL
80static inline uint16_t EncodeHalDevAddress(const I2C_HandleTypeDef* hi2c,
81 uint16_t slave_addr)
82{
83 DEV_ASSERT(hi2c != nullptr);
84
85#if defined(I2C_ADDRESSINGMODE_10BIT)
86 if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT)
87 {
88 ASSERT(slave_addr <= 0x03FF);
89 return static_cast<uint16_t>(slave_addr & 0x03FF);
90 }
91#endif
92
93 // 默认按 7-bit
94 ASSERT(slave_addr <= 0x007F);
95 return static_cast<uint16_t>((slave_addr & 0x007F) << 1);
96}
97
98static inline ErrorCode MapHalStartFailure(const I2C_HandleTypeDef* hi2c,
99 HAL_StatusTypeDef st)
100{
101 // Preserve HAL's immediate start-failure signal without forcing a full controller
102 // reset.
103#ifdef HAL_I2C_ERROR_NONE
104 const uint32_t err = hi2c->ErrorCode;
105#ifdef HAL_I2C_WRONG_START
106 if ((err & (HAL_I2C_ERROR_TIMEOUT | HAL_I2C_WRONG_START)) != 0U)
107#else
108 if ((err & HAL_I2C_ERROR_TIMEOUT) != 0U)
109#endif
110 {
111 return ErrorCode::TIMEOUT;
112 }
113 if (err != HAL_I2C_ERROR_NONE)
114 {
115 return ErrorCode::FAILED;
116 }
117#else
118 UNUSED(hi2c);
119#endif
120 return (st == HAL_BUSY) ? ErrorCode::BUSY : ErrorCode::FAILED;
121}
122
123struct I2CFilterState
124{
125 bool analog_filter{false};
126 uint32_t digital_filter{0U};
127};
128
129static I2CFilterState CaptureI2CFilterState(const I2C_HandleTypeDef* handle);
130static void RestoreI2CFilterState(I2C_HandleTypeDef* handle, I2CFilterState state);
131static bool ResetI2CPeripheral(I2C_TypeDef* instance);
132
133static void RecoverAfterBlockTimeout(STM32I2C* i2c)
134{
135 DEV_ASSERT(i2c != nullptr);
136
137 auto* hi2c = i2c->i2c_handle_;
138 const I2CFilterState filter_state = CaptureI2CFilterState(hi2c);
139 i2c->recovering_ = true;
140 if (hi2c->hdmarx != nullptr)
141 {
142 (void)HAL_DMA_Abort(hi2c->hdmarx);
143 }
144 if (hi2c->hdmatx != nullptr)
145 {
146 (void)HAL_DMA_Abort(hi2c->hdmatx);
147 }
148
149 // Reset only the I2C peripheral so GPIO/NVIC and the selected RCC kernel
150 // clock source survive timeout recovery. Fall back to the legacy HAL
151 // DeInit path only on families without an RCC peripheral-reset primitive.
152 bool initialized = false;
153 if (ResetI2CPeripheral(hi2c->Instance))
154 {
155 initialized = HAL_I2C_Init(hi2c) == HAL_OK;
156 }
157 else
158 {
159 (void)HAL_I2C_DeInit(hi2c);
160 initialized = HAL_I2C_Init(hi2c) == HAL_OK;
161 }
162 if (initialized)
163 {
164 RestoreI2CFilterState(hi2c, filter_state);
165 }
166
167 i2c->read_ = false;
168 i2c->read_op_ = {};
169 i2c->write_op_ = {};
170 i2c->read_buff_ = {nullptr, 0};
171 i2c->recovering_ = false;
172}
173
174static inline ErrorCode WaitBlockResultAndRecoverTimeout(STM32I2C* i2c, uint32_t timeout)
175{
176 DEV_ASSERT(i2c != nullptr);
177 const ErrorCode ans = i2c->block_wait_.Wait(timeout);
178 if (ans == ErrorCode::TIMEOUT)
179 {
180 RecoverAfterBlockTimeout(i2c);
181 }
182 return ans;
183}
184
185static bool ResetI2CPeripheral(I2C_TypeDef* instance)
186{
187#if defined(I2C1) && defined(__HAL_RCC_I2C1_FORCE_RESET) && \
188 defined(__HAL_RCC_I2C1_RELEASE_RESET)
189 if (instance == I2C1)
190 {
191 __HAL_RCC_I2C1_FORCE_RESET();
192 __NOP();
193 __HAL_RCC_I2C1_RELEASE_RESET();
194 return true;
195 }
196#endif
197
198#if defined(I2C2) && defined(__HAL_RCC_I2C2_FORCE_RESET) && \
199 defined(__HAL_RCC_I2C2_RELEASE_RESET)
200 if (instance == I2C2)
201 {
202 __HAL_RCC_I2C2_FORCE_RESET();
203 __NOP();
204 __HAL_RCC_I2C2_RELEASE_RESET();
205 return true;
206 }
207#endif
208
209#if defined(I2C3) && defined(__HAL_RCC_I2C3_FORCE_RESET) && \
210 defined(__HAL_RCC_I2C3_RELEASE_RESET)
211 if (instance == I2C3)
212 {
213 __HAL_RCC_I2C3_FORCE_RESET();
214 __NOP();
215 __HAL_RCC_I2C3_RELEASE_RESET();
216 return true;
217 }
218#endif
219
220#if defined(I2C4) && defined(__HAL_RCC_I2C4_FORCE_RESET) && \
221 defined(__HAL_RCC_I2C4_RELEASE_RESET)
222 if (instance == I2C4)
223 {
224 __HAL_RCC_I2C4_FORCE_RESET();
225 __NOP();
226 __HAL_RCC_I2C4_RELEASE_RESET();
227 return true;
228 }
229#endif
230
231#if defined(I2C5) && defined(__HAL_RCC_I2C5_FORCE_RESET) && \
232 defined(__HAL_RCC_I2C5_RELEASE_RESET)
233 if (instance == I2C5)
234 {
235 __HAL_RCC_I2C5_FORCE_RESET();
236 __NOP();
237 __HAL_RCC_I2C5_RELEASE_RESET();
238 return true;
239 }
240#endif
241
242#if defined(I2C6) && defined(__HAL_RCC_I2C6_FORCE_RESET) && \
243 defined(__HAL_RCC_I2C6_RELEASE_RESET)
244 if (instance == I2C6)
245 {
246 __HAL_RCC_I2C6_FORCE_RESET();
247 __NOP();
248 __HAL_RCC_I2C6_RELEASE_RESET();
249 return true;
250 }
251#endif
252
253#if defined(I2C7) && defined(__HAL_RCC_I2C7_FORCE_RESET) && \
254 defined(__HAL_RCC_I2C7_RELEASE_RESET)
255 if (instance == I2C7)
256 {
257 __HAL_RCC_I2C7_FORCE_RESET();
258 __NOP();
259 __HAL_RCC_I2C7_RELEASE_RESET();
260 return true;
261 }
262#endif
263
264#if defined(I2C8) && defined(__HAL_RCC_I2C8_FORCE_RESET) && \
265 defined(__HAL_RCC_I2C8_RELEASE_RESET)
266 if (instance == I2C8)
267 {
268 __HAL_RCC_I2C8_FORCE_RESET();
269 __NOP();
270 __HAL_RCC_I2C8_RELEASE_RESET();
271 return true;
272 }
273#endif
274
275 return false;
276}
277
278/* Resolve a non-zero clock only when the selected source is known. */
279#if defined(STM32H7) && defined(HAL_RCC_MODULE_ENABLED)
280static uint32_t GetH7HSIClock()
281{
282#if defined(RCC_CR_HSIRDY)
283 if ((RCC->CR & RCC_CR_HSIRDY) == 0U)
284 {
285 return 0U;
286 }
287#endif
288#if defined(__HAL_RCC_GET_HSI_DIVIDER) && defined(RCC_CR_HSIDIV_Pos)
289 return HSI_VALUE >> (__HAL_RCC_GET_HSI_DIVIDER() >> RCC_CR_HSIDIV_Pos);
290#else
291 return HSI_VALUE;
292#endif
293}
294
295static uint32_t GetH7CSIClock()
296{
297#if defined(RCC_CR_CSIRDY)
298 return (RCC->CR & RCC_CR_CSIRDY) != 0U ? CSI_VALUE : 0U;
299#else
300 return 0U;
301#endif
302}
303
304static uint32_t GetH7Pll3RClock()
305{
306#if defined(RCC_CR_PLL3RDY)
307 if ((RCC->CR & RCC_CR_PLL3RDY) == 0U)
308 {
309 return 0U;
310 }
311#endif
312#if defined(RCC_PLLCFGR_DIVR3EN)
313 if ((RCC->PLLCFGR & RCC_PLLCFGR_DIVR3EN) == 0U)
314 {
315 return 0U;
316 }
317#elif defined(RCC_PLLCFGR_PLL3REN)
318 if ((RCC->PLLCFGR & RCC_PLLCFGR_PLL3REN) == 0U)
319 {
320 return 0U;
321 }
322#else
323 return 0U;
324#endif
325 PLL3_ClocksTypeDef pll3{};
326 HAL_RCCEx_GetPLL3ClockFreq(&pll3);
327 return pll3.PLL3_R_Frequency;
328}
329
330static uint32_t GetH7I2CClock(I2C_TypeDef* instance)
331{
332#if defined(I2C4) && defined(LL_RCC_I2C4_CLKSOURCE)
333 if (instance == I2C4)
334 {
335 const uint32_t source = LL_RCC_GetI2CClockSource(LL_RCC_I2C4_CLKSOURCE);
336#if defined(LL_RCC_I2C4_CLKSOURCE_PCLK4)
337 if (source == LL_RCC_I2C4_CLKSOURCE_PCLK4)
338 {
339 return HAL_RCCEx_GetD3PCLK1Freq();
340 }
341#endif
342#if defined(LL_RCC_I2C4_CLKSOURCE_PLL3R)
343 if (source == LL_RCC_I2C4_CLKSOURCE_PLL3R)
344 {
345 return GetH7Pll3RClock();
346 }
347#endif
348#if defined(LL_RCC_I2C4_CLKSOURCE_HSI)
349 if (source == LL_RCC_I2C4_CLKSOURCE_HSI)
350 {
351 return GetH7HSIClock();
352 }
353#endif
354#if defined(LL_RCC_I2C4_CLKSOURCE_CSI)
355 if (source == LL_RCC_I2C4_CLKSOURCE_CSI)
356 {
357 return GetH7CSIClock();
358 }
359#endif
360 return 0U;
361 }
362#endif
363
364#if defined(LL_RCC_I2C123_CLKSOURCE)
365 const uint32_t source = LL_RCC_GetI2CClockSource(LL_RCC_I2C123_CLKSOURCE);
366#if defined(LL_RCC_I2C123_CLKSOURCE_PCLK1)
367 if (source == LL_RCC_I2C123_CLKSOURCE_PCLK1)
368 {
369 return HAL_RCC_GetPCLK1Freq();
370 }
371#endif
372#if defined(LL_RCC_I2C123_CLKSOURCE_PLL3R)
373 if (source == LL_RCC_I2C123_CLKSOURCE_PLL3R)
374 {
375 return GetH7Pll3RClock();
376 }
377#endif
378#if defined(LL_RCC_I2C123_CLKSOURCE_HSI)
379 if (source == LL_RCC_I2C123_CLKSOURCE_HSI)
380 {
381 return GetH7HSIClock();
382 }
383#endif
384#if defined(LL_RCC_I2C123_CLKSOURCE_CSI)
385 if (source == LL_RCC_I2C123_CLKSOURCE_CSI)
386 {
387 return GetH7CSIClock();
388 }
389#endif
390#elif defined(LL_RCC_I2C1235_CLKSOURCE)
391 const uint32_t source = LL_RCC_GetI2CClockSource(LL_RCC_I2C1235_CLKSOURCE);
392#if defined(LL_RCC_I2C1235_CLKSOURCE_PCLK1)
393 if (source == LL_RCC_I2C1235_CLKSOURCE_PCLK1)
394 {
395 return HAL_RCC_GetPCLK1Freq();
396 }
397#endif
398#if defined(LL_RCC_I2C1235_CLKSOURCE_PLL3R)
399 if (source == LL_RCC_I2C1235_CLKSOURCE_PLL3R)
400 {
401 return GetH7Pll3RClock();
402 }
403#endif
404#if defined(LL_RCC_I2C1235_CLKSOURCE_HSI)
405 if (source == LL_RCC_I2C1235_CLKSOURCE_HSI)
406 {
407 return GetH7HSIClock();
408 }
409#endif
410#if defined(LL_RCC_I2C1235_CLKSOURCE_CSI)
411 if (source == LL_RCC_I2C1235_CLKSOURCE_CSI)
412 {
413 return GetH7CSIClock();
414 }
415#endif
416#endif
417 return 0U;
418}
419#endif
420
421#if defined(STM32F7) && defined(HAL_RCC_MODULE_ENABLED)
422static uint32_t GetF7I2CClock(I2C_TypeDef* instance)
423{
424#define LIBXR_F7_I2C_CLOCK(ID) \
425 if (instance == I2C##ID) \
426 { \
427 const uint32_t source = LL_RCC_GetI2CClockSource(LL_RCC_I2C##ID##_CLKSOURCE); \
428 if (source == LL_RCC_I2C##ID##_CLKSOURCE_PCLK1) return HAL_RCC_GetPCLK1Freq(); \
429 if (source == LL_RCC_I2C##ID##_CLKSOURCE_SYSCLK) return HAL_RCC_GetSysClockFreq(); \
430 if (source == LL_RCC_I2C##ID##_CLKSOURCE_HSI) \
431 { \
432 return (RCC->CR & RCC_CR_HSIRDY) != 0U ? HSI_VALUE : 0U; \
433 } \
434 return 0U; \
435 }
436#if defined(I2C1)
437 LIBXR_F7_I2C_CLOCK(1)
438#endif
439#if defined(I2C2)
440 LIBXR_F7_I2C_CLOCK(2)
441#endif
442#if defined(I2C3)
443 LIBXR_F7_I2C_CLOCK(3)
444#endif
445#if defined(I2C4)
446 LIBXR_F7_I2C_CLOCK(4)
447#endif
448#undef LIBXR_F7_I2C_CLOCK
449 return 0U;
450}
451#endif
452
453template <typename I2CInstance>
454static uint32_t GetI2CClock(I2CInstance* instance)
455{
456#if defined(STM32H7) && defined(HAL_RCC_MODULE_ENABLED)
457 return GetH7I2CClock(instance);
458#endif
459#if defined(STM32F7) && defined(HAL_RCC_MODULE_ENABLED)
460 return GetF7I2CClock(instance);
461#endif
462#if defined(HAL_RCC_MODULE_ENABLED)
463#if defined(RCC_PERIPHCLK_I2C8) && defined(I2C8)
464 if (instance == I2C8) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C8);
465#endif
466#if defined(RCC_PERIPHCLK_I2C7) && defined(I2C7)
467 if (instance == I2C7) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C7);
468#endif
469#if defined(RCC_PERIPHCLK_I2C6) && defined(I2C6)
470 if (instance == I2C6) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C6);
471#endif
472#if defined(RCC_PERIPHCLK_I2C5) && defined(I2C5)
473 if (instance == I2C5) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C5);
474#endif
475#if defined(RCC_PERIPHCLK_I2C4) && defined(I2C4)
476 if (instance == I2C4) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C4);
477#endif
478#if defined(RCC_PERIPHCLK_I2C1_I3C1) && defined(I2C1)
479 if (instance == I2C1) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C1_I3C1);
480#endif
481#if defined(RCC_PERIPHCLK_I2C23)
482#if defined(I2C2)
483 if (instance == I2C2) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C23);
484#endif
485#if defined(I2C3)
486 if (instance == I2C3) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C23);
487#endif
488#endif
489#if defined(RCC_PERIPHCLK_I2C3) && defined(I2C3)
490 if (instance == I2C3) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C3);
491#endif
492#if defined(RCC_PERIPHCLK_I2C2) && defined(I2C2)
493 if (instance == I2C2) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C2);
494#endif
495#if defined(RCC_PERIPHCLK_I2C1) && defined(I2C1)
496 if (instance == I2C1) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C1);
497#endif
498#if defined(RCC_PERIPHCLK_I2C1235) && defined(I2C5)
499 if (instance == I2C5) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C1235);
500#endif
501#if defined(RCC_PERIPHCLK_I2C123)
502#if defined(I2C1)
503 if (instance == I2C1) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C123);
504#endif
505#if defined(I2C2)
506 if (instance == I2C2) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C123);
507#endif
508#if defined(I2C3)
509 if (instance == I2C3) return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C123);
510#endif
511#endif
512#endif
513#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32C0) && defined(I2C2) && \
514 defined(RCC_PERIPHCLK_I2C1) && !defined(RCC_CCIPR_I2C2SEL)
515 // C0 aliases I2C2's selector to I2C1's RCC field.
516 if (instance == I2C2)
517 {
518 return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C1);
519 }
520#endif
521#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32F0) && defined(I2C2) && \
522 !defined(RCC_CFGR3_I2C2SW)
523 // F0's I2C2 is fixed to the APB1 clock; only I2C1 has a selector.
524 if (instance == I2C2)
525 {
526 return HAL_RCC_GetPCLK1Freq();
527 }
528#endif
529#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32G0) && defined(I2C3) && \
530 !defined(RCC_CCIPR_I2C3SEL)
531 // I2C3 on the G0 parts with this instance is a fixed APB1 peripheral.
532 if (instance == I2C3)
533 {
534 return HAL_RCC_GetPCLK1Freq();
535 }
536#endif
537#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32U0) && defined(I2C2) && \
538 !defined(RCC_CCIPR_I2C2SEL)
539 if (instance == I2C2)
540 {
541 return HAL_RCC_GetPCLK1Freq();
542 }
543#endif
544#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32U0) && defined(I2C4) && \
545 !defined(RCC_CCIPR_I2C4SEL)
546 if (instance == I2C4)
547 {
548 return HAL_RCC_GetPCLK1Freq();
549 }
550#endif
551#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32WB0) && \
552 (defined(I2C1) || defined(I2C2))
553 // WB0 has no independent I2C kernel selector; APB1 follows SYSCLK.
554#if defined(I2C2)
555 if (instance == I2C2)
556 {
557 return HAL_RCC_GetSysClockFreq();
558 }
559#endif
560#if defined(I2C1)
561 if (instance == I2C1)
562 {
563 return HAL_RCC_GetSysClockFreq();
564 }
565#endif
566#endif
567#if defined(HAL_RCC_MODULE_ENABLED) && defined(STM32WL3) && \
568 (defined(I2C1) || defined(I2C2))
569 // WL3 has no independent I2C kernel selector; APB1 follows SYSCLK.
570#if defined(I2C2)
571 if (instance == I2C2)
572 {
573 return HAL_RCC_GetSysClockFreq();
574 }
575#endif
576#if defined(I2C1)
577 if (instance == I2C1)
578 {
579 return HAL_RCC_GetSysClockFreq();
580 }
581#endif
582#endif
583 return 0U;
584}
585
586static I2CFilterState CaptureI2CFilterState(const I2C_HandleTypeDef* handle)
587{
588 UNUSED(handle);
589 I2CFilterState state;
590#if defined(I2C_CR1_ANFOFF)
591 state.analog_filter = (handle->Instance->CR1 & I2C_CR1_ANFOFF) == 0U;
592#elif defined(I2C_FLTR_ANOFF)
593 state.analog_filter = (handle->Instance->FLTR & I2C_FLTR_ANOFF) == 0U;
594#endif
595#if defined(I2C_CR1_DNF) && defined(I2C_CR1_DNF_Pos)
596 state.digital_filter = (handle->Instance->CR1 & I2C_CR1_DNF) >> I2C_CR1_DNF_Pos;
597#elif defined(I2C_FLTR_DNF)
598 state.digital_filter = handle->Instance->FLTR & I2C_FLTR_DNF;
599#endif
600 return state;
601}
602
603static void RestoreI2CFilterState(I2C_HandleTypeDef* handle, I2CFilterState state)
604{
605 UNUSED(state);
606 const uint32_t was_enabled = handle->Instance->CR1 & I2C_CR1_PE;
607 // PE must already be clear before modifying a filter register.
608 CLEAR_BIT(handle->Instance->CR1, I2C_CR1_PE);
609#if defined(I2C_CR1_ANFOFF)
610 MODIFY_REG(handle->Instance->CR1, I2C_CR1_ANFOFF,
611 state.analog_filter ? 0U : I2C_CR1_ANFOFF);
612#elif defined(I2C_FLTR_ANOFF)
613 MODIFY_REG(handle->Instance->FLTR, I2C_FLTR_ANOFF,
614 state.analog_filter ? 0U : I2C_FLTR_ANOFF);
615#endif
616#if defined(I2C_CR1_DNF) && defined(I2C_CR1_DNF_Pos)
617 MODIFY_REG(handle->Instance->CR1, I2C_CR1_DNF, state.digital_filter << I2C_CR1_DNF_Pos);
618#elif defined(I2C_FLTR_DNF)
619 MODIFY_REG(handle->Instance->FLTR, I2C_FLTR_DNF, state.digital_filter);
620#endif
621 SET_BIT(handle->Instance->CR1, was_enabled);
622}
623
624static STM32I2C* FindI2C(I2C_HandleTypeDef* handle)
625{
626 if (handle == nullptr || handle->Instance == nullptr)
627 {
628 return nullptr;
629 }
630 const stm32_i2c_id_t id = STM32_I2C_GetID(handle->Instance);
631 if (id == STM32_I2C_ID_ERROR || id >= STM32_I2C_NUMBER)
632 {
633 return nullptr;
634 }
635 return STM32I2C::map[id];
636}
637} // namespace
638
639STM32I2C::STM32I2C(I2C_HandleTypeDef* hi2c, RawData dma_buff,
640 uint32_t dma_enable_min_size)
641 : I2C(),
642 id_(hi2c == nullptr ? STM32_I2C_ID_ERROR : STM32_I2C_GetID(hi2c->Instance)),
643 i2c_handle_(hi2c),
644 dma_enable_min_size_(dma_enable_min_size),
645 dma_buff_(dma_buff)
646{
647 ASSERT(id_ != STM32_I2C_ID_ERROR);
648 ASSERT(id_ < STM32_I2C_NUMBER);
649 map[id_] = this;
650}
651
652ErrorCode STM32I2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
653 bool in_isr)
654{
655 if (i2c_handle_->State != HAL_I2C_STATE_READY)
656 {
657 return ErrorCode::BUSY;
658 }
659
660 read_ = true;
661
662 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
663
664 if (read_data.size_ > dma_enable_min_size_)
665 {
666 read_op_ = op;
667 read_buff_ = read_data;
668 if (op.type == ReadOperation::OperationType::BLOCK)
669 {
670 // Arm the BLOCK waiter before HAL exposes completion to IRQ context.
671 block_wait_.Start(*op.data.sem_info.sem);
672 }
673 op.MarkAsRunning();
674 const HAL_StatusTypeDef st = HAL_I2C_Master_Receive_DMA(
675 i2c_handle_, dev_addr, reinterpret_cast<uint8_t*>(dma_buff_.addr_),
676 read_data.size_);
677 if (st != HAL_OK)
678 {
679 if (op.type == ReadOperation::OperationType::BLOCK)
680 {
681 block_wait_.Cancel();
682 return MapHalStartFailure(i2c_handle_, st);
683 }
684 if (op.type == ReadOperation::OperationType::POLLING)
685 {
686 op.UpdateStatus(in_isr, ErrorCode::BUSY);
687 }
688 return ErrorCode::BUSY;
689 }
690 if (op.type == ReadOperation::OperationType::BLOCK)
691 {
692 return WaitBlockResultAndRecoverTimeout(this, op.data.sem_info.timeout);
693 }
694 return ErrorCode::OK;
695 }
696 else
697 {
698 auto ans = HAL_I2C_Master_Receive(i2c_handle_, dev_addr,
699 reinterpret_cast<uint8_t*>(read_data.addr_),
700 read_data.size_, 20) == HAL_OK
703 // BLOCK 模式下沿用统一状态更新路径。
704 // Reuse the same status update path for BLOCK mode.
705 if (op.type != ReadOperation::OperationType::BLOCK)
706 {
707 op.UpdateStatus(in_isr, ans);
708 }
709 return ans;
710 }
711}
712
713ErrorCode STM32I2C::Write(uint16_t slave_addr, ConstRawData write_data,
714 WriteOperation& op, bool in_isr)
715{
716 if (i2c_handle_->State != HAL_I2C_STATE_READY)
717 {
718 return ErrorCode::BUSY;
719 }
720
721 read_ = false;
722
723 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
724
725 Memory::FastCopy(dma_buff_.addr_, write_data.addr_, write_data.size_);
726
727 if (write_data.size_ > dma_enable_min_size_)
728 {
729 write_op_ = op;
730 if (op.type == WriteOperation::OperationType::BLOCK)
731 {
732 // Arm the BLOCK waiter before HAL exposes completion to IRQ context.
733 block_wait_.Start(*op.data.sem_info.sem);
734 }
735 STM32_CleanDCacheByAddr(dma_buff_.addr_, write_data.size_);
736 op.MarkAsRunning();
737 const HAL_StatusTypeDef st = HAL_I2C_Master_Transmit_DMA(
738 i2c_handle_, dev_addr, reinterpret_cast<uint8_t*>(dma_buff_.addr_),
739 write_data.size_);
740 if (st != HAL_OK)
741 {
742 if (op.type == WriteOperation::OperationType::BLOCK)
743 {
744 block_wait_.Cancel();
745 return MapHalStartFailure(i2c_handle_, st);
746 }
747 if (op.type == WriteOperation::OperationType::POLLING)
748 {
749 op.UpdateStatus(in_isr, ErrorCode::BUSY);
750 }
751 return ErrorCode::BUSY;
752 }
753 if (op.type == WriteOperation::OperationType::BLOCK)
754 {
755 return WaitBlockResultAndRecoverTimeout(this, op.data.sem_info.timeout);
756 }
757 return ErrorCode::OK;
758 }
759 else
760 {
761 auto ans = HAL_I2C_Master_Transmit(i2c_handle_, dev_addr,
762 reinterpret_cast<uint8_t*>(dma_buff_.addr_),
763 write_data.size_, 20) == HAL_OK
766 if (op.type != WriteOperation::OperationType::BLOCK)
767 {
768 op.UpdateStatus(in_isr, ans);
769 }
770 return ans;
771 }
772}
773
774ErrorCode STM32I2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
775 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
776{
777 ASSERT(read_data.size_ <= dma_buff_.size_);
778
779 if (i2c_handle_->State != HAL_I2C_STATE_READY)
780 {
781 return ErrorCode::BUSY;
782 }
783
784 read_ = true;
785
786 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
787
788 if (read_data.size_ > dma_enable_min_size_)
789 {
790 read_op_ = op;
791 read_buff_ = read_data;
792 if (op.type == ReadOperation::OperationType::BLOCK)
793 {
794 // Arm the BLOCK waiter before HAL exposes completion to IRQ context.
795 block_wait_.Start(*op.data.sem_info.sem);
796 }
797 op.MarkAsRunning();
798 const HAL_StatusTypeDef st = HAL_I2C_Mem_Read_DMA(
799 i2c_handle_, dev_addr, mem_addr,
800 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
801 : I2C_MEMADD_SIZE_16BIT,
802 reinterpret_cast<uint8_t*>(dma_buff_.addr_), read_data.size_);
803 if (st != HAL_OK)
804 {
805 if (op.type == ReadOperation::OperationType::BLOCK)
806 {
807 block_wait_.Cancel();
808 return MapHalStartFailure(i2c_handle_, st);
809 }
810 if (op.type == ReadOperation::OperationType::POLLING)
811 {
812 op.UpdateStatus(in_isr, ErrorCode::BUSY);
813 }
814 return ErrorCode::BUSY;
815 }
816 if (op.type == ReadOperation::OperationType::BLOCK)
817 {
818 return WaitBlockResultAndRecoverTimeout(this, op.data.sem_info.timeout);
819 }
820 return ErrorCode::OK;
821 }
822 else
823 {
824 auto ans =
825 HAL_I2C_Mem_Read(i2c_handle_, dev_addr, mem_addr,
826 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
827 : I2C_MEMADD_SIZE_16BIT,
828 reinterpret_cast<uint8_t*>(read_data.addr_), read_data.size_,
829 20) == HAL_OK
832
833 if (op.type != ReadOperation::OperationType::BLOCK)
834 {
835 op.UpdateStatus(in_isr, ans);
836 }
837 return ans;
838 }
839}
840
841ErrorCode STM32I2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
842 ConstRawData write_data, WriteOperation& op,
843 MemAddrLength mem_addr_size, bool in_isr)
844{
845 ASSERT(write_data.size_ <= dma_buff_.size_);
846
847 if (i2c_handle_->State != HAL_I2C_STATE_READY)
848 {
849 return ErrorCode::BUSY;
850 }
851
852 read_ = false;
853
854 const uint16_t dev_addr = EncodeHalDevAddress(i2c_handle_, slave_addr);
855
856 Memory::FastCopy(dma_buff_.addr_, write_data.addr_, write_data.size_);
857
858 if (write_data.size_ > dma_enable_min_size_)
859 {
860 write_op_ = op;
861 if (op.type == WriteOperation::OperationType::BLOCK)
862 {
863 // Arm the BLOCK waiter before HAL exposes completion to IRQ context.
864 block_wait_.Start(*op.data.sem_info.sem);
865 }
866 STM32_CleanDCacheByAddr(dma_buff_.addr_, write_data.size_);
867 op.MarkAsRunning();
868 const HAL_StatusTypeDef st = HAL_I2C_Mem_Write_DMA(
869 i2c_handle_, dev_addr, mem_addr,
870 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
871 : I2C_MEMADD_SIZE_16BIT,
872 reinterpret_cast<uint8_t*>(dma_buff_.addr_), write_data.size_);
873 if (st != HAL_OK)
874 {
875 if (op.type == WriteOperation::OperationType::BLOCK)
876 {
877 block_wait_.Cancel();
878 return MapHalStartFailure(i2c_handle_, st);
879 }
880 if (op.type == WriteOperation::OperationType::POLLING)
881 {
882 op.UpdateStatus(in_isr, ErrorCode::BUSY);
883 }
884 return ErrorCode::BUSY;
885 }
886 if (op.type == WriteOperation::OperationType::BLOCK)
887 {
888 return WaitBlockResultAndRecoverTimeout(this, op.data.sem_info.timeout);
889 }
890 return ErrorCode::OK;
891 }
892 else
893 {
894 auto ans =
895 HAL_I2C_Mem_Write(i2c_handle_, dev_addr, mem_addr,
896 mem_addr_size == MemAddrLength::BYTE_8 ? I2C_MEMADD_SIZE_8BIT
897 : I2C_MEMADD_SIZE_16BIT,
898 reinterpret_cast<uint8_t*>(dma_buff_.addr_), write_data.size_,
899 20) == HAL_OK
902
903 if (op.type != WriteOperation::OperationType::BLOCK)
904 {
905 op.UpdateStatus(in_isr, ans);
906 }
907 return ans;
908 }
909}
910
912{
913 if (i2c_handle_ == nullptr ||
914 STM32_I2C_GetID(i2c_handle_->Instance) == STM32_I2C_ID_ERROR ||
915 config.clock_speed == 0U)
916 {
917 return ErrorCode::ARG_ERR;
918 }
919 const auto is_busy = [this]()
920 {
921 return recovering_ || i2c_handle_->State != HAL_I2C_STATE_READY ||
922 i2c_handle_->Lock == HAL_LOCKED ||
923 __HAL_I2C_GET_FLAG(i2c_handle_, I2C_FLAG_BUSY) != RESET;
924 };
925 uint32_t timing = 0U;
926 const auto old_init = i2c_handle_->Init;
927 const I2CFilterState old_filter_state = CaptureI2CFilterState(i2c_handle_);
928 if constexpr (HasClockSpeed<decltype(i2c_handle_)>::value)
929 {
930 if (config.clock_speed > 400000U)
931 {
933 }
934#if defined(I2C_CCR_CCR) && defined(HAL_RCC_MODULE_ENABLED)
935 const uint32_t pclk = HAL_RCC_GetPCLK1Freq();
936 const uint32_t factor =
937 config.clock_speed <= 100000U
938 ? 2U
939 : (i2c_handle_->Init.DutyCycle == I2C_DUTYCYCLE_16_9 ? 25U : 3U);
940 const uint64_t denominator = uint64_t(config.clock_speed) * factor;
941 if (pclk == 0U || (uint64_t(pclk) + denominator - 1U) / denominator > I2C_CCR_CCR)
942 {
944 }
945#endif
946 }
947 else if constexpr (HasTiming<decltype(i2c_handle_)>::value)
948 {
949 if (!STM32I2CTiming::Compute(GetI2CClock(i2c_handle_->Instance), config.clock_speed,
950 old_filter_state.analog_filter,
951 old_filter_state.digital_filter, timing))
952 {
954 }
955 }
956 else
957 {
959 }
960
961 // Report intrinsic configuration errors before transient controller state.
962 // Calculation can be preempted, so re-check immediately before reset.
963 if (is_busy())
964 {
965 return ErrorCode::BUSY;
966 }
967 if constexpr (HasClockSpeed<decltype(i2c_handle_)>::value)
968 {
969 SetClockSpeed(i2c_handle_, config);
970 }
971 else
972 {
973 SetTiming(i2c_handle_, timing);
974 }
975 if (!ResetI2CPeripheral(i2c_handle_->Instance))
976 {
977 i2c_handle_->Init = old_init;
979 }
980 if (HAL_I2C_Init(i2c_handle_) != HAL_OK)
981 {
982 i2c_handle_->Init = old_init;
983 if (ResetI2CPeripheral(i2c_handle_->Instance) && HAL_I2C_Init(i2c_handle_) == HAL_OK)
984 {
985 RestoreI2CFilterState(i2c_handle_, old_filter_state);
986 }
987 return ErrorCode::INIT_ERR;
988 }
989 RestoreI2CFilterState(i2c_handle_, old_filter_state);
990 return ErrorCode::OK;
991}
992
993extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c)
994{
995 STM32I2C* i2c = FindI2C(hi2c);
996 if (i2c && !i2c->recovering_ &&
997 (i2c->read_op_.type != ReadOperation::OperationType::NONE))
998 {
1000#ifdef HAL_I2C_ERROR_NONE
1001 ec = (hi2c->ErrorCode == HAL_I2C_ERROR_NONE) ? ErrorCode::OK : ErrorCode::FAILED;
1002#endif
1003 STM32_InvalidateDCacheByAddr(i2c->dma_buff_.addr_, i2c->read_buff_.size_);
1004 if (ec == ErrorCode::OK)
1005 {
1006 Memory::FastCopy(i2c->read_buff_.addr_, i2c->dma_buff_.addr_,
1007 i2c->read_buff_.size_);
1008 }
1009 if (i2c->read_op_.type == ReadOperation::OperationType::BLOCK)
1010 {
1011 (void)i2c->block_wait_.TryPost(true, ec);
1012 }
1013 else
1014 {
1015 i2c->read_op_.UpdateStatus(true, ec);
1016 }
1017 }
1018}
1019
1020extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c)
1021{
1022 STM32I2C* i2c = FindI2C(hi2c);
1023 if (i2c && !i2c->recovering_ &&
1024 (i2c->write_op_.type != WriteOperation::OperationType::NONE))
1025 {
1027#ifdef HAL_I2C_ERROR_NONE
1028 ec = (hi2c->ErrorCode == HAL_I2C_ERROR_NONE) ? ErrorCode::OK : ErrorCode::FAILED;
1029#endif
1030 if (i2c->write_op_.type == WriteOperation::OperationType::BLOCK)
1031 {
1032 (void)i2c->block_wait_.TryPost(true, ec);
1033 }
1034 else
1035 {
1036 i2c->write_op_.UpdateStatus(true, ec);
1037 }
1038 }
1039}
1040
1041extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c)
1042{
1043 STM32I2C* i2c = FindI2C(hi2c);
1044 if (i2c && !i2c->recovering_ &&
1045 (i2c->write_op_.type != WriteOperation::OperationType::NONE))
1046 {
1048#ifdef HAL_I2C_ERROR_NONE
1049 ec = (hi2c->ErrorCode == HAL_I2C_ERROR_NONE) ? ErrorCode::OK : ErrorCode::FAILED;
1050#endif
1051 if (i2c->write_op_.type == WriteOperation::OperationType::BLOCK)
1052 {
1053 (void)i2c->block_wait_.TryPost(true, ec);
1054 }
1055 else
1056 {
1057 i2c->write_op_.UpdateStatus(true, ec);
1058 }
1059 }
1060}
1061
1062extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c)
1063{
1064 STM32I2C* i2c = FindI2C(hi2c);
1065 if (i2c && !i2c->recovering_ &&
1066 (i2c->read_op_.type != ReadOperation::OperationType::NONE))
1067 {
1069#ifdef HAL_I2C_ERROR_NONE
1070 ec = (hi2c->ErrorCode == HAL_I2C_ERROR_NONE) ? ErrorCode::OK : ErrorCode::FAILED;
1071#endif
1072 STM32_InvalidateDCacheByAddr(i2c->dma_buff_.addr_, i2c->read_buff_.size_);
1073 if (ec == ErrorCode::OK)
1074 {
1075 Memory::FastCopy(i2c->read_buff_.addr_, i2c->dma_buff_.addr_,
1076 i2c->read_buff_.size_);
1077 }
1078 if (i2c->read_op_.type == ReadOperation::OperationType::BLOCK)
1079 {
1080 (void)i2c->block_wait_.TryPost(true, ec);
1081 }
1082 else
1083 {
1084 i2c->read_op_.UpdateStatus(true, ec);
1085 }
1086 }
1087}
1088
1089extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c)
1090{
1091 STM32I2C* i2c = FindI2C(hi2c);
1092
1093 if (i2c && !i2c->recovering_)
1094 {
1095 if (i2c->read_)
1096 {
1097 if (i2c->read_op_.type == ReadOperation::OperationType::BLOCK)
1098 {
1099 (void)i2c->block_wait_.TryPost(true, ErrorCode::FAILED);
1100 }
1101 else
1102 {
1103 i2c->read_op_.UpdateStatus(true, ErrorCode::FAILED);
1104 }
1105 }
1106 else
1107 {
1108 if (i2c->write_op_.type == WriteOperation::OperationType::BLOCK)
1109 {
1110 (void)i2c->block_wait_.TryPost(true, ErrorCode::FAILED);
1111 }
1112 else
1113 {
1114 i2c->write_op_.UpdateStatus(true, ErrorCode::FAILED);
1115 }
1116 }
1117 }
1118}
1119
1120#endif
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.
void Cancel()
清除等待状态,不发送通知 / Clear the wait state without posting.
只读原始数据视图 / 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
STM32 I2C 驱动实现 / STM32 I2C driver implementation.
Definition stm32_i2c.hpp:55
ErrorCode SetConfig(Configuration config) override
配置 I2C 设备参数。 Configures the I2C device settings.
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.
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.
ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation &op, bool in_isr) override
向 I2C 设备写入数据。 Writes data to an I2C device.
ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation &op, bool in_isr) override
读取 I2C 设备的数据。 Reads data from an I2C device.
STM32I2C(I2C_HandleTypeDef *hi2c, RawData dma_buff, uint32_t dma_enable_min_size=3)
构造 I2C 对象 / Construct I2C object
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
void STM32_InvalidateDCacheByAddr(const void *addr, size_t size)
失效指定内存范围覆盖的 D-Cache cache line Invalidates D-Cache lines covering the specified memory range
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ INIT_ERR
初始化错误 / Initialization error
@ BUSY
忙碌 / Busy
@ NOT_SUPPORT
不支持 / Not supported
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
清理指定内存范围覆盖的 D-Cache cache line Cleans D-Cache lines covering the specified memory range
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