1010 * 2024-12-10 zzk597 add support for STM32F1 series
1111 * 2024-06-23 wdfk-prog Add blocking modes and distinguish POLL,INT,DMA modes
1212 * 2024-06-23 wdfk-prog Distinguish STM32 I2C timing semantics by IP generation
13+ * 2026-04-20 wdfk-prog Stabilize async completion and recovery flow
1314 */
1415
1516#include "drv_hard_i2c.h"
@@ -176,15 +177,17 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
176177 }
177178#endif /* defined(BSP_I2C_TX_USING_DMA) */
178179#if defined(BSP_I2C_USING_IRQ )
179- if ((i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX || i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX )
180- || (i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_INT_TX || i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_INT_RX ))
180+ if ((( i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX ) || ( i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX ) )
181+ || (( i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_INT_TX ) || ( i2c_drv -> i2c_dma_flag & RT_DEVICE_FLAG_INT_RX ) ))
181182 {
182183 /* In the data transfer function stm32_i2c_master_xfer(), the IT transfer function
183184 HAL_I2C_Master_Seq_Transmit_IT() is used when DMA is not used, so the IT interrupt
184185 must be enable anyway, regardless of the DMA configuration, otherwise
185186 the rt_completion_wait() will always timeout. */
186187 HAL_NVIC_SetPriority (i2c_drv -> config -> evirq_type , 2 , 0 );
187188 HAL_NVIC_EnableIRQ (i2c_drv -> config -> evirq_type );
189+ HAL_NVIC_SetPriority (i2c_drv -> config -> erirq_type , 2 , 0 );
190+ HAL_NVIC_EnableIRQ (i2c_drv -> config -> erirq_type );
188191 }
189192#endif /* defined(BSP_I2C_USING_IRQ) */
190193
@@ -205,7 +208,8 @@ static rt_err_t stm32_i2c_configure(struct rt_i2c_bus_device *bus)
205208 * @param handle Pointer to the HAL I2C handle.
206209 * @param msg Pointer to the RT-Thread I2C message descriptor.
207210 * @param mode HAL sequential transfer mode.
208- * @param timeout Timeout in RT-Thread ticks for polling transfer.
211+ * @param timeout Timeout in milliseconds for polling transfer.
212+ * @param async_allowed RT_TRUE when the current context allows IRQ/DMA wait.
209213 * @param need_wait Output flag set to RT_TRUE when IT/DMA path is used.
210214 * @return HAL status returned by the selected HAL receive API.
211215 * @retval HAL_OK Transfer start succeeded.
@@ -216,6 +220,7 @@ static HAL_StatusTypeDef stm32_i2c_master_receive_start(struct stm32_i2c *i2c_ob
216220 struct rt_i2c_msg * msg ,
217221 uint32_t mode ,
218222 rt_uint32_t timeout ,
223+ rt_bool_t async_allowed ,
219224 rt_bool_t * need_wait )
220225{
221226 RT_UNUSED (i2c_obj );
@@ -229,15 +234,15 @@ static HAL_StatusTypeDef stm32_i2c_master_receive_start(struct stm32_i2c *i2c_ob
229234 * need_wait = RT_FALSE ;
230235
231236#if defined(BSP_I2C_RX_USING_DMA )
232- if ((i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX ) && (msg -> len >= DMA_TRANS_MIN_LEN ))
237+ if (async_allowed && (i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX ) && (msg -> len >= DMA_TRANS_MIN_LEN ))
233238 {
234239 * need_wait = RT_TRUE ;
235240 return HAL_I2C_Master_Seq_Receive_DMA (handle , (msg -> addr << 1 ), msg -> buf , msg -> len , mode );
236241 }
237242#endif /* defined(BSP_I2C_RX_USING_DMA) */
238243
239244#if defined(BSP_I2C_RX_USING_INT )
240- if (i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_INT_RX )
245+ if (async_allowed && ( i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_INT_RX ) )
241246 {
242247 * need_wait = RT_TRUE ;
243248 return HAL_I2C_Master_Seq_Receive_IT (handle , (msg -> addr << 1 ), msg -> buf , msg -> len , mode );
@@ -257,7 +262,8 @@ static HAL_StatusTypeDef stm32_i2c_master_receive_start(struct stm32_i2c *i2c_ob
257262 * @param handle Pointer to the HAL I2C handle.
258263 * @param msg Pointer to the RT-Thread I2C message descriptor.
259264 * @param mode HAL sequential transfer mode.
260- * @param timeout Timeout in RT-Thread ticks for polling transfer.
265+ * @param timeout Timeout in milliseconds for polling transfer.
266+ * @param async_allowed RT_TRUE when the current context allows IRQ/DMA wait.
261267 * @param need_wait Output flag set to RT_TRUE when IT/DMA path is used.
262268 * @return HAL status returned by the selected HAL transmit API.
263269 * @retval HAL_OK Transfer start succeeded.
@@ -268,6 +274,7 @@ static HAL_StatusTypeDef stm32_i2c_master_transmit_start(struct stm32_i2c *i2c_o
268274 struct rt_i2c_msg * msg ,
269275 uint32_t mode ,
270276 rt_uint32_t timeout ,
277+ rt_bool_t async_allowed ,
271278 rt_bool_t * need_wait )
272279{
273280 RT_UNUSED (i2c_obj );
@@ -281,15 +288,15 @@ static HAL_StatusTypeDef stm32_i2c_master_transmit_start(struct stm32_i2c *i2c_o
281288 * need_wait = RT_FALSE ;
282289
283290#if defined(BSP_I2C_TX_USING_DMA )
284- if ((i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX ) && (msg -> len >= DMA_TRANS_MIN_LEN ))
291+ if (async_allowed && (i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX ) && (msg -> len >= DMA_TRANS_MIN_LEN ))
285292 {
286293 * need_wait = RT_TRUE ;
287294 return HAL_I2C_Master_Seq_Transmit_DMA (handle , (msg -> addr << 1 ), msg -> buf , msg -> len , mode );
288295 }
289296#endif /* defined(BSP_I2C_TX_USING_DMA) */
290297
291298#if defined(BSP_I2C_TX_USING_INT )
292- if (i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_INT_TX )
299+ if (async_allowed && ( i2c_obj -> i2c_dma_flag & RT_DEVICE_FLAG_INT_TX ) )
293300 {
294301 * need_wait = RT_TRUE ;
295302 return HAL_I2C_Master_Seq_Transmit_IT (handle , (msg -> addr << 1 ), msg -> buf , msg -> len , mode );
@@ -386,7 +393,8 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
386393 struct stm32_i2c * i2c_obj ;
387394 rt_bool_t is_last = RT_FALSE ;
388395 uint32_t mode = 0 ;
389- rt_uint32_t timeout ;
396+ rt_uint32_t timeout_ms ;
397+
390398 if (num == 0 )
391399 {
392400 return 0 ;
@@ -398,39 +406,56 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
398406 I2C_HandleTypeDef * handle = & i2c_obj -> handle ;
399407 RT_ASSERT (handle != RT_NULL );
400408#if defined(BSP_I2C_USING_IRQ )
409+ rt_bool_t need_abort = RT_FALSE ;
401410 struct rt_completion * completion ;
402411 completion = & i2c_obj -> completion ;
403412#endif /* defined(BSP_I2C_USING_IRQ) */
404413 LOG_D ("xfer start %d megs" , num );
405414 for (i = 0 ; i < num ; i ++ )
406415 {
407416 rt_bool_t need_wait = RT_FALSE ;
417+ const rt_bool_t scheduler_available = rt_scheduler_is_available ();
418+ const rt_bool_t irq_disabled = rt_hw_interrupt_is_disabled ();
419+ const rt_bool_t async_allowed = (scheduler_available && !irq_disabled );
420+
408421 msg = & msgs [i ];
409422 is_last = (i == (num - 1 ));
410423 next_msg = is_last ? RT_NULL : & msgs [i + 1 ];
411424 mode = stm32_i2c_get_xfer_mode (i , msg , next_msg , is_last );
412425 LOG_D ("xfer msgs[%d] addr=0x%2x buf=0x%x len= 0x%x flags= 0x%x" , i , msg -> addr , msg -> buf , msg -> len , msg -> flags );
413426#if defined(STM32_I2C_TIMINGR_IP )
414- timeout = bus -> timeout ? bus -> timeout : 100U ;
427+ timeout_ms = bus -> timeout ? bus -> timeout : 100U ;
415428#else
416- timeout = TIMEOUT_CALC (msg );
429+ timeout_ms = TIMEOUT_CALC (msg );
417430#endif
431+ #if defined(BSP_I2C_USING_IRQ )
432+ rt_tick_t timeout_tick = rt_tick_from_millisecond (timeout_ms );
433+ rt_completion_init (completion );
434+ #endif /* defined(BSP_I2C_USING_IRQ) */
418435 if (msg -> flags & RT_I2C_RD )
419436 {
420437 LOG_D ("xfer rec msgs[%d] hal mode = %s" , i , stm32_i2c_mode_name (mode ));
421- ret = stm32_i2c_master_receive_start (i2c_obj , handle , msg , mode , timeout , & need_wait );
438+ ret = stm32_i2c_master_receive_start (i2c_obj , handle , msg , mode , timeout_ms , async_allowed , & need_wait );
422439 if (ret != HAL_OK )
423440 {
424- LOG_E ("I2C[%s] Read error(%d)!\n " , bus -> parent .parent .name , ret );
441+ LOG_E ("I2C[%s] Read error(%d)!" , bus -> parent .parent .name , ret );
425442 goto out ;
426443 }
427444#if defined(BSP_I2C_USING_IRQ )
428445 if (need_wait )
429446 {
430- ret = rt_completion_wait (completion , timeout );
447+ ret = rt_completion_wait (completion , timeout_tick );
431448 if (ret != RT_EOK )
432449 {
433- LOG_W ("I2C[%s] receive wait failed %d, timeout %d" , bus -> parent .parent .name , ret , timeout );
450+ need_abort = RT_TRUE ;
451+ LOG_W ("I2C[%s] receive wait failed %d, timeout %u ms" , bus -> parent .parent .name , ret , timeout_ms );
452+ goto out ;
453+ }
454+
455+ if (handle -> ErrorCode != HAL_I2C_ERROR_NONE )
456+ {
457+ need_abort = RT_TRUE ;
458+ LOG_E ("I2C[%s] receive failed, error code: 0x%08x" , bus -> parent .parent .name , handle -> ErrorCode );
434459 goto out ;
435460 }
436461 }
@@ -439,19 +464,27 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
439464 else
440465 {
441466 LOG_D ("xfer trans msgs[%d] hal mode = %s" , i , stm32_i2c_mode_name (mode ));
442- ret = stm32_i2c_master_transmit_start (i2c_obj , handle , msg , mode , timeout , & need_wait );
467+ ret = stm32_i2c_master_transmit_start (i2c_obj , handle , msg , mode , timeout_ms , async_allowed , & need_wait );
443468 if (ret != HAL_OK )
444469 {
445- LOG_E ("I2C[%s] Write error(%d)!\n " , bus -> parent .parent .name , ret );
470+ LOG_E ("I2C[%s] Write error(%d)!" , bus -> parent .parent .name , ret );
446471 goto out ;
447472 }
448473#if defined(BSP_I2C_USING_IRQ )
449474 if (need_wait )
450475 {
451- ret = rt_completion_wait (completion , timeout );
476+ ret = rt_completion_wait (completion , timeout_tick );
452477 if (ret != RT_EOK )
453478 {
454- LOG_W ("I2C[%s] transmit wait failed %d, timeout %d" , bus -> parent .parent .name , ret , timeout );
479+ need_abort = RT_TRUE ;
480+ LOG_W ("I2C[%s] transmit wait failed %d, timeout %u ms" , bus -> parent .parent .name , ret , timeout_ms );
481+ goto out ;
482+ }
483+
484+ if (handle -> ErrorCode != HAL_I2C_ERROR_NONE )
485+ {
486+ need_abort = RT_TRUE ;
487+ LOG_E ("I2C[%s] transmit failed, error code: 0x%08x" , bus -> parent .parent .name , handle -> ErrorCode );
455488 goto out ;
456489 }
457490 }
@@ -469,20 +502,20 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
469502out :
470503 ret = i ;
471504 /*
472- * On TIMINGR-based STM32 I2C IPs (currently F7/H7 in this driver),
473- * STOPI only enables STOP-event interrupt handling.
474- * It does not actively generate a STOP condition on the bus.
475- *
476- * For legacy STM32 I2C IPs, the HAL error handler already generates a
477- * STOP condition on AF in master/memory modes, so this driver does not
478- * manually issue another STOP in the AF path.
479- */
505+ * On TIMINGR-based STM32 I2C IPs (currently F7/H7 in this driver),
506+ * STOPI only enables STOP-event interrupt handling.
507+ * It does not actively generate a STOP condition on the bus.
508+ *
509+ * For legacy STM32 I2C IPs, the HAL error handler already generates a
510+ * STOP condition on AF in master/memory modes, so this driver does not
511+ * manually issue another STOP in the AF path.
512+ */
480513 if (handle -> ErrorCode & HAL_I2C_ERROR_AF )
481514 {
482515 LOG_W ("I2C[%s] NACK Error" , bus -> parent .parent .name );
483516#if defined(STM32_I2C_TIMINGR_IP )
484517 handle -> Instance -> CR1 |= I2C_IT_STOPI ;
485- #endif /* defined(STM32_I2C_TIMINGR_IP) */
518+ #endif /* defined(STM32_I2C_TIMINGR_IP) */
486519 }
487520 if (handle -> ErrorCode & HAL_I2C_ERROR_BERR )
488521 {
@@ -491,8 +524,46 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
491524 handle -> Instance -> CR1 |= I2C_IT_STOPI ;
492525#else
493526 handle -> Instance -> CR1 |= I2C_CR1_STOP ;
494- #endif /* defined(STM32_I2C_TIMINGR_IP) */
527+ #endif /* defined(STM32_I2C_TIMINGR_IP) */
528+ }
529+ #if defined(BSP_I2C_USING_IRQ )
530+ if (need_abort && (msg != RT_NULL ))
531+ {
532+ if (HAL_I2C_Master_Abort_IT (handle , (msg -> addr << 1 )) != HAL_OK )
533+ {
534+ LOG_W ("I2C[%s] abort start failed, state: %d, error: 0x%08x" ,
535+ bus -> parent .parent .name ,
536+ handle -> State ,
537+ handle -> ErrorCode );
538+ }
539+ else
540+ {
541+ rt_uint32_t timeout = timeout_ms ;
542+ const rt_bool_t scheduler_available = rt_scheduler_is_available ();
543+ const rt_bool_t irq_disabled = rt_hw_interrupt_is_disabled ();
544+
545+ while (HAL_I2C_GetState (handle ) != HAL_I2C_STATE_READY )
546+ {
547+ if (timeout -- > 0 )
548+ {
549+ if (scheduler_available && !irq_disabled )
550+ {
551+ rt_thread_mdelay (1 );
552+ }
553+ else
554+ {
555+ rt_hw_us_delay (1000 );
556+ }
557+ }
558+ else
559+ {
560+ LOG_E ("I2C[%s] timeout! state did not become READY after abort." , bus -> parent .parent .name );
561+ break ;
562+ }
563+ }
564+ }
495565 }
566+ #endif /* defined(BSP_I2C_USING_IRQ) */
496567
497568 return ret ;
498569#undef TIMEOUT_FREQ_KHZ
@@ -690,27 +761,24 @@ void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
690761
691762void HAL_I2C_ErrorCallback (I2C_HandleTypeDef * hi2c )
692763{
693- LOG_W ("%s error code %d" , hi2c -> Instance == I2C1 ? "I2C1"
694- : hi2c -> Instance == I2C2 ? "I2C2"
695- : hi2c -> Instance == I2C3 ? "I2C3"
696- #ifdef I2C4
697- : hi2c -> Instance == I2C4 ? "I2C4"
698- #endif /* I2C4 */
699- : "unknown" ,
700- hi2c -> ErrorCode );
764+ struct stm32_i2c * i2c_drv = rt_container_of (hi2c , struct stm32_i2c , handle );
765+
766+ LOG_W ("%s error code 0x%08x" , i2c_drv -> config -> name , hi2c -> ErrorCode );
701767#if defined(STM32_I2C_TIMINGR_IP )
702- /* Send stop signal to prevent bus lock-up */
703- if (hi2c -> ErrorCode == HAL_I2C_ERROR_AF )
768+ /*
769+ * Trigger STOP handling immediately in IRQ context so the peripheral can
770+ * leave the error state before the waiting thread starts its recovery path.
771+ */
772+ if (hi2c -> ErrorCode & HAL_I2C_ERROR_AF )
704773 {
705- LOG_W ("I2C NACK Error now stoped" );
706774 hi2c -> Instance -> CR1 |= I2C_IT_STOPI ;
707775 }
708- if (hi2c -> ErrorCode == HAL_I2C_ERROR_BERR )
776+ if (hi2c -> ErrorCode & HAL_I2C_ERROR_BERR )
709777 {
710- LOG_W ("I2C BUS Error now stoped" );
711778 hi2c -> Instance -> CR1 |= I2C_IT_STOPI ;
712779 }
713780#endif /* defined(STM32_I2C_TIMINGR_IP) */
781+ rt_completion_done (& i2c_drv -> completion );
714782}
715783
716784#ifdef BSP_USING_HARD_I2C1
0 commit comments