-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvirtual_i2c.c
307 lines (284 loc) · 7.28 KB
/
virtual_i2c.c
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
// Copyright (c) 2019 Yoki
// Licensed under the MIT License
/**
*******************************************************************************
* @file virtual_i2c.c
* @author Yoki
* @version V1.0.0
* @date 2017-4-16
* @brief Use GPIO virtual i2c bus protocol
********************************************************************************
*/
#include "stm32f1xx_hal.h"
#include "virtual_i2c.h"
#define VI2C_SCL_HIGH(_VIRTUAL_I2C_) (_VIRTUAL_I2C_.gpioPort->BSRR |= _VIRTUAL_I2C_.i2cSclPin)
#define VI2C_SCL_LOW(_VIRTUAL_I2C_) (_VIRTUAL_I2C_.gpioPort->BRR |= _VIRTUAL_I2C_.i2cSclPin)
#define VI2C_SDA_HIGH(_VIRTUAL_I2C_) (_VIRTUAL_I2C_.gpioPort->BSRR |= _VIRTUAL_I2C_.i2cSdaPin)
#define VI2C_SDA_LOW(_VIRTUAL_I2C_) (_VIRTUAL_I2C_.gpioPort->BRR |= _VIRTUAL_I2C_.i2cSdaPin)
#define VI2C_SDA_READ(_VIRTUAL_I2C_) ((_VIRTUAL_I2C_.gpioPort->ODR & _VIRTUAL_I2C_.i2cSdaPin) ? 1 : 0)
#define VI2C_SCL_READ(_VIRTUAL_I2C_) ((_VIRTUAL_I2C_.gpioPort->ODR & _VIRTUAL_I2C_.i2cSclPin) ? 1 : 0)
/**
* @fn static void i2cDelay
*
* @brief I2C bus delay, on the standard mode, i2c clock speed is 100KHz
* while on the fast mode, the clock speed up to 400KHz
*
* input parameters
*
* @param None
*
* output parameters
*
* @retval None
*
*/
void i2cDelay(I2cSpeed_e i2cSpeed)
{
uint8_t i = (uint8_t)i2cSpeed;
for (; i > 0; i--); /*!< When STM32 clock is 72MHz, run at the flash and MDK no optimize set */
/*!< When cycle count is 10, the i2c clock freqency is 205KHz */
/*!< When cycle count is 7, the i2c clock freqency is 347KHz, SCL high level is 1.5us and low level is 2.87us */
/*!< When cycle count is 5, the i2c clock freqency is 421KHz, SCL high level is 1.25us and low level is 2.375us */
}
/**
* @fn void i2cStart
*
* @brief Send a start signal to the i2c bus.
*
* input parameters
*
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval None
*
*/
void i2cStart(VirtualI2C_s sI2C)
{
VI2C_SDA_HIGH(sI2C.sI2cPortPin);
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin);
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SDA_LOW(sI2C.sI2cPortPin);
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SCL_LOW(sI2C.sI2cPortPin);
i2cDelay(sI2C.eI2cSpeed);
}
/**
* @fn void i2cStop
*
* @brief Send a stop signal to the i2c bus.
*
* input parameters
* @param sI2C: sI2C: specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval None
*
*/
void i2cStop(VirtualI2C_s sI2C)
{
VI2C_SDA_LOW(sI2C.sI2cPortPin);
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin);
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SDA_HIGH(sI2C.sI2cPortPin);
}
/**
* @fn void i2cSendByte
*
* @brief Send a byte data to i2c device.
*
* input parameters
*
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @param ucByte - the data that what to send.
*
* @retval None
*
*/
void i2cSendByte(VirtualI2C_s sI2C, uint8_t ucByte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
if (ucByte & 0x80) VI2C_SDA_HIGH(sI2C.sI2cPortPin);
else VI2C_SDA_LOW(sI2C.sI2cPortPin);
i2cDelay(sI2C.eI2cSpeed);
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin); // sampling data
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
//VI2C_SCL_HIGH(sI2C.sI2cPortPin); // sampling data
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SCL_LOW(sI2C.sI2cPortPin);
if (i >= 7) VI2C_SDA_HIGH(sI2C.sI2cPortPin); // realese i2c bus
ucByte <<= 1;
sI2C.I2C_Delay(sI2C.eI2cSpeed); // optional comment
}
}
/**
* @fn uint8_t i2cReadByte
*
* @brief read a byte data from i2c device.
*
* input parameters
*
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval value - a byte data from i2c device.
*
*/
uint8_t i2cReadByte(VirtualI2C_s sI2C)
{
uint8_t i, value = 0;
//uint8_t readValue;
for (i = 0; i < 8; i++)
{
value <<= 1;
//VI2C_SCL_HIGH(sI2C.sI2cPortPin);
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin);
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
sI2C.I2C_Delay(sI2C.eI2cSpeed);
//readValue = VI2C_SDA_READ(sI2C.sI2cPortPin);
if ( VI2C_SDA_READ(sI2C.sI2cPortPin) == 1 ) value++;
VI2C_SCL_LOW(sI2C.sI2cPortPin);
sI2C.I2C_Delay(sI2C.eI2cSpeed);
}
return value;
}
/**
* @fn uint8_t i2cWaitAck
*
* @brief Generate a i2c clock and then read a ACK signal.
*
* input parameters
*
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval ret - 0: correct ACK signal, 1: no device acknowledge.
*
*/
uint8_t i2cWaitAck(VirtualI2C_s sI2C)
{
uint8_t ret = 0;
VI2C_SDA_HIGH(sI2C.sI2cPortPin); // release i2c bus
sI2C.I2C_Delay(sI2C.eI2cSpeed);
// VI2C_SCL_HIGH(sI2C.sI2cPortPin); // Pull high SCL then SDA return ACK signal
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin); // Pull high SCL then SDA return ACK signal
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
sI2C.I2C_Delay(sI2C.eI2cSpeed);
if ( VI2C_SDA_READ(sI2C.sI2cPortPin) == 1) ret = 1; // sampling data
VI2C_SCL_LOW(sI2C.sI2cPortPin);
sI2C.I2C_Delay(sI2C.eI2cSpeed);
return ret;
}
/**
* @fn i2cAck
*
* @brief Generate a ACK singal.
*
* input parameters
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval None
*
*/
void i2cAck(VirtualI2C_s sI2C)
{
VI2C_SDA_LOW(sI2C.sI2cPortPin);
sI2C.I2C_Delay(sI2C.eI2cSpeed);
// VI2C_SCL_HIGH(sI2C.sI2cPortPin); // generate a i2c clock
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin); // generate a i2c clcok
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SCL_LOW(sI2C.sI2cPortPin);
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SDA_HIGH(sI2C.sI2cPortPin); // release i2c bus
}
/**
* @fn void i2cNAck
*
* @brief Generate a NACK signal.
*
* input parameters
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval None
*
*/
void i2cNAck(VirtualI2C_s sI2C)
{
VI2C_SDA_HIGH(sI2C.sI2cPortPin); // release i2c bus
sI2C.I2C_Delay(sI2C.eI2cSpeed);
// VI2C_SCL_HIGH(sI2C.sI2cPortPin); // generate a i2c clcok
for(;;)
{
VI2C_SCL_HIGH(sI2C.sI2cPortPin); // generate a i2c clcok
if ( VI2C_SCL_READ(sI2C.sI2cPortPin) == 1 )
break;
}
sI2C.I2C_Delay(sI2C.eI2cSpeed);
VI2C_SCL_LOW(sI2C.sI2cPortPin);
sI2C.I2C_Delay(sI2C.eI2cSpeed);
}
/**
* @fn uint8_t i2cCheckDevice
*
* @brief Check if exist i2c device on the i2c bus, the i2c master send a address of
* slave to bus, then judgement the corresponding slave device whether or not
exist by read ACK signal on i2c bus.
*
* input parameters
* @param sI2C - specifies a struct of virtual i2c bus configuration.
*
* output parameters
*
* @retval ucAck - 0: device exist, 1: no device exist.
*
*/
uint8_t i2cCheckDevice(VirtualI2C_s sI2C)
{
uint8_t ucAck;
i2cStart(sI2C);
i2cSendByte(sI2C, (I2C_WR | sI2C.I2cAddr_un.i2c7BitAddr)); /*!< Send device address and R/W access control bit: 0 - W, 1 - R*/
ucAck = i2cWaitAck(sI2C); // wati slave ACK signal
i2cStop(sI2C);
return ucAck;
}
/**************************************** Copyright (C) 2019 Yoki **************************************/