Răsfoiți Sursa

[components][i2c]增加通用的软件模拟 I2C (#7850)

sp-cai 1 an în urmă
părinte
comite
7f6f086601

+ 200 - 0
components/drivers/Kconfig

@@ -130,6 +130,206 @@ if RT_USING_I2C
             bool "Use simulate I2C debug message"
             default n
     endif
+
+    config RT_USING_SOFT_I2C
+        bool "Use GPIO to soft simulate I2C"
+        default n
+        select RT_USING_PIN
+        select RT_USING_I2C_BITOPS
+    if RT_USING_SOFT_I2C
+        config RT_USING_SOFT_I2C1
+            bool "Enable I2C1 Bus (software simulation)"
+            default y
+            if RT_USING_SOFT_I2C1
+                config RT_SOFT_I2C1_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 1
+                config RT_SOFT_I2C1_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 2
+                config RT_SOFT_I2C1_BUS_NAME
+                    string "Bus name"
+                    default i2c1
+                config RT_SOFT_I2C1_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C1_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C2
+            bool "Enable I2C2 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C2
+                config RT_SOFT_I2C2_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 3
+                config RT_SOFT_I2C2_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 4
+                config RT_SOFT_I2C2_BUS_NAME
+                    string "Bus name"
+                    default i2c2
+                config RT_SOFT_I2C2_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C2_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C3
+            bool "Enable I2C3 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C3
+                config RT_SOFT_I2C3_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 5
+                config RT_SOFT_I2C3_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 6
+                config RT_SOFT_I2C3_BUS_NAME
+                    string "Bus name"
+                    default i2c3
+                config RT_SOFT_I2C3_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C3_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C4
+            bool "Enable I2C4 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C4
+                config RT_SOFT_I2C4_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 7
+                config RT_SOFT_I2C4_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 8
+                config RT_SOFT_I2C4_BUS_NAME
+                    string "Bus name"
+                    default i2c4
+                config RT_SOFT_I2C4_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C4_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C5
+            bool "Enable I2C5 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C5
+                config RT_SOFT_I2C5_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 9
+                config RT_SOFT_I2C5_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C5_BUS_NAME
+                    string "Bus name"
+                    default i2c5
+                config RT_SOFT_I2C5_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C5_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C6
+            bool "Enable I2C6 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C6
+                config RT_SOFT_I2C6_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 11
+                config RT_SOFT_I2C6_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 12
+                config RT_SOFT_I2C6_BUS_NAME
+                    string "Bus name"
+                    default i2c6
+                config RT_SOFT_I2C6_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C6_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C7
+            bool "Enable I2C7 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C7
+                config RT_SOFT_I2C7_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 13
+                config RT_SOFT_I2C7_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 14
+                config RT_SOFT_I2C7_BUS_NAME
+                    string "Bus name"
+                    default i2c7
+                config RT_SOFT_I2C7_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C7_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+        config RT_USING_SOFT_I2C8
+            bool "Enable I2C8 Bus (software simulation)"
+            default n
+            if RT_USING_SOFT_I2C8
+                config RT_SOFT_I2C8_SCL_PIN
+                    int "SCL pin number"
+                    range 0 32767
+                    default 15
+                config RT_SOFT_I2C8_SDA_PIN
+                    int "SDA pin number"
+                    range 0 32767
+                    default 16
+                config RT_SOFT_I2C8_BUS_NAME
+                    string "Bus name"
+                    default i2c8
+                config RT_SOFT_I2C8_TIMING_DELAY
+                    int "Timing delay (us)"
+                    range 0 32767
+                    default 10
+                config RT_SOFT_I2C8_TIMING_TIMEOUT
+                    int "Timing timeout (tick)"
+                    range 0 32767
+                    default 10
+            endif
+    endif
 endif
 
 config RT_USING_PHY

+ 2 - 0
components/drivers/i2c/SConscript

@@ -9,6 +9,8 @@ i2c_dev.c
 
 if GetDepend('RT_USING_I2C_BITOPS'):
     src = src + ['i2c-bit-ops.c']
+if GetDepend('RT_USING_SOFT_I2C'):
+    src = src + ['soft_i2c.c']
 
 # The set of source files associated with this SConscript file.
 path = [cwd + '/../include']

+ 263 - 0
components/drivers/i2c/soft_i2c.c

@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author        Notes
+ * 2023-07-30     sp-cai        first version
+ */
+
+#include <rtdevice.h>
+
+#ifdef RT_USING_SOFT_I2C
+#if !defined(RT_USING_SOFT_I2C1) && !defined(RT_USING_SOFT_I2C2) &&\
+    !defined(RT_USING_SOFT_I2C3) && !defined(RT_USING_SOFT_I2C4) &&\
+    !defined(RT_USING_SOFT_I2C5) && !defined(RT_USING_SOFT_I2C6) &&\
+    !defined(RT_USING_SOFT_I2C7) && !defined(RT_USING_SOFT_I2C8)
+    #error "Please define at least one RT_USING_SOFT_I2Cx"
+    /*
+    This driver can be disabled at:
+    menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers
+    */
+#endif
+
+#define DBG_ENABLE
+#define DBG_TAG                         "I2C_S"
+#ifdef RT_I2C_BITOPS_DEBUG
+    #define DBG_LEVEL                   DBG_LOG
+#endif
+#include <rtdbg.h>
+
+/* i2c config class */
+struct soft_i2c_config
+{
+    rt_base_t       scl_pin;
+    rt_base_t       sda_pin;
+    const char      *bus_name;
+    rt_uint16_t     timing_delay;   /* scl and sda line delay */
+    rt_uint16_t     timing_timeout; /* in tick */
+};
+
+/* i2c dirver class */
+struct rt_soft_i2c
+{
+    struct rt_i2c_bus_device    i2c_bus;
+    struct rt_i2c_bit_ops       ops;
+};
+
+struct soft_i2c_config i2c_cfg[] =
+{
+    #ifdef RT_USING_SOFT_I2C1
+    {
+        .scl_pin        = RT_SOFT_I2C1_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C1_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C1_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C1_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C1_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C1
+    #ifdef RT_USING_SOFT_I2C2
+    {
+        .scl_pin        = RT_SOFT_I2C2_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C2_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C2_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C2_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C2_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C2
+    #ifdef RT_USING_SOFT_I2C3
+    {
+        .scl_pin        = RT_SOFT_I2C3_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C3_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C3_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C3_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C3_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C3
+    #ifdef RT_USING_SOFT_I2C4
+    {
+        .scl_pin        = RT_SOFT_I2C4_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C4_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C4_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C4_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C4_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C4
+    #ifdef RT_USING_SOFT_I2C5
+    {
+        .scl_pin        = RT_SOFT_I2C5_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C5_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C5_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C5_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C5_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C5
+    #ifdef RT_USING_SOFT_I2C6
+    {
+        .scl_pin        = RT_SOFT_I2C6_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C6_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C6_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C6_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C6_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C6
+    #ifdef RT_USING_SOFT_I2C7
+    {
+        .scl_pin        = RT_SOFT_I2C7_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C7_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C7_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C7_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C7_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C7
+    #ifdef RT_USING_SOFT_I2C8
+    {
+        .scl_pin        = RT_SOFT_I2C8_SCL_PIN,
+        .sda_pin        = RT_SOFT_I2C8_SDA_PIN,
+        .bus_name       = RT_SOFT_I2C8_BUS_NAME,
+        .timing_delay   = RT_SOFT_I2C8_TIMING_DELAY,
+        .timing_timeout = RT_SOFT_I2C8_TIMING_TIMEOUT,
+    },
+    #endif  //RT_USING_SOFT_I2C8
+};
+
+
+static struct rt_soft_i2c i2c_bus_obj[sizeof(i2c_cfg) / sizeof(i2c_cfg[0])] =
+{ 0 };
+
+/**
+* This function initializes the i2c pin.
+* @param i2c config class.
+*/
+static void pin_init(const struct soft_i2c_config *cfg)
+{
+    rt_pin_mode(cfg->scl_pin, PIN_MODE_OUTPUT_OD);
+    rt_pin_mode(cfg->sda_pin, PIN_MODE_OUTPUT_OD);
+    rt_pin_write(cfg->scl_pin, PIN_HIGH);
+    rt_pin_write(cfg->sda_pin, PIN_HIGH);
+}
+
+
+/**
+* This function sets the sda pin.
+* @param i2c config class.
+* @param The sda pin state.
+*/
+static void set_sda(void *cfg, rt_int32_t value)
+{
+    rt_pin_write(((const struct soft_i2c_config*)cfg)->sda_pin, value);
+}
+
+/**
+* This function sets the scl pin.
+* @param i2c config class.
+* @param The sda pin state.
+*/
+static void set_scl(void *cfg, rt_int32_t value)
+{
+    rt_pin_write(((const struct soft_i2c_config*)cfg)->scl_pin, value);
+}
+
+/**
+* This function gets the sda pin state.
+* @param i2c config class.
+*/
+static rt_int32_t get_sda(void *cfg)
+{
+    return rt_pin_read(((const struct soft_i2c_config*)cfg)->sda_pin);
+}
+
+/**
+* This function gets the scl pin state.
+* @param i2c config class.
+*/
+static rt_int32_t get_scl(void *cfg)
+{
+    return rt_pin_read(((const struct soft_i2c_config*)cfg)->scl_pin);
+}
+
+
+static const struct rt_i2c_bit_ops soft_i2c_ops =
+{
+    .set_sda = set_sda,
+    .set_scl = set_scl,
+    .get_sda = get_sda,
+    .get_scl = get_scl,
+    .udelay = rt_hw_us_delay,
+};
+
+/**
+* if i2c is locked, this function will unlock it
+*
+* @param i2c config class.
+*
+* @return RT_EOK indicates successful unlock.
+*/
+static rt_err_t i2c_bus_unlock(const struct soft_i2c_config *cfg)
+{
+    rt_ubase_t i = 0;
+
+    if(PIN_LOW == rt_pin_read(cfg->sda_pin))
+    {
+        while(i++ < 9)
+        {
+            rt_pin_write(cfg->scl_pin, PIN_HIGH);
+            rt_hw_us_delay(cfg->timing_delay);
+            rt_pin_write(cfg->scl_pin, PIN_LOW);
+            rt_hw_us_delay(cfg->timing_delay);
+        }
+    }
+    if(PIN_LOW == rt_pin_read(cfg->sda_pin))
+    {
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/* I2C initialization function */
+int rt_soft_i2c_init(void)
+{
+    int err = RT_EOK;
+    struct rt_soft_i2c *obj;
+
+    for(int i = 0; i < sizeof(i2c_bus_obj) / sizeof(i2c_bus_obj[0]); i++)
+    {
+        struct soft_i2c_config *cfg = &i2c_cfg[i];
+
+        pin_init(cfg);
+
+        obj = &i2c_bus_obj[i];
+        obj->ops = soft_i2c_ops;
+        obj->ops.data = cfg;
+        obj->i2c_bus.priv = &obj->ops;
+        obj->ops.delay_us = cfg->timing_delay;
+        obj->ops.timeout = cfg->timing_timeout;
+        if(rt_i2c_bit_add_bus(&obj->i2c_bus, cfg->bus_name) == RT_EOK)
+        {
+            i2c_bus_unlock(cfg);
+            LOG_D("Software simulation %s init done"
+                  ", SCL pin: 0x%02X, SDA pin: 0x%02X"
+                  , cfg->bus_name
+                  , cfg->scl_pin
+                  , cfg->sda_pin
+                 );
+        }
+        else
+        {
+            err++;
+            LOG_E("Software simulation %s init fail"
+                  ", SCL pin: 0x%02X, SDA pin: 0x%02X"
+                  , cfg->bus_name
+                  , cfg->scl_pin
+                  , cfg->sda_pin
+                 );
+        }
+    }
+
+    return err;
+}
+INIT_PREV_EXPORT(rt_soft_i2c_init);
+
+#endif // RT_USING_SOFT_I2C