/**********************************************************************
|
* Copyright: (C)2024 LingYun IoT System Studio
|
* Author: GuoWenxue<guowenxue@gmail.com>
|
*
|
* Description: The purpose of this code is to provide a simple C library,
|
* which providing software bit-bang of the I2C protocol on
|
* any GPIO pins for ISKBoard.
|
*
|
* ChangeLog:
|
* Version Date Author Description
|
* V1.0.0 2024.08.29 GuoWenxue Release initial version
|
*
|
***********************************************************************/
|
|
#ifndef __I2C_BITBANG_H
|
#define __I2C_BITBANG_H
|
|
#include "stm32l4xx_hal.h"
|
#include <stdint.h>
|
#include <stdatomic.h>
|
|
#define I2C_DELAY_US 5 /* I2C timing delay in microseconds */
|
#define I2C_TIMEOUT_COUNT 100 /* Timeout counter for waiting ACK */
|
|
/* GPIO port for I2C typedef */
|
typedef struct i2c_gpio_s
|
{
|
GPIO_TypeDef *group; /* GPIO group */
|
uint16_t pin; /* GPIO pin */
|
} i2c_gpio_t;
|
|
/* I2C bus typedef */
|
typedef struct i2c_bus_s
|
{
|
volatile atomic_bool lock; /* Bus lock flag */
|
uint8_t addr; /* 7-bits slave address */
|
i2c_gpio_t scl; /* SCL GPIO pin */
|
i2c_gpio_t sda; /* SDA GPIO pin */
|
} i2c_bus_t;
|
|
/* GPIO level enum */
|
enum
|
{
|
LOW = 0,
|
HIGH = 1,
|
};
|
|
/* I2C ACK/NACK enum */
|
typedef enum
|
{
|
I2C_ACK = 0,
|
I2C_NACK = 1
|
} i2c_ack_t;
|
|
/* I2C status enum */
|
typedef enum
|
{
|
I2C_OK = 0,
|
I2C_ERROR = 1,
|
I2C_TIMEOUT = 2,
|
I2C_BUSY = 3
|
} i2c_status_t;
|
|
/*
|
*+---------------------------------+
|
*| I2C bus control function |
|
*+---------------------------------+
|
*/
|
|
/* I2C1 bus instance for SHT20, RTC, OLED on board */
|
extern i2c_bus_t i2c1_bus;
|
|
/* I2C2 bus instance on MikroBUS */
|
extern i2c_bus_t i2c2_bus;
|
|
/**
|
* @brief Initialize I2C GPIO pins
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_init(i2c_bus_t *bus);
|
|
/**
|
* @brief Deinitialize I2C GPIO pins
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_deinit(i2c_bus_t *bus);
|
|
/**
|
* @brief 通用 I2C 设备属性结构体
|
*/
|
typedef struct {
|
i2c_bus_t *bus; /* 绑定的 I2C 物理总线实例 */
|
uint8_t dev_addr; /* 7位设备物理从机地址 */
|
} i2c_dev_t;
|
|
/**
|
* @brief 绑定设备及地址到 I2C 总线上
|
* @param dev: I2C 设备结构体指针
|
* @param bus: 物理总线指针
|
* @param dev_addr: 7位从机地址
|
* @retval 0: 成功; -1: 失败
|
*/
|
extern int i2c_bind_dev(i2c_dev_t *dev, i2c_bus_t *bus, uint8_t dev_addr);
|
|
|
/**
|
* @brief 将I2C总线加锁让设备独占总线
|
* @param dev: I2C 设备结构体指针
|
* @retval 0: 成功; -1: 失败
|
*/
|
extern int i2c_lock_dev(i2c_dev_t *dev);
|
|
/**
|
* @brief 释放设备的 I2C 总线锁
|
* @param dev: I2C 设备结构体指针
|
* @retval 无
|
*/
|
extern void i2c_free_dev(i2c_dev_t *dev);
|
|
/**
|
* @brief Lock I2C bus for exclusive access (bare metal mutex)
|
* @param bus: pointer to I2C bus structure
|
* @retval I2C_OK if success, I2C_BUSY if bus is locked
|
*/
|
extern i2c_status_t i2c_lock(i2c_bus_t *bus);
|
|
/**
|
* @brief Unlock I2C bus
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_unlock(i2c_bus_t *bus);
|
|
/**
|
* @brief Scan I2C bus for connected devices
|
* @param bus: pointer to I2C bus structure
|
* @retval none
|
*/
|
extern void i2c_scan(i2c_bus_t *bus);
|
|
|
/*
|
*+---------------------------------+
|
*| I2C timing sequence function |
|
*+---------------------------------+
|
*/
|
|
/**
|
* @brief Generate I2C start condition
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_start(i2c_bus_t *bus);
|
|
/**
|
* @brief Generate I2C stop condition
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_stop(i2c_bus_t *bus);
|
|
/**
|
* @brief Wait for ACK from slave
|
* @param bus: pointer to I2C bus structure
|
* @retval I2C_ACK or I2C_NACK
|
*/
|
extern i2c_ack_t i2c_wait_ack(i2c_bus_t *bus);
|
|
/**
|
* @brief Send ACK to slave
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_send_ack(i2c_bus_t *bus);
|
|
/**
|
* @brief Send NACK to slave
|
* @param bus: pointer to I2C bus structure
|
* @retval None
|
*/
|
extern void i2c_send_nack(i2c_bus_t *bus);
|
|
/**
|
* @brief Write one byte to I2C bus
|
* @param bus: pointer to I2C bus structure
|
* @param byte: byte to write
|
* @retval None
|
*/
|
extern void i2c_write_byte(i2c_bus_t *bus, uint8_t byte);
|
|
/**
|
* @brief Read one byte from I2C bus
|
* @param bus: pointer to I2C bus structure
|
* @retval received byte
|
*/
|
extern uint8_t i2c_read_byte(i2c_bus_t *bus);
|
|
|
/*
|
*+-----------------------------------+
|
*| I2C read/write function |
|
*+-----------------------------------+
|
*/
|
|
/**
|
* @brief Write data to I2C slave device
|
* @param bus: pointer to I2C bus structure
|
* @param addr: 7-bit slave address
|
* @param reg: register address
|
* @param data: pointer to data buffer
|
* @param len: data length
|
* @retval I2C status
|
*/
|
extern i2c_status_t i2c_write(i2c_bus_t *bus, uint8_t addr, uint8_t reg, uint8_t *data, uint16_t len);
|
|
/**
|
* @brief Read data from I2C slave device
|
* @param bus: pointer to I2C bus structure
|
* @param addr: 7-bit slave address
|
* @param reg: register address
|
* @param data: pointer to data buffer
|
* @param len: data length
|
* @retval I2C status
|
*/
|
extern i2c_status_t i2c_read(i2c_bus_t *bus, uint8_t addr, uint8_t reg, uint8_t *data, uint16_t len);
|
|
/**
|
* @brief Write data to I2C slave device without register address
|
* @param bus: pointer to I2C bus structure
|
* @param addr: 7-bit slave address
|
* @param data: pointer to data buffer
|
* @param len: data length
|
* @retval I2C status
|
*/
|
extern i2c_status_t i2c_write_no_reg(i2c_bus_t *bus, uint8_t addr, uint8_t *data, uint16_t len);
|
|
/**
|
* @brief Read data from I2C slave device without register address
|
* @param bus: pointer to I2C bus structure
|
* @param addr: 7-bit slave address
|
* @param data: pointer to data buffer
|
* @param len: data length
|
* @retval I2C status
|
*/
|
extern i2c_status_t i2c_read_no_reg(i2c_bus_t *bus, uint8_t addr, uint8_t *data, uint16_t len);
|
|
|
/*
|
*+-----------------------------------+
|
*| Linux I2C API–compatible function |
|
*+-----------------------------------+
|
*/
|
|
#define I2C_M_WR 0x0000 /* 写控制标志 */
|
#define I2C_M_RD 0x0001 /* 读控制标志 */
|
|
typedef struct {
|
uint8_t addr; /* 7位从机地址 */
|
uint16_t flags; /* I2C_M_WR 或 I2C_M_RD */
|
uint16_t len; /* 数据长度 */
|
uint8_t *buf; /* 数据指针 */
|
} i2c_msg_t;
|
|
/* Functions compatible with the Linux I2C adapter API */
|
extern i2c_status_t i2c_transfer(i2c_bus_t *bus, i2c_msg_t *msgs, int num);
|
|
#endif /* __I2C_BITBANG_H */
|