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

feat:[STM32][I2C]:Distinguish STM32 I2C timing semantics by IP generation

wdfk-prog 13 часов назад
Родитель
Сommit
141895ec82

+ 3 - 0
bsp/stm32/libraries/HAL_Drivers/drivers/config/f1/i2c_hard_config.h

@@ -22,6 +22,7 @@ extern "C" {
 #define I2C1_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C1,                           \
+        .timing = 100000,                           \
         .timeout=0x1000,                            \
         .name = "hwi2c1",                           \
         .evirq_type = I2C1_EV_IRQn,                 \
@@ -57,6 +58,7 @@ extern "C" {
 #define I2C2_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C2,                           \
+        .timing = 100000,                           \
         .timeout=0x1000,                            \
         .name = "hwi2c2",                           \
         .evirq_type = I2C2_EV_IRQn,                 \
@@ -92,6 +94,7 @@ extern "C" {
 #define I2C3_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C3,                           \
+        .timing = 100000,                           \
         .timeout=0x1000,                            \
         .name = "hwi2c3",                           \
         .evirq_type = I2C3_EV_IRQn,                 \

+ 4 - 4
bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/i2c_hard_config.h

@@ -23,7 +23,7 @@ extern "C" {
 #define I2C1_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C1,                           \
-        .timing=0x10707DBC,                         \
+        .timing = 100000,                           \
         .timeout=0x1000,                            \
         .name = "hwi2c1",                           \
         .evirq_type = I2C1_EV_IRQn,                 \
@@ -81,7 +81,7 @@ extern "C" {
 #define I2C2_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C2,                           \
-        .timing=0x10707DBC,                         \
+        .timing = 100000,                           \
         .timeout=0x1000,                            \
         .name = "hwi2c2",                           \
         .evirq_type = I2C2_EV_IRQn,                 \
@@ -139,7 +139,7 @@ extern "C" {
 #define I2C3_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C3,                           \
-        .timing=0x10707DBC,                         \
+        .timing = 100000,                           \
         .timeout=0x1000,                            \
         .name = "hwi2c3",                           \
         .evirq_type = I2C3_EV_IRQn,                 \
@@ -197,7 +197,7 @@ extern "C" {
 #define I2C4_BUS_CONFIG                             \
     {                                               \
         .Instance = I2C4,                           \
-        .timing = 0x10707DBC,                       \
+        .timing = 100000,                           \
         .timeout = 0x1000,                          \
         .name = "hwi2c4",                           \
         .evirq_type = I2C4_EV_IRQn,                 \

+ 98 - 29
bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.c

@@ -9,6 +9,7 @@
  * 2024-04-23     Zeidan    fix bugs, test on STM32F429IGTx
  * 2024-12-10     zzk597    add support for STM32F1 series
  * 2024-06-23     wdfk-prog Add blocking modes and distinguish POLL,INT,DMA modes
+ * 2024-06-23     wdfk-prog Distinguish STM32 I2C timing semantics by IP generation
  */
 
 #include "drv_hard_i2c.h"
@@ -19,6 +20,18 @@
 #define LOG_TAG "drv.i2c.hw"
 #include <drv_log.h>
 
+/*
+ * Default timing values follow the IP generation split declared in
+ * drv_hard_i2c.h:
+ * - legacy IP  (F1/F4): timing is the bus speed in Hz
+ * - TIMINGR IP (F7/H7): timing is the raw I2C_TIMINGR value
+ */
+#if defined(STM32_I2C_TIMINGR_IP)
+#define DEFAULT_I2C_TIMING_VALUE 0x307075B1U    // 100K
+#else
+#define DEFAULT_I2C_TIMING_VALUE (100*1000U)    //HZ
+#endif
+
 /* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */
 #define DMA_TRANS_MIN_LEN 2
 
@@ -56,6 +69,16 @@ static struct stm32_i2c_config i2c_config[] =
 
 static struct stm32_i2c i2c_objs[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};
 
+static void stm32_i2c_apply_default_config(struct stm32_i2c_config *cfg)
+{
+    RT_ASSERT(cfg != RT_NULL);
+
+    if (cfg->timing == 0U)
+    {
+        cfg->timing = DEFAULT_I2C_TIMING_VALUE;
+    }
+}
+
 static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
 {
     RT_ASSERT(i2c_drv != RT_NULL);
@@ -64,14 +87,16 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
     struct stm32_i2c_config *cfg = i2c_drv->config;
 
     rt_memset(i2c_handle, 0, sizeof(I2C_HandleTypeDef));
+    stm32_i2c_apply_default_config(cfg);
+
     i2c_handle->Instance = cfg->Instance;
-#if defined(SOC_SERIES_STM32H7)
+#if defined(STM32_I2C_TIMINGR_IP)
     i2c_handle->Init.Timing = cfg->timing;
     i2c_handle->Init.OwnAddress2Masks = I2C_OA2_NOMASK;
 #else
-    i2c_handle->Init.ClockSpeed = 100000;
+    i2c_handle->Init.ClockSpeed = cfg->timing;
     i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2;
-#endif /* defined(SOC_SERIES_STM32H7) */
+#endif /* defined(STM32_I2C_TIMINGR_IP) */
     i2c_handle->Init.OwnAddress1 = 0;
     i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
     i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
@@ -87,7 +112,7 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
     {
         return -RT_EFAULT;
     }
-#if defined(SOC_SERIES_STM32H7)
+#if defined(STM32_I2C_TIMINGR_IP)
     /* Configure Analogue filter */
     if (HAL_I2CEx_ConfigAnalogFilter(i2c_handle, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
     {
@@ -99,7 +124,7 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
     {
         return -RT_EFAULT;
     }
-#endif /* defined(SOC_SERIES_STM32H7) */
+#endif /* defined(STM32_I2C_TIMINGR_IP) */
 #if defined(BSP_I2C_RX_USING_DMA)
     /* I2C2 DMA Init */
     if (i2c_drv->i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX)
@@ -325,6 +350,10 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
                                         struct rt_i2c_msg msgs[],
                                         rt_uint32_t num)
 {
+    /* timeout = data_time + dev_addr_time + reserve_time */
+#define TIMEOUT_FREQ_KHZ(freq) (((freq) / 1000U) ? ((freq) / 1000U) : 1U)
+#define TIMEOUT_CALC(msg) (((msg)->len * 8U) / TIMEOUT_FREQ_KHZ(bus->config.usage_freq) + 1U + 5U)
+
     rt_uint32_t i = 0;
     rt_int32_t ret = 0;
     struct rt_i2c_msg *msg = RT_NULL;
@@ -348,13 +377,6 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
     completion = &i2c_obj->completion;
 #endif /* defined(BSP_I2C_USING_IRQ) */
     LOG_D("xfer start %d megs", num);
-
-    rt_uint32_t freq_khz = bus->config.usage_freq / 1000;
-    if (freq_khz == 0)
-    {
-        freq_khz = 1;
-    }
-
     for (i = 0; i < num; i++)
     {
         rt_bool_t need_wait = RT_FALSE;
@@ -363,10 +385,11 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
         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);
-
-        // timeout= data_time + dev_addr_time + reserve_time
-        timeout = (msg->len * 8) / freq_khz + 1 + 5;
-
+#if defined(STM32_I2C_TIMINGR_IP)
+        timeout = bus->timeout ? bus->timeout : 100U;
+#else
+        timeout = TIMEOUT_CALC(msg);
+#endif
         if (msg->flags & RT_I2C_RD)
         {
             LOG_D("xfer  rec  msgs[%d] hal mode = %s", i, stm32_i2c_mode_name(mode));
@@ -421,38 +444,78 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
 out:
     ret = i;
     /*
-    * On STM32H7, STOPI only enables STOP-event interrupt handling.
+    * On TIMINGR-based STM32 I2C IPs (currently F7/H7 in this driver),
+    * 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.
+    * For legacy STM32 I2C IPs, the 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[%s] NACK Error", bus->parent.parent.name);
-#if defined(SOC_SERIES_STM32H7)
+#if defined(STM32_I2C_TIMINGR_IP)
         handle->Instance->CR1 |= I2C_IT_STOPI;
-#endif  /* defined(SOC_SERIES_STM32H7) */
+#endif  /* defined(STM32_I2C_TIMINGR_IP) */
     }
     if (handle->ErrorCode & HAL_I2C_ERROR_BERR)
     {
         LOG_W("I2C[%s] BUS Error", bus->parent.parent.name);
-#if defined(SOC_SERIES_STM32H7)
+#if defined(STM32_I2C_TIMINGR_IP)
         handle->Instance->CR1 |= I2C_IT_STOPI;
 #else
         handle->Instance->CR1 |= I2C_CR1_STOP;
-#endif  /* defined(SOC_SERIES_STM32H7) */
+#endif  /* defined(STM32_I2C_TIMINGR_IP) */
     }
 
     return ret;
+#undef TIMEOUT_FREQ_KHZ
+#undef TIMEOUT_CALC
+}
+
+rt_err_t stm_i2c_bus_control(struct rt_i2c_bus_device *bus, int cmd, void *args)
+{
+    struct stm32_i2c *i2c_obj;
+    RT_ASSERT(bus != RT_NULL);
+
+    i2c_obj = rt_container_of(bus, struct stm32_i2c, i2c_bus);
+    RT_ASSERT(i2c_obj != RT_NULL);
+
+    switch (cmd)
+    {
+        case BSP_I2C_CTRL_SET_TIMING:
+        {
+            if (args == RT_NULL)
+            {
+                return -RT_EINVAL;
+            }
+
+            rt_uint32_t timing = *(rt_uint32_t *)args;
+            if(timing <= 0)
+            {
+                return -RT_ERROR;
+            }
+
+            i2c_obj->i2c_bus.config.usage_freq = i2c_obj->config->timing = timing;
+            return stm32_i2c_configure(&i2c_obj->i2c_bus);
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+    return -RT_EINVAL;
 }
 
 static const struct rt_i2c_bus_device_ops stm32_i2c_ops =
 {
     .master_xfer = stm32_i2c_master_xfer,
-    RT_NULL,
-    RT_NULL,
+#if defined(STM32_I2C_LEGACY_IP)
+    .i2c_bus_control = stm_i2c_bus_control,
+#endif
+    .slave_xfer = RT_NULL,
 };
 
 int RT_hw_i2c_bus_init(void)
@@ -465,6 +528,12 @@ int RT_hw_i2c_bus_init(void)
         i2c_objs[i].i2c_bus.ops = &stm32_i2c_ops;
         i2c_objs[i].config = &i2c_config[i];
         i2c_objs[i].i2c_bus.timeout = i2c_config[i].timeout;
+        stm32_i2c_apply_default_config(&i2c_config[i]);
+#if defined(STM32_I2C_LEGACY_IP)
+        i2c_objs[i].i2c_bus.config.max_hz = i2c_config[i].timing;
+        i2c_objs[i].i2c_bus.config.usage_freq = i2c_config[i].timing;
+#endif
+
 #ifdef BSP_I2C_USING_DMA
         if ((i2c_objs[i].i2c_dma_flag & RT_DEVICE_FLAG_DMA_RX))
         {
@@ -525,7 +594,7 @@ int RT_hw_i2c_bus_init(void)
             i2c_objs[i].dma.handle_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
             i2c_objs[i].dma.handle_tx.Init.Mode                = DMA_NORMAL;
             i2c_objs[i].dma.handle_tx.Init.Priority            = DMA_PRIORITY_LOW;
-#endif
+#endif /* SOC_SERIES_STM32U5 */
 #if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7)
 
             i2c_objs[i].dma.handle_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
@@ -685,7 +754,7 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
 #endif /* I2C4 */
                                 : "unknown",
                                 hi2c->ErrorCode);
-#if defined(SOC_SERIES_STM32H7)
+#if defined(STM32_I2C_TIMINGR_IP)
     /* Send stop signal to prevent bus lock-up */
     if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
     {
@@ -697,7 +766,7 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
         LOG_W("I2C BUS Error now stoped");
         hi2c->Instance->CR1 |= I2C_IT_STOPI;
     }
-#endif /* defined(SOC_SERIES_STM32H7) */
+#endif /* defined(STM32_I2C_TIMINGR_IP) */
 }
 
 #ifdef BSP_USING_HARD_I2C1

+ 32 - 2
bsp/stm32/libraries/HAL_Drivers/drivers/drv_hard_i2c.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2024, RT-Thread Development Team
+ * Copyright (c) 2006-2026, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -7,6 +7,7 @@
  * Date           Author       Notes
  * 2024-02-17     Dyyt587      first version
  * 2024-06-23     wdfk-prog    Add mode selection scaffolding
+ * 2024-06-23     wdfk-prog    Distinguish STM32 I2C timing semantics by IP generation
  */
 
 #ifndef __DRV_HARD_I2C_H__
@@ -97,10 +98,39 @@ extern "C"
 #define BSP_I2C_USING_IRQ
 #endif
 
+/*
+ * timing semantics are intentionally split by I2C IP generation:
+ *
+ * - legacy I2C IP:
+ *   use bus frequency in Hz (for example 100000/400000), because HAL
+ *   configures the peripheral through ClockSpeed/DutyCycle.
+ *
+ * - TIMINGR-based I2C IP:
+ *   keep using the raw TIMINGR register value for now. Exact timing
+ *   generation depends on board-level inputs such as kernel clock,
+ *   rise/fall time, digital/analog filter settings, and target bus mode,
+ *   so this change does not convert TIMINGR platforms to a unified Hz API.
+ */
+#if defined(SOC_SERIES_STM32F1)  \
+ || defined(SOC_SERIES_STM32F2)  \
+ || defined(SOC_SERIES_STM32F4)  \
+ || defined(SOC_SERIES_STM32L1)
+#define STM32_I2C_LEGACY_IP
+#else
+#define STM32_I2C_TIMINGR_IP
+#endif
+
+#define BSP_I2C_CTRL_SET_TIMING 0x40
+
 struct stm32_i2c_config
 {
     const char              *name;
     I2C_TypeDef             *Instance;
+    /*
+     * timing semantics depend on the I2C IP generation:
+     * - legacy IP  (F1/F4): bus speed in Hz
+     * - TIMINGR IP (F7/H7): raw TIMINGR register value
+     */
     rt_uint32_t             timing;
     rt_uint32_t             timeout;
     IRQn_Type               evirq_type;
@@ -139,4 +169,4 @@ struct stm32_i2c
 }
 #endif
 
-#endif /* __DRV_I2C_H__ */
+#endif /* __DRV_HARD_I2C_H__ */