Просмотр исходного кода

refactor[stm32][i2c]: restructure transfer flow and error handling

wdfk-prog 3 недель назад
Родитель
Сommit
0861ee1e51
1 измененных файлов с 233 добавлено и 185 удалено
  1. 233 185
      bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c

+ 233 - 185
bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c

@@ -19,6 +19,9 @@
 #define LOG_TAG "drv.i2c.hw"
 #define LOG_TAG "drv.i2c.hw"
 #include <drv_log.h>
 #include <drv_log.h>
 
 
+/* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */
+#define DMA_TRANS_MIN_LEN 2
+
 typedef enum
 typedef enum
 {
 {
 #ifdef BSP_USING_HARD_I2C1
 #ifdef BSP_USING_HARD_I2C1
@@ -64,6 +67,7 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
     i2c_handle->Instance = cfg->Instance;
     i2c_handle->Instance = cfg->Instance;
 #if defined(SOC_SERIES_STM32H7)
 #if defined(SOC_SERIES_STM32H7)
     i2c_handle->Init.Timing = cfg->timing;
     i2c_handle->Init.Timing = cfg->timing;
+    i2c_handle->Init.OwnAddress2Masks = I2C_OA2_NOMASK;
 #else
 #else
     i2c_handle->Init.ClockSpeed = 100000;
     i2c_handle->Init.ClockSpeed = 100000;
     i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2;
     i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2;
@@ -74,10 +78,6 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
     i2c_handle->Init.OwnAddress2 = 0;
     i2c_handle->Init.OwnAddress2 = 0;
     i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
     i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
     i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
     i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
-#if defined(SOC_SERIES_STM32H7)
-    i2c_handle->Init.OwnAddress2Masks = I2C_OA2_NOMASK;
-#endif /* defined(SOC_SERIES_STM32H7) */
-
     if (HAL_I2C_DeInit(i2c_handle) != HAL_OK)
     if (HAL_I2C_DeInit(i2c_handle) != HAL_OK)
     {
     {
         return -RT_EFAULT;
         return -RT_EFAULT;
@@ -148,6 +148,171 @@ static rt_err_t stm32_i2c_configure(struct rt_i2c_bus_device *bus)
 
 
     return stm32_i2c_init(i2c_drv);
     return stm32_i2c_init(i2c_drv);
 }
 }
+
+/**
+ * @brief Start one master receive transfer and report whether wait is required.
+ * @param i2c_obj Pointer to the STM32 I2C driver object.
+ * @param handle Pointer to the HAL I2C handle.
+ * @param msg Pointer to the RT-Thread I2C message descriptor.
+ * @param mode HAL sequential transfer mode.
+ * @param timeout Timeout in RT-Thread ticks for polling transfer.
+ * @param need_wait Output flag set to RT_TRUE when IT/DMA path is used.
+ * @return HAL status returned by the selected HAL receive API.
+ * @retval HAL_OK Transfer start succeeded.
+ * @retval HAL_ERROR Transfer start failed or no receive backend is enabled.
+ */
+static HAL_StatusTypeDef stm32_i2c_master_receive_start(struct stm32_i2c *i2c_obj,
+                                                        I2C_HandleTypeDef *handle,
+                                                        struct rt_i2c_msg *msg,
+                                                        uint32_t mode,
+                                                        rt_uint32_t timeout,
+                                                        rt_bool_t *need_wait)
+{
+    RT_UNUSED(i2c_obj);
+    RT_UNUSED(mode);
+    RT_UNUSED(timeout);
+    RT_ASSERT(i2c_obj != RT_NULL);
+    RT_ASSERT(handle != RT_NULL);
+    RT_ASSERT(msg != RT_NULL);
+    RT_ASSERT(need_wait != RT_NULL);
+
+    *need_wait = RT_FALSE;
+
+#if defined(BSP_I2C_RX_USING_DMA)
+    if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN))
+    {
+        *need_wait = RT_TRUE;
+        return HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr << 1), msg->buf, msg->len, mode);
+    }
+#endif /* defined(BSP_I2C_RX_USING_DMA) */
+
+#if defined(BSP_I2C_RX_USING_INT)
+    if (i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX)
+    {
+        *need_wait = RT_TRUE;
+        return HAL_I2C_Master_Seq_Receive_IT(handle, (msg->addr << 1), msg->buf, msg->len, mode);
+    }
+#endif /* defined(BSP_I2C_RX_USING_INT) */
+
+#if defined(BSP_I2C_RX_USING_POLL)
+    return HAL_I2C_Master_Receive(handle, (msg->addr << 1), msg->buf, msg->len, timeout);
+#else
+    return HAL_ERROR;
+#endif /* defined(BSP_I2C_RX_USING_POLL) */
+}
+
+/**
+ * @brief Start one master transmit transfer and report whether wait is required.
+ * @param i2c_obj Pointer to the STM32 I2C driver object.
+ * @param handle Pointer to the HAL I2C handle.
+ * @param msg Pointer to the RT-Thread I2C message descriptor.
+ * @param mode HAL sequential transfer mode.
+ * @param timeout Timeout in RT-Thread ticks for polling transfer.
+ * @param need_wait Output flag set to RT_TRUE when IT/DMA path is used.
+ * @return HAL status returned by the selected HAL transmit API.
+ * @retval HAL_OK Transfer start succeeded.
+ * @retval HAL_ERROR Transfer start failed or no transmit backend is enabled.
+ */
+static HAL_StatusTypeDef stm32_i2c_master_transmit_start(struct stm32_i2c *i2c_obj,
+                                                         I2C_HandleTypeDef *handle,
+                                                         struct rt_i2c_msg *msg,
+                                                         uint32_t mode,
+                                                         rt_uint32_t timeout,
+                                                         rt_bool_t *need_wait)
+{
+    RT_UNUSED(i2c_obj);
+    RT_UNUSED(mode);
+    RT_UNUSED(timeout);
+    RT_ASSERT(i2c_obj != RT_NULL);
+    RT_ASSERT(handle != RT_NULL);
+    RT_ASSERT(msg != RT_NULL);
+    RT_ASSERT(need_wait != RT_NULL);
+
+    *need_wait = RT_FALSE;
+
+#if defined(BSP_I2C_TX_USING_DMA)
+    if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN))
+    {
+        *need_wait = RT_TRUE;
+        return HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr << 1), msg->buf, msg->len, mode);
+    }
+#endif /* defined(BSP_I2C_TX_USING_DMA) */
+
+#if defined(BSP_I2C_TX_USING_INT)
+    if (i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX)
+    {
+        *need_wait = RT_TRUE;
+        return HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr << 1), msg->buf, msg->len, mode);
+    }
+#endif /* defined(BSP_I2C_TX_USING_INT) */
+
+#if defined(BSP_I2C_TX_USING_POLL)
+    return HAL_I2C_Master_Transmit(handle, (msg->addr << 1), msg->buf, msg->len, timeout);
+#else
+    return HAL_ERROR;
+#endif /* defined(BSP_I2C_TX_USING_POLL) */
+}
+
+/**
+ * @brief Compute HAL transfer mode for the current message in a sequence.
+ * @param index Index of the current message.
+ * @param msg Pointer to the current I2C message.
+ * @param next_msg Pointer to the next I2C message, or RT_NULL for the last one.
+ * @param is_last RT_TRUE when the current message is the last frame.
+ * @return HAL sequential transfer option used by the message.
+ * @retval I2C_FIRST_AND_NEXT_FRAME Continue transfer without repeated start.
+ * @retval I2C_LAST_FRAME_NO_STOP Keep bus active for following frame semantics.
+ * @retval I2C_LAST_FRAME End transfer with the last frame behavior.
+ */
+static uint32_t stm32_i2c_get_xfer_mode(rt_int32_t index,
+                                        struct rt_i2c_msg *msg,
+                                        struct rt_i2c_msg *next_msg,
+                                        rt_bool_t is_last)
+{
+    if (is_last)
+    {
+        if (msg->flags & RT_I2C_NO_STOP)
+        {
+            return I2C_LAST_FRAME_NO_STOP;
+        }
+
+        return I2C_LAST_FRAME;
+    }
+
+    if (next_msg->flags & RT_I2C_NO_START)
+    {
+        if ((next_msg->flags & RT_I2C_RD) == (msg->flags & RT_I2C_RD))
+        {
+            /* The same mode, can use no start */
+            return I2C_FIRST_AND_NEXT_FRAME;
+        }
+
+        /* Not allowed to use no start, sending address is required when changing direction, user setting error */
+        LOG_W("user set flags error msg[%d] flags RT_I2C_NO_START has canceled", index + 1);
+    }
+
+    return I2C_LAST_FRAME_NO_STOP;
+}
+
+/**
+ * @brief Convert HAL transfer mode value to a readable log string.
+ * @param mode HAL sequential transfer option.
+ * @return Constant string for logging.
+ */
+const char *stm32_i2c_mode_name(uint32_t mode)
+{
+    switch (mode)
+    {
+    case I2C_FIRST_AND_NEXT_FRAME:
+        return "I2C_FIRST_AND_NEXT_FRAME";
+    case I2C_LAST_FRAME_NO_STOP:
+        return "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP";
+    case I2C_LAST_FRAME:
+        return "I2C_LAST_FRAME";
+    default:
+        return "unknown mode";
+    }
+}
 /**
 /**
  * @brief Hardware I2C driver transfer
  * @brief Hardware I2C driver transfer
  *
  *
@@ -160,26 +325,20 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
                                         struct rt_i2c_msg msgs[],
                                         struct rt_i2c_msg msgs[],
                                         rt_uint32_t num)
                                         rt_uint32_t num)
 {
 {
-    /* for stm32 dma may more stability */
-#define DMA_TRANS_MIN_LEN 2 /* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */
-#define TRANS_TIMEOUT_PERSEC 8 /* per ms will trans nums bytes */
-
-    rt_int32_t i, ret = 0;
-    struct rt_i2c_msg *msg = msgs;
-    struct rt_i2c_msg *next_msg = 0;
+    rt_uint32_t i = 0;
+    rt_int32_t ret = 0;
+    struct rt_i2c_msg *msg = RT_NULL;
+    struct rt_i2c_msg *next_msg = RT_NULL;
     struct stm32_i2c *i2c_obj;
     struct stm32_i2c *i2c_obj;
+    rt_bool_t is_last = RT_FALSE;
     uint32_t mode = 0;
     uint32_t mode = 0;
-    RT_UNUSED(mode);
-    uint8_t next_flag = 0;
     rt_uint32_t timeout;
     rt_uint32_t timeout;
-
     if (num == 0)
     if (num == 0)
     {
     {
         return 0;
         return 0;
     }
     }
 
 
     RT_ASSERT((msgs != RT_NULL) && (bus != RT_NULL));
     RT_ASSERT((msgs != RT_NULL) && (bus != RT_NULL));
-
     i2c_obj = rt_container_of(bus, struct stm32_i2c, i2c_bus);
     i2c_obj = rt_container_of(bus, struct stm32_i2c, i2c_bus);
     RT_ASSERT(i2c_obj != RT_NULL);
     RT_ASSERT(i2c_obj != RT_NULL);
     I2C_HandleTypeDef *handle = &i2c_obj->handle;
     I2C_HandleTypeDef *handle = &i2c_obj->handle;
@@ -188,218 +347,104 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
     struct rt_completion *completion;
     struct rt_completion *completion;
     completion = &i2c_obj->completion;
     completion = &i2c_obj->completion;
 #endif /* defined(BSP_I2C_USING_IRQ) */
 #endif /* defined(BSP_I2C_USING_IRQ) */
-    LOG_D("xfer start %d mags", num);
-    for (i = 0; i < (num - 1); i++)
+    LOG_D("xfer start %d megs", num);
+
+    rt_uint32_t freq_khz = bus->config.usage_freq / 1000;
+    if (freq_khz == 0)
     {
     {
-        mode = 0;
+        freq_khz = 1;
+    }
+
+    for (i = 0; i < num; i++)
+    {
+        rt_bool_t need_wait = RT_FALSE;
         msg = &msgs[i];
         msg = &msgs[i];
+        is_last = (i == (num - 1));
+        next_msg = is_last ? RT_NULL : &msgs[i + 1];
+        mode = stm32_i2c_get_xfer_mode(i, msg, next_msg, is_last);
         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);
         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);
-        next_msg = &msgs[i + 1];
-        next_flag = next_msg->flags;
-        timeout = msg->len / TRANS_TIMEOUT_PERSEC + 5;
-        if (next_flag & RT_I2C_NO_START)
-        {
-            if ((next_flag & RT_I2C_RD) == (msg->flags & RT_I2C_RD))
-            { /* The same mode, can use no start */
-                mode = I2C_FIRST_AND_NEXT_FRAME;
-            }
-            else
-            {
-                /* Not allowed to use no start, sending address is required when changing direction, user setting error */
-                LOG_W("user set flags error msg[%d] flags RT_I2C_NO_START has canceled", i + 1);
-                mode = I2C_LAST_FRAME_NO_STOP;
-            }
-        }
-        else
-        {
-            mode = I2C_LAST_FRAME_NO_STOP;
-        }
+
+        // timeout= data_time + dev_addr_time + reserve_time
+        timeout = (msg->len * 8) / freq_khz + 1 + 5;
 
 
         if (msg->flags & RT_I2C_RD)
         if (msg->flags & RT_I2C_RD)
         {
         {
-            LOG_D("xfer  rec  msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP"
-                                                                                                                      : mode == I2C_LAST_FRAME           ? "I2C_LAST_FRAME"
-                                                                                                                                                         : "nuknown mode");
-#if defined(BSP_I2C_RX_USING_DMA)
-            if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN))
-            {
-                ret = HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-            }
-            else
-#endif /* defined(BSP_I2C_RX_USING_DMA) */
-#if defined(BSP_I2C_RX_USING_INT)
-            if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX)
-            {
-                ret = HAL_I2C_Master_Seq_Receive_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-            }
-            else
-#endif /* defined(BSP_I2C_RX_USING_INT) */
-#if defined(BSP_I2C_RX_USING_POLL)
-            {
-                ret = HAL_I2C_Master_Receive(handle, (msg->addr<<1), msg->buf, msg->len, timeout);
-            }
-#endif /* defined(BSP_I2C_RX_USING_POLL) */
-            if (ret !=  HAL_OK)
+            LOG_D("xfer  rec  msgs[%d] hal mode = %s", i, stm32_i2c_mode_name(mode));
+            ret = stm32_i2c_master_receive_start(i2c_obj, handle, msg, mode, timeout, &need_wait);
+            if (ret != HAL_OK)
             {
             {
-                LOG_E("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret);
+                LOG_E("I2C[%s] Read error(%d)!\n", bus->parent.parent.name, ret);
                 goto out;
                 goto out;
             }
             }
 #if defined(BSP_I2C_USING_IRQ)
 #if defined(BSP_I2C_USING_IRQ)
-            ret = rt_completion_wait(completion, timeout);
-            if (ret != RT_EOK)
+            if (need_wait)
             {
             {
-                LOG_W("receive error %d, timeout %d", ret, timeout);
-                goto out;
+                ret = rt_completion_wait(completion, timeout);
+                if (ret != RT_EOK)
+                {
+                    LOG_W("I2C[%s] receive wait failed %d, timeout %d", bus->parent.parent.name, ret, timeout);
+                    goto out;
+                }
             }
             }
 #endif /* defined(BSP_I2C_USING_IRQ) */
 #endif /* defined(BSP_I2C_USING_IRQ) */
         }
         }
         else
         else
         {
         {
-            LOG_D("xfer trans msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP"
-                                                                                                                      : mode == I2C_LAST_FRAME           ? "I2C_LAST_FRAME"
-                                                                                                                                                         : "nuknown mode");
-#if defined(BSP_I2C_TX_USING_DMA)
-            if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN))
-            {
-                ret = HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-            }
-            else
-#endif /* defined(BSP_I2C_TX_USING_DMA) */
-#if defined(BSP_I2C_TX_USING_INT)
-            if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX)
-            {
-                ret = HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-            }
-            else
-#endif /* defined(BSP_I2C_TX_USING_INT) */
-#if defined(BSP_I2C_TX_USING_POLL)
-            {
-                ret = HAL_I2C_Master_Transmit(handle, (msg->addr<<1), msg->buf, msg->len, timeout);
-            }
-#endif /* defined(BSP_I2C_TX_USING_POLL) */
+            LOG_D("xfer trans msgs[%d] hal mode = %s", i, stm32_i2c_mode_name(mode));
+            ret = stm32_i2c_master_transmit_start(i2c_obj, handle, msg, mode, timeout, &need_wait);
             if (ret != HAL_OK)
             if (ret != HAL_OK)
             {
             {
-                LOG_E("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret);
+                LOG_E("I2C[%s] Write error(%d)!\n", bus->parent.parent.name, ret);
                 goto out;
                 goto out;
             }
             }
 #if defined(BSP_I2C_USING_IRQ)
 #if defined(BSP_I2C_USING_IRQ)
-            ret = rt_completion_wait(completion, timeout);
-            if (ret != RT_EOK)
+            if (need_wait)
             {
             {
-                LOG_W("receive error %d, timeout %d", ret, timeout);
-                goto out;
+                ret = rt_completion_wait(completion, timeout);
+                if (ret != RT_EOK)
+                {
+                    LOG_W("I2C[%s] transmit wait failed %d, timeout %d", bus->parent.parent.name, ret, timeout);
+                    goto out;
+                }
             }
             }
 #endif /* defined(BSP_I2C_USING_IRQ) */
 #endif /* defined(BSP_I2C_USING_IRQ) */
         }
         }
-        LOG_D("xfer  next msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x\r\n", i + 1, next_msg->addr, next_msg->buf, next_msg->len, next_msg->flags);
-    }
-    /* last msg */
-    msg = &msgs[i];
-    timeout = msg->len / TRANS_TIMEOUT_PERSEC + 5;
-    if (msg->flags & RT_I2C_NO_STOP)
-        mode = I2C_LAST_FRAME_NO_STOP;
-    else
-        mode = I2C_LAST_FRAME;
-    LOG_D("xfer  last msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x", i, msg->addr, msg->buf, msg->len, msg->flags);
-    if (msg->flags & RT_I2C_RD)
-    {
-        LOG_D("xfer  rec  msgs[%d] hal mode=%s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP"
-                                                                                                                : mode == I2C_LAST_FRAME           ? "I2C_LAST_FRAME"
-                                                                                                                                                   : "nuknown mode");
-#if defined(BSP_I2C_RX_USING_DMA)
-        if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX) && (msg->len >= DMA_TRANS_MIN_LEN))
-        {
-            ret = HAL_I2C_Master_Seq_Receive_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-        }
-        else
-#endif /* defined(BSP_I2C_RX_USING_DMA) */
-#if defined(BSP_I2C_RX_USING_INT)
-        if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_RX)
-        {
-            ret = HAL_I2C_Master_Seq_Receive_IT(handle,(msg->addr<<1), msg->buf, msg->len, mode);
-        }
-        else
-#endif /* defined(BSP_I2C_RX_USING_INT) */
-#if defined(BSP_I2C_RX_USING_POLL)
-        {
-            ret = HAL_I2C_Master_Receive(handle, (msg->addr<<1), msg->buf, msg->len, timeout);
-        }
-#endif /* defined(BSP_I2C_RX_USING_POLL) */
-        if (ret != HAL_OK)
-        {
-            LOG_E("[%s:%d]I2C Read error(%d)!\n", __func__, __LINE__, ret);
-            goto out;
-        }
-#if defined(BSP_I2C_USING_IRQ)
-        ret = rt_completion_wait(completion, timeout);
-        if (ret != RT_EOK)
-        {
-            LOG_W("receive error %d, timeout %d", ret, timeout);
-            goto out;
-        }
-#endif /* defined(BSP_I2C_USING_IRQ) */
-    }
-    else
-    {
-        LOG_D("xfer trans msgs[%d] hal mode = %s", i, mode == I2C_FIRST_AND_NEXT_FRAME ? "I2C_FIRST_AND_NEXT_FRAME" : mode == I2C_LAST_FRAME       ? "I2C_LAST_FRAME"
-                                                                                                                  : mode == I2C_LAST_FRAME_NO_STOP ? "I2C_FIRST_FRAME/I2C_LAST_FRAME_NO_STOP"
-                                                                                                                                                   : "nuknown mode");
-#if defined(BSP_I2C_TX_USING_DMA)
-        if ((i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_DMA_TX) && (msg->len >= DMA_TRANS_MIN_LEN))
-        {
-            ret = HAL_I2C_Master_Seq_Transmit_DMA(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-        }
-        else
-#endif /* defined(BSP_I2C_TX_USING_DMA) */
-#if defined(BSP_I2C_TX_USING_INT)
-        if(i2c_obj->i2c_dma_flag & RT_DEVICE_FLAG_INT_TX)
-        {
-            ret = HAL_I2C_Master_Seq_Transmit_IT(handle, (msg->addr<<1), msg->buf, msg->len, mode);
-        }
-        else
-#endif /* defined(BSP_I2C_TX_USING_INT) */
-#if defined(BSP_I2C_TX_USING_POLL)
-        {
-            ret = HAL_I2C_Master_Transmit(handle, (msg->addr<<1), msg->buf, msg->len, timeout);
-        }
-#endif /* defined(BSP_I2C_TX_USING_POLL) */
-        if (ret != HAL_OK)
+        if (!is_last)
         {
         {
-            LOG_E("[%s:%d]I2C Write error(%d)!\n", __func__, __LINE__, ret);
-            goto out;
+            LOG_D("xfer  next msgs[%d] addr=0x%2x buf= 0x%x len= 0x%x flags = 0x%x\r\n", i + 1, next_msg->addr, next_msg->buf, next_msg->len, next_msg->flags);
         }
         }
-#if defined(BSP_I2C_USING_IRQ)
-        ret = rt_completion_wait(completion, timeout);
-        if (ret != RT_EOK)
-        {
-            LOG_W("transmit error %d, timeout %d", ret, timeout);
-            goto out;
-        }
-#endif /* defined(BSP_I2C_USING_IRQ) */
     }
     }
     ret = num;
     ret = num;
-    LOG_D("xfer  end  %d mags\r\n", num);
+    LOG_D("xfer  end  %d megs\r\n", num);
     return ret;
     return ret;
 
 
 out:
 out:
-    if (handle->ErrorCode == HAL_I2C_ERROR_AF)
+    ret = i;
+    /*
+    * On STM32H7, STOPI only enables STOP-event interrupt handling.
+    * It does not actively generate a STOP condition on the bus.
+    *
+    * For non-H7 STM32 series, the legacy HAL error handler already
+    * generates a STOP condition on AF in master/memory modes, so
+    * this driver does not manually issue another STOP in the AF path.
+    */
+    if (handle->ErrorCode & HAL_I2C_ERROR_AF)
     {
     {
-        LOG_W("I2C NACK Error now stoped");
-        /* Send stop signal to prevent bus lock-up */
+        LOG_W("I2C[%s] NACK Error", bus->parent.parent.name);
 #if defined(SOC_SERIES_STM32H7)
 #if defined(SOC_SERIES_STM32H7)
         handle->Instance->CR1 |= I2C_IT_STOPI;
         handle->Instance->CR1 |= I2C_IT_STOPI;
-#endif /* defined(SOC_SERIES_STM32H7) */
+#endif  /* defined(SOC_SERIES_STM32H7) */
     }
     }
-    if (handle->ErrorCode == HAL_I2C_ERROR_BERR)
+    if (handle->ErrorCode & HAL_I2C_ERROR_BERR)
     {
     {
-        LOG_W("I2C BUS Error now stoped");
+        LOG_W("I2C[%s] BUS Error", bus->parent.parent.name);
 #if defined(SOC_SERIES_STM32H7)
 #if defined(SOC_SERIES_STM32H7)
         handle->Instance->CR1 |= I2C_IT_STOPI;
         handle->Instance->CR1 |= I2C_IT_STOPI;
 #else
 #else
         handle->Instance->CR1 |= I2C_CR1_STOP;
         handle->Instance->CR1 |= I2C_CR1_STOP;
-#endif /* defined(SOC_SERIES_STM32H7) */
-        ret=i-1;
+#endif  /* defined(SOC_SERIES_STM32H7) */
     }
     }
+
     return ret;
     return ret;
 }
 }
 
 
@@ -635,6 +680,9 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
     LOG_W("%s error code %d",   hi2c->Instance == I2C1 ? "I2C1"
     LOG_W("%s error code %d",   hi2c->Instance == I2C1 ? "I2C1"
                                 : hi2c->Instance == I2C2 ? "I2C2"
                                 : hi2c->Instance == I2C2 ? "I2C2"
                                 : hi2c->Instance == I2C3 ? "I2C3"
                                 : hi2c->Instance == I2C3 ? "I2C3"
+#ifdef I2C4
+                                : hi2c->Instance == I2C4 ? "I2C4"
+#endif /* I2C4 */
                                 : "unknown",
                                 : "unknown",
                                 hi2c->ErrorCode);
                                 hi2c->ErrorCode);
 #if defined(SOC_SERIES_STM32H7)
 #if defined(SOC_SERIES_STM32H7)