guowenxue
4 days ago d42fb887237e30d5026e006a3774d6b0a215b829
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/**********************************************************************
 *   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 */