-
Notifications
You must be signed in to change notification settings - Fork 0
/
i2c_if.c
402 lines (370 loc) · 10.8 KB
/
i2c_if.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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// Standard includes
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
// Driverlib includes
#include "hw_types.h"
#include "hw_memmap.h"
#include "hw_ints.h"
#include "hw_i2c.h"
#include "i2c.h"
#include "pin.h"
#include "rom.h"
#include "rom_map.h"
#include "prcm.h"
// Common interface include
#include "i2c_if.h"
#include "registers_def.h"
#define I2C_BASE I2CA0_BASE
#define SYS_CLK 80000000
#define FAILURE -1
#define SUCCESS 0
#define RETERR_IF_TRUE(condition) {if(condition) return FAILURE;}
#define RET_IF_ERR(Func) {int iRetVal = (Func); \
if (SUCCESS != iRetVal) \
return iRetVal;}
static int I2CTransact(unsigned long ulCmd);
int
ADE7880_Read(Register reg, int *data)
{
//Data holders for the I2C Communcation
unsigned char ucDevAddr, ucRegAddr[2], ucRdLen;
unsigned char aucRdDataBuf[256];
//Spit or Convert the values into bytes (unsigned char - 1 byte)
ucDevAddr = (unsigned char) DEV_ADDR;
ucRegAddr[0] = (unsigned char) (reg.address>>8);
ucRegAddr[1] = (unsigned char) reg.address;
ucRdLen = (unsigned char) reg.length;
//Write the Register Address to Read
RET_IF_ERR(I2C_IF_Write(ucDevAddr,ucRegAddr,2,0));
//Read the Register data to aucRdDataBuf
RET_IF_ERR(I2C_IF_Read(ucDevAddr, &aucRdDataBuf[0], ucRdLen));
//Convert data from buffer to value
*data = (aucRdDataBuf[0] << 24) + (aucRdDataBuf[1] << 16) + (aucRdDataBuf[2] << 8) + (aucRdDataBuf[3]);
*data = *data >> (32 - (reg.length*8));
return SUCCESS;
}
int
ADE7880_Write(Register reg, int data)
{
//Data holders for the I2C Communcation
unsigned char ucDevAddr, ucStopBit, ucLen;
unsigned char aucDataBuf[256];
//Temporarty Variables
int iRetVal;
int count;
//Spit or Convert the values into bytes (unsigned char - 1 byte)
ucDevAddr = (unsigned char) DEV_ADDR;
ucLen = (unsigned char) reg.length + 2;
ucStopBit = (unsigned char) 1;
aucDataBuf[0] = (unsigned char) (reg.address>>8);
aucDataBuf[1] = (unsigned char) reg.address;
//Data value buffered as individual bytes
for(count = 2; reg.length >= 0; reg.length--, count++)
{
aucDataBuf[count] = (unsigned char) (data >> ((reg.length-1) * 8));
}
//Write to the data into the given Register
iRetVal = I2C_IF_Write(ucDevAddr, aucDataBuf, ucLen, ucStopBit); //TODO Change the iRetVal to RET_IF_ERR()
return iRetVal;
}
//****************************************************************************
//
//! Invokes the transaction over I2C
//!
//! \param ulCmd is the command to be executed over I2C
//!
//! This function works in a polling mode,
//! 1. Initiates the transfer of the command.
//! 2. Waits for the I2C transaction completion
//! 3. Check for any error in transaction
//! 4. Clears the master interrupt
//!
//! \return 0: Success, < 0: Failure.
//
//****************************************************************************
static int I2CTransact(unsigned long ulCmd) {
//
// Clear all interrupts
//
MAP_I2CMasterIntClearEx(I2C_BASE,
MAP_I2CMasterIntStatusEx(I2C_BASE, false));
//
// Set the time-out. Not to be used with breakpoints.
//
MAP_I2CMasterTimeoutSet(I2C_BASE, I2C_TIMEOUT_VAL);
//
// Initiate the transfer.
//
MAP_I2CMasterControl(I2C_BASE, ulCmd);
//
// Wait until the current byte has been transferred.
// Poll on the raw interrupt status.
//
while ((MAP_I2CMasterIntStatusEx(I2C_BASE, false)
& (I2C_INT_MASTER | I2C_MRIS_CLKTOUT)) == 0) {
}
//
// Check for any errors in transfer
//
if (MAP_I2CMasterErr(I2C_BASE) != I2C_MASTER_ERR_NONE) {
switch (ulCmd) {
case I2C_MASTER_CMD_BURST_SEND_START:
case I2C_MASTER_CMD_BURST_SEND_CONT:
case I2C_MASTER_CMD_BURST_SEND_STOP:
MAP_I2CMasterControl(I2C_BASE,
I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
break;
case I2C_MASTER_CMD_BURST_RECEIVE_START:
case I2C_MASTER_CMD_BURST_RECEIVE_CONT:
case I2C_MASTER_CMD_BURST_RECEIVE_FINISH:
MAP_I2CMasterControl(I2C_BASE,
I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
break;
default:
break;
}
return FAILURE;
}
return SUCCESS;
}
//****************************************************************************
//
//! Invokes the I2C driver APIs to write to the specified address
//!
//! \param ucDevAddr is the 7-bit I2C slave address
//! \param pucData is the pointer to the data to be written
//! \param ucLen is the length of data to be written
//! \param ucStop determines if the transaction is followed by stop bit
//!
//! This function works in a polling mode,
//! 1. Writes the device register address to be written to.
//! 2. In a loop, writes all the bytes over I2C
//!
//! \return 0: Success, < 0: Failure.
//
//****************************************************************************
int I2C_IF_Write(unsigned char ucDevAddr, unsigned char *pucData,
unsigned char ucLen, unsigned char ucStop) {
RETERR_IF_TRUE(pucData == NULL);
RETERR_IF_TRUE(ucLen == 0);
//
// Set I2C codec slave address
//
MAP_I2CMasterSlaveAddrSet(I2C_BASE, ucDevAddr, false);
//
// Write the first byte to the controller.
//
MAP_I2CMasterDataPut(I2C_BASE, *pucData);
//
// Initiate the transfer.
//
RET_IF_ERR(I2CTransact(I2C_MASTER_CMD_BURST_SEND_START));
//
// Decrement the count and increment the data pointer
// to facilitate the next transfer
//
ucLen--;
pucData++;
//
// Loop until the completion of transfer or error
//
while (ucLen) {
//
// Write the next byte of data
//
MAP_I2CMasterDataPut(I2C_BASE, *pucData);
//
// Transact over I2C to send byte
//
RET_IF_ERR(I2CTransact(I2C_MASTER_CMD_BURST_SEND_CONT));
//
// Decrement the count and increment the data pointer
// to facilitate the next transfer
//
ucLen--;
pucData++;
}
//
// If stop bit is to be sent, send it.
//
if (ucStop == true) {
RET_IF_ERR(I2CTransact(I2C_MASTER_CMD_BURST_SEND_STOP));
}
return SUCCESS;
}
//****************************************************************************
//
//! Invokes the I2C driver APIs to read from the device. This assumes the
//! device local address to read from is set using the I2CWrite API.
//!
//! \param ucDevAddr is the 7-bit I2C slave address
//! \param pucData is the pointer to the read data to be placed
//! \param ucLen is the length of data to be read
//!
//! This function works in a polling mode,
//! 1. Writes the device register address to be written to.
//! 2. In a loop, reads all the bytes over I2C
//!
//! \return 0: Success, < 0: Failure.
//
//****************************************************************************
int I2C_IF_Read(unsigned char ucDevAddr, unsigned char *pucData,
unsigned char ucLen) {
unsigned long ulCmdID;
RETERR_IF_TRUE(pucData == NULL);
RETERR_IF_TRUE(ucLen == 0);
//
// Set I2C codec slave address
//
MAP_I2CMasterSlaveAddrSet(I2C_BASE, ucDevAddr, true);
//
// Check if its a single receive or burst receive
//
if (ucLen == 1) {
//
// Configure for a single receive
//
ulCmdID = I2C_MASTER_CMD_SINGLE_RECEIVE;
} else {
//
// Initiate a burst receive sequence
//
ulCmdID = I2C_MASTER_CMD_BURST_RECEIVE_START;
}
//
// Initiate the transfer.
//
RET_IF_ERR(I2CTransact(ulCmdID));
//
// Decrement the count and increment the data pointer
// to facilitate the next transfer
//
ucLen--;
//
// Loop until the completion of reception or error
//
while (ucLen) {
//
// Receive the byte over I2C
//
*pucData = MAP_I2CMasterDataGet(I2C_BASE);
//
// Decrement the count and increment the data pointer
// to facilitate the next transfer
//
ucLen--;
pucData++;
if (ucLen) {
//
// Continue the reception
//
RET_IF_ERR(I2CTransact(I2C_MASTER_CMD_BURST_RECEIVE_CONT));
} else {
//
// Complete the last reception
//
RET_IF_ERR(I2CTransact(I2C_MASTER_CMD_BURST_RECEIVE_FINISH));
}
}
//
// Receive the byte over I2C
//
*pucData = MAP_I2CMasterDataGet(I2C_BASE);
return SUCCESS;
}
//****************************************************************************
//
//! Invokes the I2C driver APIs to read from a specified address the device.
//! This assumes the device local address to be of 8-bit. For other
//! combinations use I2CWrite followed by I2CRead.
//!
//! \param ucDevAddr is the 7-bit I2C slave address
//! \param pucWrDataBuf is the pointer to the data to be written (reg addr)
//! \param ucWrLen is the length of data to be written
//! \param pucRdDataBuf is the pointer to the read data to be placed
//! \param ucRdLen is the length of data to be read
//!
//! This function works in a polling mode,
//! 1. Writes the data over I2C (device register address to be read from).
//! 2. In a loop, reads all the bytes over I2C
//!
//! \return 0: Success, < 0: Failure.
//
//****************************************************************************
int I2C_IF_ReadFrom(unsigned char ucDevAddr, unsigned char *pucWrDataBuf,
unsigned char ucWrLen, unsigned char *pucRdDataBuf,
unsigned char ucRdLen) {
//
// Write the register address to be read from.
// Stop bit implicitly assumed to be 0.
//
RET_IF_ERR(I2C_IF_Write(ucDevAddr, pucWrDataBuf, ucWrLen, 0));
//
// Read the specified length of data
//
RET_IF_ERR(I2C_IF_Read(ucDevAddr, pucRdDataBuf, ucRdLen));
return SUCCESS;
}
//****************************************************************************
//
//! Enables and configures the I2C peripheral
//!
//! \param ulMode is the mode configuration of I2C
//! The parameter \e ulMode is one of the following
//! - \b I2C_MASTER_MODE_STD for 100 Kbps standard mode.
//! - \b I2C_MASTER_MODE_FST for 400 Kbps fast mode.
//!
//! This function works in a polling mode,
//! 1. Powers ON the I2C peripheral.
//! 2. Configures the I2C peripheral
//!
//! \return 0: Success, < 0: Failure.
//
//****************************************************************************
int I2C_IF_Open(unsigned long ulMode) {
//
// Enable I2C Peripheral
//
//MAP_HwSemaphoreLock(HWSEM_I2C, HWSEM_WAIT_FOR_EVER);
MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, PRCM_RUN_MODE_CLK);
MAP_PRCMPeripheralReset(PRCM_I2CA0);
//
// Configure I2C module in the specified mode
//
switch (ulMode) {
case I2C_MASTER_MODE_STD: /* 100000 */
MAP_I2CMasterInitExpClk(I2C_BASE, SYS_CLK, false);
break;
case I2C_MASTER_MODE_FST: /* 400000 */
MAP_I2CMasterInitExpClk(I2C_BASE, SYS_CLK, true);
break;
default:
MAP_I2CMasterInitExpClk(I2C_BASE, SYS_CLK, true);
break;
}
//
// Disables the multi-master mode
//
//MAP_I2CMasterDisable(I2C_BASE);
return SUCCESS;
}
//****************************************************************************
//
//! Disables the I2C peripheral
//!
//! \param None
//!
//! This function works in a polling mode,
//! 1. Powers OFF the I2C peripheral.
//!
//! \return 0: Success, < 0: Failure.
//
//****************************************************************************
int I2C_IF_Close() {
//
// Power OFF the I2C peripheral
//
MAP_PRCMPeripheralClkDisable(PRCM_I2CA0, PRCM_RUN_MODE_CLK);
return SUCCESS;
}