From 0e25b92cd79d43eb017f2fda7a95024c032c4943 Mon Sep 17 00:00:00 2001 From: MacRsh Date: Thu, 14 Dec 2023 00:41:37 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E8=BD=AF=E4=BB=B6I2C?= =?UTF-8?q?=E6=80=BB=E7=BA=BF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- device/soft_i2c.c | 267 ++++++++++++++++++++++++++++++++++++++ document/Kconfig.md | 4 +- include/device/soft_i2c.h | 47 +++++++ include/mr_lib.h | 3 + include/mr_service.h | 4 +- 5 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 device/soft_i2c.c create mode 100644 include/device/soft_i2c.h diff --git a/device/soft_i2c.c b/device/soft_i2c.c new file mode 100644 index 0000000..8aac185 --- /dev/null +++ b/device/soft_i2c.c @@ -0,0 +1,267 @@ +/* + * @copyright (c) 2023, MR Development Team + * + * @license SPDX-License-Identifier: Apache-2.0 + * + * @date 2023-12-13 MacRsh First version + */ + +#include "include/device/soft_i2c.h" + +#if defined(MR_USING_I2C) && defined(MR_USING_SOFT_I2C) + +#ifdef MR_USING_PIN +#include "include/device/pin.h" +#else +#warning "Please define MR_USING_PIN. Otherwise Soft-I2C will not work." +#endif /* MR_USING_PIN */ + +#define SOFT_I2C_LOW 0 +#define SOFT_I2C_HIGH 1 + +MR_INLINE void soft_i2c_scl_set(struct mr_soft_i2c_bus *soft_i2c_bus, uint8_t value) +{ + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->scl_pin); + mr_dev_write(soft_i2c_bus->desc, &value, sizeof(value)); +} + +MR_INLINE void soft_i2c_bus_sda_set(struct mr_soft_i2c_bus *soft_i2c_bus, uint8_t value) +{ + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->sda_pin); + mr_dev_write(soft_i2c_bus->desc, &value, sizeof(value)); +} + +MR_INLINE uint8_t soft_i2c_sda_get(struct mr_soft_i2c_bus *soft_i2c_bus) +{ + uint8_t value = 0; + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->sda_pin); + mr_dev_read(soft_i2c_bus->desc, &value, sizeof(value)); + return value; +} + +static void soft_i2c_bus_wait_ack(struct mr_i2c_bus *i2c_bus) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_HIGH); + mr_delay_us(soft_i2c_bus->delay); + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_HIGH); + mr_delay_us(soft_i2c_bus->delay); + + soft_i2c_sda_get(soft_i2c_bus); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); +} + +static void soft_i2c_bus_send_ack(struct mr_i2c_bus *i2c_bus, int ack) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); + if (ack == MR_ENABLE) + { + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_LOW); + } else + { + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_HIGH); + } + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_HIGH); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); +} + +static int mr_soft_i2c_bus_configure(struct mr_i2c_bus *i2c_bus, struct mr_i2c_config *config, int addr, int addr_bits) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + int state = (config->baud_rate != 0) ? MR_ENABLE : MR_DISABLE; + + if (state == MR_ENABLE) + { + if (soft_i2c_bus->desc < 0) + { + soft_i2c_bus->desc = mr_dev_open("pin", MR_OFLAG_RDWR); + if (soft_i2c_bus->desc < 0) + { + return soft_i2c_bus->desc; + } + } + + /* Configure SCL pin */ + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->scl_pin); + int ret = mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_MODE, mr_make_local(int, MR_PIN_MODE_OUTPUT_OD)); + if (ret < 0) + { + return ret; + } + + /* Configure SDA pin */ + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->sda_pin); + ret = mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_MODE, mr_make_local(int, MR_PIN_MODE_OUTPUT_OD)); + if (ret < 0) + { + return ret; + } + } else + { + if (soft_i2c_bus->desc >= 0) + { + /* Reconfigure SCL pin */ + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->scl_pin); + int ret = mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_MODE, mr_make_local(int, MR_PIN_MODE_NONE)); + if (ret < 0) + { + return ret; + } + + /* Reconfigure SDA pin */ + mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_NUMBER, &soft_i2c_bus->sda_pin); + ret = mr_dev_ioctl(soft_i2c_bus->desc, MR_CTL_PIN_SET_MODE, mr_make_local(int, MR_PIN_MODE_NONE)); + if (ret < 0) + { + return ret; + } + + mr_dev_close(soft_i2c_bus->desc); + soft_i2c_bus->desc = -1; + } + } + return MR_EOK; +} + +static void mr_soft_i2c_bus_start(struct mr_i2c_bus *i2c_bus) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_HIGH); + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_HIGH); + + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); +} + +static void mr_soft_i2c_bus_write(struct mr_i2c_bus *i2c_bus, uint8_t data); + +static void mr_soft_i2c_bus_send_addr(struct mr_i2c_bus *i2c_bus, int addr, int addr_bits) +{ + mr_soft_i2c_bus_write(i2c_bus, addr); + if (addr_bits == MR_I2C_ADDR_BITS_10) + { + mr_soft_i2c_bus_write(i2c_bus, (addr >> 8)); + } +} + +static void mr_soft_i2c_bus_stop(struct mr_i2c_bus *i2c_bus) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_LOW); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_HIGH); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_HIGH); +} + +static uint8_t mr_soft_i2c_bus_read(struct mr_i2c_bus *i2c_bus, int ack_state) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + uint8_t data = 0; + size_t bits = 0; + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_HIGH); + + for (bits = 0; bits < 8; bits++) + { + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_HIGH); + mr_delay_us(soft_i2c_bus->delay); + data <<= 1; + if (soft_i2c_sda_get(soft_i2c_bus) == SOFT_I2C_HIGH) + { + data |= 0x01; + } + } + + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_bus_send_ack(i2c_bus, ack_state); + return data; +} + +static void mr_soft_i2c_bus_write(struct mr_i2c_bus *i2c_bus, uint8_t data) +{ + struct mr_soft_i2c_bus *soft_i2c_bus = (struct mr_soft_i2c_bus *)i2c_bus; + size_t bits = 0; + + for (bits = 0; bits < 8; bits++) + { + if (data & 0x80) + { + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_HIGH); + } else + { + soft_i2c_bus_sda_set(soft_i2c_bus, SOFT_I2C_LOW); + } + data <<= 1; + + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_HIGH); + mr_delay_us(soft_i2c_bus->delay); + soft_i2c_scl_set(soft_i2c_bus, SOFT_I2C_LOW); + } + soft_i2c_bus_wait_ack(i2c_bus); +} + +/** + * @brief This function registers a soft-i2c-bus. + * + * @param soft_i2c_bus The soft-i2c-bus. + * @param name The name of the soft-i2c-bus. + * @param scl_pin The scl pin of the soft-i2c-bus. + * @param sda_pin The sda pin of the soft-i2c-bus. + * + * @return MR_EOK on success, otherwise an error code. + */ +int mr_soft_i2c_bus_register(struct mr_soft_i2c_bus *soft_i2c_bus, const char *name, int scl_pin, int sda_pin) +{ + static struct mr_i2c_bus_ops ops = + { + mr_soft_i2c_bus_configure, + mr_soft_i2c_bus_start, + mr_soft_i2c_bus_send_addr, + mr_soft_i2c_bus_stop, + mr_soft_i2c_bus_read, + mr_soft_i2c_bus_write + }; + static struct mr_drv drv = + { + Mr_Drv_Type_I2C, + &ops, + MR_NULL + }; + + mr_assert(soft_i2c_bus != MR_NULL); + mr_assert(name != MR_NULL); + + /* Initialize the fields */ + soft_i2c_bus->delay = 0; + soft_i2c_bus->scl_pin = scl_pin; + soft_i2c_bus->sda_pin = sda_pin; + soft_i2c_bus->desc = -1; + + return mr_i2c_bus_register(&soft_i2c_bus->i2c_bus, name, &drv); +} + +#endif /* defined(MR_USING_I2C) && defined(MR_USING_SOFT_I2C) */ diff --git a/document/Kconfig.md b/document/Kconfig.md index 7c131f3..9fc60ef 100644 --- a/document/Kconfig.md +++ b/document/Kconfig.md @@ -81,9 +81,7 @@ import re import sys import textwrap -from kconfiglib import Kconfig, split_expr, expr_value, expr_str, BOOL, - TRISTATE, TRI_TO_STR, AND, OR - +from kconfiglib import Kconfig, split_expr, expr_value, expr_str, BOOL, TRISTATE, TRI_TO_STR, AND, OR def generate_config(kconfig_file, config_in, config_out, header_out): print("Parsing " + kconfig_file) diff --git a/include/device/soft_i2c.h b/include/device/soft_i2c.h new file mode 100644 index 0000000..6807f49 --- /dev/null +++ b/include/device/soft_i2c.h @@ -0,0 +1,47 @@ +/* + * @copyright (c) 2023, MR Development Team + * + * @license SPDX-License-Identifier: Apache-2.0 + * + * @date 2023-12-13 MacRsh First version + */ + +#ifndef _SOFT_I2C_H_ +#define _SOFT_I2C_H_ + +#include "include/mr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if defined(MR_USING_I2C) && defined(MR_USING_SOFT_I2C) + +#include "include/device/i2c.h" + +/** +* @brief Soft-I2C bus structure. +*/ +struct mr_soft_i2c_bus +{ + struct mr_i2c_bus i2c_bus; /* I2C-bus device */ + + uint32_t delay; /* Speed delay */ + int scl_pin; /* SCL pin */ + int sda_pin; /* SDA pin */ + int desc; /* SCL-SDA descriptor */ +}; + +/** +* @addtogroup Soft-I2C. +* @{ +*/ +int mr_soft_i2c_bus_register(struct mr_soft_i2c_bus *soft_i2c_bus, const char *name, int scl_pin, int sda_pin); +/** @} */ +#endif /* defined(MR_USING_I2C) && defined(MR_USING_SOFT_I2C) */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _SOFT_I2C_H_ */ diff --git a/include/mr_lib.h b/include/mr_lib.h index 46180ac..1dd333c 100644 --- a/include/mr_lib.h +++ b/include/mr_lib.h @@ -29,6 +29,9 @@ extern "C" { #ifdef MR_USING_I2C #include "device/i2c.h" +#ifdef MR_USING_SOFT_I2C +#include "device/soft_i2c.h" +#endif #endif #ifdef MR_USING_PIN diff --git a/include/mr_service.h b/include/mr_service.h index 009049f..0dc250f 100644 --- a/include/mr_service.h +++ b/include/mr_service.h @@ -62,12 +62,12 @@ extern "C" { #define mr_log_error(fmt, ...) #endif /* MR_USING_LOG_ERROR */ #ifdef MR_USING_LOG_WARN -#define mr_log_warn(fmt, ...) mr_log("warn", fmt, ##__VA_ARGS__) +#define mr_log_warn(fmt, ...) mr_log("warn ", fmt, ##__VA_ARGS__) #else #define mr_log_warn(fmt, ...) #endif /* MR_USING_LOG_WARN */ #ifdef MR_USING_LOG_INFO -#define mr_log_info(fmt, ...) mr_log("info", fmt, ##__VA_ARGS__) +#define mr_log_info(fmt, ...) mr_log("info ", fmt, ##__VA_ARGS__) #else #define mr_log_info(fmt, ...) #endif /* MR_USING_LOG_INFO */