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,57 @@ 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 * 1000U + RT_TICK_PER_SECOND - 1U ) / RT_TICK_PER_SECOND : 100U ;
415428#else
416- timeout = TIMEOUT_CALC (msg );
417- #endif
429+ timeout_ms = TIMEOUT_CALC (msg );
430+ #endif /* defined(STM32_I2C_TIMINGR_IP) */
431+
432+ #if defined(BSP_I2C_USING_IRQ )
433+ rt_tick_t timeout_tick = rt_tick_from_millisecond (timeout_ms );
434+ rt_completion_init (completion );
435+ #endif /* defined(BSP_I2C_USING_IRQ) */
418436 if (msg -> flags & RT_I2C_RD )
419437 {
420438 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 );
439+ ret = stm32_i2c_master_receive_start (i2c_obj , handle , msg , mode , timeout_ms , async_allowed , & need_wait );
422440 if (ret != HAL_OK )
423441 {
424- LOG_E ("I2C[%s] Read error(%d)!\n " , bus -> parent .parent .name , ret );
442+ LOG_E ("I2C[%s] Read error(%d)!" , bus -> parent .parent .name , ret );
425443 goto out ;
426444 }
427445#if defined(BSP_I2C_USING_IRQ )
428446 if (need_wait )
429447 {
430- ret = rt_completion_wait (completion , timeout );
448+ ret = rt_completion_wait (completion , timeout_tick );
431449 if (ret != RT_EOK )
432450 {
433- LOG_W ("I2C[%s] receive wait failed %d, timeout %d" , bus -> parent .parent .name , ret , timeout );
451+ need_abort = RT_TRUE ;
452+ LOG_W ("I2C[%s] receive wait failed %d, timeout %u ms" , bus -> parent .parent .name , ret , timeout_ms );
453+ goto out ;
454+ }
455+
456+ if (handle -> ErrorCode != HAL_I2C_ERROR_NONE )
457+ {
458+ need_abort = RT_TRUE ;
459+ LOG_E ("I2C[%s] receive failed, error code: 0x%08x" , bus -> parent .parent .name , handle -> ErrorCode );
434460 goto out ;
435461 }
436462 }
@@ -439,19 +465,27 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
439465 else
440466 {
441467 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 );
468+ ret = stm32_i2c_master_transmit_start (i2c_obj , handle , msg , mode , timeout_ms , async_allowed , & need_wait );
443469 if (ret != HAL_OK )
444470 {
445- LOG_E ("I2C[%s] Write error(%d)!\n " , bus -> parent .parent .name , ret );
471+ LOG_E ("I2C[%s] Write error(%d)!" , bus -> parent .parent .name , ret );
446472 goto out ;
447473 }
448474#if defined(BSP_I2C_USING_IRQ )
449475 if (need_wait )
450476 {
451- ret = rt_completion_wait (completion , timeout );
477+ ret = rt_completion_wait (completion , timeout_tick );
452478 if (ret != RT_EOK )
453479 {
454- LOG_W ("I2C[%s] transmit wait failed %d, timeout %d" , bus -> parent .parent .name , ret , timeout );
480+ need_abort = RT_TRUE ;
481+ LOG_W ("I2C[%s] transmit wait failed %d, timeout %u ms" , bus -> parent .parent .name , ret , timeout_ms );
482+ goto out ;
483+ }
484+
485+ if (handle -> ErrorCode != HAL_I2C_ERROR_NONE )
486+ {
487+ need_abort = RT_TRUE ;
488+ LOG_E ("I2C[%s] transmit failed, error code: 0x%08x" , bus -> parent .parent .name , handle -> ErrorCode );
455489 goto out ;
456490 }
457491 }
@@ -469,20 +503,20 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
469503out :
470504 ret = i ;
471505 /*
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- */
506+ * On TIMINGR-based STM32 I2C IPs (currently F7/H7 in this driver),
507+ * STOPI only enables STOP-event interrupt handling.
508+ * It does not actively generate a STOP condition on the bus.
509+ *
510+ * For legacy STM32 I2C IPs, the HAL error handler already generates a
511+ * STOP condition on AF in master/memory modes, so this driver does not
512+ * manually issue another STOP in the AF path.
513+ */
480514 if (handle -> ErrorCode & HAL_I2C_ERROR_AF )
481515 {
482516 LOG_W ("I2C[%s] NACK Error" , bus -> parent .parent .name );
483517#if defined(STM32_I2C_TIMINGR_IP )
484518 handle -> Instance -> CR1 |= I2C_IT_STOPI ;
485- #endif /* defined(STM32_I2C_TIMINGR_IP) */
519+ #endif /* defined(STM32_I2C_TIMINGR_IP) */
486520 }
487521 if (handle -> ErrorCode & HAL_I2C_ERROR_BERR )
488522 {
@@ -491,8 +525,46 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
491525 handle -> Instance -> CR1 |= I2C_IT_STOPI ;
492526#else
493527 handle -> Instance -> CR1 |= I2C_CR1_STOP ;
494- #endif /* defined(STM32_I2C_TIMINGR_IP) */
528+ #endif /* defined(STM32_I2C_TIMINGR_IP) */
495529 }
530+ #if defined(BSP_I2C_USING_IRQ )
531+ if (need_abort && (msg != RT_NULL ))
532+ {
533+ if (HAL_I2C_Master_Abort_IT (handle , (msg -> addr << 1 )) != HAL_OK )
534+ {
535+ LOG_W ("I2C[%s] abort start failed, state: %d, error: 0x%08x" ,
536+ bus -> parent .parent .name ,
537+ handle -> State ,
538+ handle -> ErrorCode );
539+ }
540+ else
541+ {
542+ rt_uint32_t timeout = timeout_ms ;
543+ const rt_bool_t scheduler_available = rt_scheduler_is_available ();
544+ const rt_bool_t irq_disabled = rt_hw_interrupt_is_disabled ();
545+
546+ while (HAL_I2C_GetState (handle ) != HAL_I2C_STATE_READY )
547+ {
548+ if (timeout -- > 0 )
549+ {
550+ if (scheduler_available && !irq_disabled )
551+ {
552+ rt_thread_mdelay (1 );
553+ }
554+ else
555+ {
556+ rt_hw_us_delay (1000 );
557+ }
558+ }
559+ else
560+ {
561+ LOG_E ("I2C[%s] timeout! state did not become READY after abort." , bus -> parent .parent .name );
562+ break ;
563+ }
564+ }
565+ }
566+ }
567+ #endif /* defined(BSP_I2C_USING_IRQ) */
496568
497569 return ret ;
498570#undef TIMEOUT_FREQ_KHZ
@@ -690,27 +762,24 @@ void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
690762
691763void HAL_I2C_ErrorCallback (I2C_HandleTypeDef * hi2c )
692764{
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 );
765+ struct stm32_i2c * i2c_drv = rt_container_of (hi2c , struct stm32_i2c , handle );
766+
767+ LOG_W ("%s error code 0x%08x" , i2c_drv -> config -> name , hi2c -> ErrorCode );
701768#if defined(STM32_I2C_TIMINGR_IP )
702- /* Send stop signal to prevent bus lock-up */
703- if (hi2c -> ErrorCode == HAL_I2C_ERROR_AF )
769+ /*
770+ * Trigger STOP handling immediately in IRQ context so the peripheral can
771+ * leave the error state before the waiting thread starts its recovery path.
772+ */
773+ if (hi2c -> ErrorCode & HAL_I2C_ERROR_AF )
704774 {
705- LOG_W ("I2C NACK Error now stoped" );
706775 hi2c -> Instance -> CR1 |= I2C_IT_STOPI ;
707776 }
708- if (hi2c -> ErrorCode == HAL_I2C_ERROR_BERR )
777+ if (hi2c -> ErrorCode & HAL_I2C_ERROR_BERR )
709778 {
710- LOG_W ("I2C BUS Error now stoped" );
711779 hi2c -> Instance -> CR1 |= I2C_IT_STOPI ;
712780 }
713781#endif /* defined(STM32_I2C_TIMINGR_IP) */
782+ rt_completion_done (& i2c_drv -> completion );
714783}
715784
716785#ifdef BSP_USING_HARD_I2C1
0 commit comments