Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 19 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions components/drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,114 @@ 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_I2C5
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
bool "Enable I2C5 Bus (software simulation)"
default n
if RT_USING_SOFT_I2C5
comment "Notice: PA00 --> 0x00; PA01 --> 0x01"
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
config RT_SOFT_I2C5_SCL_PIN
hex "SCL pin number"
range 0x00 0xFF
default 0x00
config RT_SOFT_I2C5_SDA_PIN
hex "SDA pin number"
range 0x00 0xFF
default 0x01
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
comment "Notice: PB02 --> 0x12; PB03 --> 0x13"
config RT_SOFT_I2C6_SCL_PIN
hex "SCL pin number"
range 0x00 0xFF
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
default 0x12
config RT_SOFT_I2C6_SDA_PIN
hex "SDA pin number"
range 0x00 0xFF
default 0x13
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
comment "Notice: PC04 --> 0x24; PC05 --> 0x25"
config RT_SOFT_I2C7_SCL_PIN
hex "SCL pin number"
range 0x00 0xFF
default 0x24
config RT_SOFT_I2C7_SDA_PIN
hex "SDA pin number"
range 0x00 0xFF
default 0x25
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
comment "Notice: PD06 --> 0x36; PD07 --> 0x37"
config RT_SOFT_I2C8_SCL_PIN
hex "SCL pin number"
range 0x00 0xFF
default 0x36
config RT_SOFT_I2C8_SDA_PIN
hex "SDA pin number"
range 0x00 0xFF
default 0x37
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
Expand Down
2 changes: 2 additions & 0 deletions components/drivers/i2c/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
220 changes: 220 additions & 0 deletions components/drivers/i2c/soft_i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* 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_I2C5) || defined(RT_USING_SOFT_I2C6)||\
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
defined(RT_USING_SOFT_I2C7) ||defined(RT_USING_SOFT_I2C8)

#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_I2C5
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
{
.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_I2Cx
#endif // RT_USING_SOFT_I2C
7 changes: 4 additions & 3 deletions components/drivers/include/drivers/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ extern "C" {
#define RT_I2C_NO_READ_ACK (1u << 6) /* when I2C reading, we do not ACK */
#define RT_I2C_NO_STOP (1u << 7)


struct rt_i2c_msg
{
rt_uint16_t addr;
rt_uint16_t flags;
rt_uint16_t len;
rt_uint32_t len;
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
rt_uint8_t *buf;
};

Expand All @@ -55,9 +56,9 @@ struct rt_i2c_bus_device
struct rt_device parent;
const struct rt_i2c_bus_device_ops *ops;
rt_uint16_t flags;
rt_uint16_t retries;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i2c.h 修改理由?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一个操作的重试次数没必要用32位数值,16位数值更有利于字节对齐。
这个修改探讨一下

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你在哪里用到这个变量了?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

见 i2c-bit-ops.c 这个文件用到的

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

哦,你改了下位置。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的

struct rt_mutex lock;
rt_uint32_t timeout;
rt_uint32_t retries;
void *priv;
};

Expand Down Expand Up @@ -87,7 +88,7 @@ rt_ssize_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
rt_uint8_t *buf,
rt_uint32_t count);

rt_inline rt_err_t rt_i2c_bus_lock(struct rt_i2c_bus_device *bus, rt_tick_t timeout)
rt_inline rt_err_t rt_i2c_bus_lock(struct rt_i2c_bus_device *bus, rt_int32_t timeout)
sp-cai marked this conversation as resolved.
Show resolved Hide resolved
{
return rt_mutex_take(&bus->lock, timeout);
}
Expand Down