From 7f6f086601a5e3f964dc6d3bf958d1eb250b7d0e Mon Sep 17 00:00:00 2001 From: sp-cai <70000077+sp-cai@users.noreply.github.com> Date: Tue, 17 Oct 2023 23:24:32 +0800 Subject: [PATCH] =?UTF-8?q?[components][i2c]=E5=A2=9E=E5=8A=A0=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E8=BD=AF=E4=BB=B6=E6=A8=A1=E6=8B=9F=20I2C=20?= =?UTF-8?q?(#7850)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/drivers/Kconfig | 200 +++++++++++++++++++++++ components/drivers/i2c/SConscript | 2 + components/drivers/i2c/soft_i2c.c | 263 ++++++++++++++++++++++++++++++ 3 files changed, 465 insertions(+) create mode 100644 components/drivers/i2c/soft_i2c.c diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 4fd3553df2..1bb9a07c91 100755 --- a/components/drivers/Kconfig +++ b/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 diff --git a/components/drivers/i2c/SConscript b/components/drivers/i2c/SConscript index 5e85a645a7..aef9f5be9b 100644 --- a/components/drivers/i2c/SConscript +++ b/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'] diff --git a/components/drivers/i2c/soft_i2c.c b/components/drivers/i2c/soft_i2c.c new file mode 100644 index 0000000000..7c3bd1e93a --- /dev/null +++ b/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 + +#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 + +/* 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