LPCOpen Platform for LPC18XX/43XX microcontrollers: C:/w/lpcopen_docs/software/lpc_core/lpc_chip/chip_18xx_43xx/i2c_18xx_43xx.c Source File

| LPCOpen Platform for LPC18XX/43XX microcontrollers 18XX43XX LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

i2c_18xx_43xx.c
Go to the documentation of this file.
1 /*
2 * @brief LPC18xx/43xx I2C driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2013
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licensor disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31
32 #include "chip.h"
33
34 /*****************************************************************************
35 * Private types/enumerations/variables
36 ****************************************************************************/
37
38 /* Control flags */
39 #define I2C_CON_FLAGS (I2C_CON_AA | I2C_CON_SI | I2C_CON_STO | I2C_CON_STA)
40 #define LPC_I2Cx(id) ((i2c[id].ip))
41 #define SLAVE_ACTIVE(iic) (((iic)->flags & 0xFF00) != 0)
42
43 /* I2C common interface structure */
44 struct i2c_interface {
45 LPC_I2C_T *ip; /* IP base address of the I2C device */
46 CHIP_CCU_CLK_T clk; /* Clock used by I2C */
47 I2C_EVENTHANDLER_T mEvent; /* Current active Master event handler */
48 I2C_EVENTHANDLER_T sEvent; /* Slave transfer events */
49 I2C_XFER_T *mXfer; /* Current active xfer pointer */
50 I2C_XFER_T *sXfer; /* Pointer to store xfer when bus is busy */
51 uint32_t flags; /* Flags used by I2C master and slave */
52 };
53
54 /* Slave interface structure */
55 struct i2c_slave_interface {
56 I2C_XFER_T *xfer;
57 I2C_EVENTHANDLER_T event;
58 };
59
60 /* I2C interfaces */
61 static struct i2c_interface i2c[I2C_NUM_INTERFACE] = {
62 {LPC_I2C0, CLK_APB1_I2C0, Chip_I2C_EventHandler, NULL, NULL, NULL, 0},
63 {LPC_I2C1, CLK_APB3_I2C1, Chip_I2C_EventHandler, NULL, NULL, NULL, 0}
64 };
65
66 static struct i2c_slave_interface i2c_slave[I2C_NUM_INTERFACE][I2C_SLAVE_NUM_INTERFACE];
67
68 /*****************************************************************************
69 * Public types/enumerations/variables
70 ****************************************************************************/
71
72 /*****************************************************************************
73 * Private functions
74 ****************************************************************************/
75
76 STATIC INLINE void enableClk(I2C_ID_T id)
77 {
78 Chip_Clock_Enable(i2c[id].clk);
79 }
80
81 STATIC INLINE void disableClk(I2C_ID_T id)
82 {
83 Chip_Clock_Disable(i2c[id].clk);
84 }
85
86 /* Get the ADC Clock Rate */
87 STATIC INLINE uint32_t getClkRate(I2C_ID_T id)
88 {
89 return Chip_Clock_GetRate(i2c[id].clk);
90 }
91
92 /* Enable I2C and start master transfer */
93 STATIC INLINE void startMasterXfer(LPC_I2C_T *pI2C)
94 {
95 /* Reset STA, STO, SI */
96 pI2C->CONCLR = I2C_CON_SI | I2C_CON_STA | I2C_CON_AA;
97
98 /* Enter to Master Transmitter mode */
99 pI2C->CONSET = I2C_CON_I2EN | I2C_CON_STA;
100 }
101
102 /* Enable I2C and enable slave transfers */
103 STATIC INLINE void startSlaverXfer(LPC_I2C_T *pI2C)
104 {
105 /* Reset STA, STO, SI */
106 pI2C->CONCLR = I2C_CON_SI | I2C_CON_STA;
107
108 /* Enter to Master Transmitter mode */
109 pI2C->CONSET = I2C_CON_I2EN | I2C_CON_AA;
110 }
111
112 /* Check if I2C bus is free */
113 STATIC INLINE int isI2CBusFree(LPC_I2C_T *pI2C)
114 {
115 return !(pI2C->CONSET & I2C_CON_STO);
116 }
117
118 /* Get current state of the I2C peripheral */
119 STATIC INLINE int getCurState(LPC_I2C_T *pI2C)
120 {
121 return (int) (pI2C->STAT & I2C_STAT_CODE_BITMASK);
122 }
123
124 /* Check if the active state belongs to master mode*/
125 STATIC INLINE int isMasterState(LPC_I2C_T *pI2C)
126 {
127 return getCurState(pI2C) < 0x60;
128 }
129
130 /* Set OWN slave address for specific slave ID */
131 STATIC void setSlaveAddr(LPC_I2C_T *pI2C, I2C_SLAVE_ID sid, uint8_t addr, uint8_t mask)
132 {
133 uint32_t index = (uint32_t) sid - 1;
134 pI2C->MASK[index] = mask;
135 if (sid == I2C_SLAVE_0) {
136 pI2C->ADR0 = addr;
137 }
138 else {
139 volatile uint32_t *abase = &pI2C->ADR1;
140 abase[index - 1] = addr;
141 }
142 }
143
144 /* Match the slave address */
145 STATIC int isSlaveAddrMatching(uint8_t addr1, uint8_t addr2, uint8_t mask)
146 {
147 mask |= 1;
148 return (addr1 & ~mask) == (addr2 & ~mask);
149 }
150
151 /* Get the index of the active slave */
152 STATIC I2C_SLAVE_ID lookupSlaveIndex(LPC_I2C_T *pI2C, uint8_t slaveAddr)
153 {
154 if (!(slaveAddr >> 1)) {
155 return I2C_SLAVE_GENERAL; /* General call address */
156 }
157 if (isSlaveAddrMatching(pI2C->ADR0, slaveAddr, pI2C->MASK[0])) {
158 return I2C_SLAVE_0;
159 }
160 if (isSlaveAddrMatching(pI2C->ADR1, slaveAddr, pI2C->MASK[1])) {
161 return I2C_SLAVE_1;
162 }
163 if (isSlaveAddrMatching(pI2C->ADR2, slaveAddr, pI2C->MASK[2])) {
164 return I2C_SLAVE_2;
165 }
166 if (isSlaveAddrMatching(pI2C->ADR3, slaveAddr, pI2C->MASK[3])) {
167 return I2C_SLAVE_3;
168 }
169
170 /* If everything is fine the code should never come here */
171 return I2C_SLAVE_GENERAL;
172 }
173
174 /* Master transfer state change handler handler */
175 int handleMasterXferState(LPC_I2C_T *pI2C, I2C_XFER_T *xfer)
176 {
177 uint32_t cclr = I2C_CON_FLAGS;
178
179 switch (getCurState(pI2C)) {
180 case 0x08: /* Start condition on bus */
181 case 0x10: /* Repeated start condition */
182 pI2C->DAT = (xfer->slaveAddr << 1) | (xfer->txSz == 0);
183 break;
184
185 /* Tx handling */
186 case 0x18: /* SLA+W sent and ACK received */
187 case 0x28: /* DATA sent and ACK received */
188 if (!xfer->txSz) {
189 cclr &= ~(xfer->rxSz ? I2C_CON_STA : I2C_CON_STO);
190 }
191 else {
192 pI2C->DAT = *xfer->txBuff++;
193 xfer->txSz--;
194 }
195 break;
196
197 /* Rx handling */
198 case 0x58: /* Data Received and NACK sent */
199 cclr &= ~I2C_CON_STO;
200
201 case 0x50: /* Data Received and ACK sent */
202 *xfer->rxBuff++ = pI2C->DAT;
203 xfer->rxSz--;
204
205 case 0x40: /* SLA+R sent and ACK received */
206 if (xfer->rxSz > 1) {
207 cclr &= ~I2C_CON_AA;
208 }
209 break;
210
211 /* NAK Handling */
212 case 0x20: /* SLA+W sent NAK received */
213 case 0x48: /* SLA+R sent NAK received */
214 xfer->status = I2C_STATUS_SLAVENAK;
215 cclr &= ~I2C_CON_STO;
216 break;
217
218 case 0x30: /* DATA sent NAK received */
219 xfer->status = I2C_STATUS_NAK;
220 cclr &= ~I2C_CON_STO;
221 break;
222
223 case 0x38: /* Arbitration lost */
224 xfer->status = I2C_STATUS_ARBLOST;
225 break;
226
227 /* Bus Error */
228 case 0x00:
229 xfer->status = I2C_STATUS_BUSERR;
230 cclr &= ~I2C_CON_STO;
231 }
232
233 /* Set clear control flags */
234 pI2C->CONSET = cclr ^ I2C_CON_FLAGS;
235 pI2C->CONCLR = cclr & ~I2C_CON_STO;
236
237 /* If stopped return 0 */
238 if (!(cclr & I2C_CON_STO) || (xfer->status == I2C_STATUS_ARBLOST)) {
239 if (xfer->status == I2C_STATUS_BUSY) {
240 xfer->status = I2C_STATUS_DONE;
241 }
242 return 0;
243 }
244 return 1;
245 }
246
247 /* Find the slave address of SLA+W or SLA+R */
248 I2C_SLAVE_ID getSlaveIndex(LPC_I2C_T *pI2C)
249 {
250 switch (getCurState(pI2C)) {
251 case 0x60:
252 case 0x68:
253 case 0x70:
254 case 0x78:
255 case 0xA8:
256 case 0xB0:
257 return lookupSlaveIndex(pI2C, pI2C->DAT);
258 }
259
260 /* If everything is fine code should never come here */
261 return I2C_SLAVE_GENERAL;
262 }
263
264 /* Slave state machine handler */
265 int handleSlaveXferState(LPC_I2C_T *pI2C, I2C_XFER_T *xfer)
266 {
267 uint32_t cclr = I2C_CON_FLAGS;
268 int ret = RET_SLAVE_BUSY;
269
270 xfer->status = I2C_STATUS_BUSY;
271 switch (getCurState(pI2C)) {
272 case 0x80: /* SLA: Data received + ACK sent */
273 case 0x90: /* GC: Data received + ACK sent */
274 *xfer->rxBuff++ = pI2C->DAT;
275 xfer->rxSz--;
276 ret = RET_SLAVE_RX;
277 if (xfer->rxSz > 1) {
278 cclr &= ~I2C_CON_AA;
279 }
280 break;
281
282 case 0x60: /* Own SLA+W received */
283 case 0x68: /* Own SLA+W received after losing arbitration */
284 case 0x70: /* GC+W received */
285 case 0x78: /* GC+W received after losing arbitration */
286 xfer->slaveAddr = pI2C->DAT & ~1;
287 if (xfer->rxSz > 1) {
288 cclr &= ~I2C_CON_AA;
289 }
290 break;
291
292 case 0xA8: /* SLA+R received */
293 case 0xB0: /* SLA+R received after losing arbitration */
294 xfer->slaveAddr = pI2C->DAT & ~1;
295
296 case 0xB8: /* DATA sent and ACK received */
297 pI2C->DAT = *xfer->txBuff++;
298 xfer->txSz--;
299 if (xfer->txSz > 0) {
300 cclr &= ~I2C_CON_AA;
301 }
302 ret = RET_SLAVE_TX;
303 break;
304
305 case 0xC0: /* Data transmitted and NAK received */
306 case 0xC8: /* Last data transmitted and ACK received */
307 case 0x88: /* SLA: Data received + NAK sent */
308 case 0x98: /* GC: Data received + NAK sent */
309 case 0xA0: /* STOP/Repeated START condition received */
310 ret = RET_SLAVE_IDLE;
311 cclr &= ~I2C_CON_AA;
312 xfer->status = I2C_STATUS_DONE;
313 if (xfer->slaveAddr & 1) {
314 cclr &= ~I2C_CON_STA;
315 }
316 break;
317 }
318
319 /* Set clear control flags */
320 pI2C->CONSET = cclr ^ I2C_CON_FLAGS;
321 pI2C->CONCLR = cclr & ~I2C_CON_STO;
322
323 return ret;
324 }
325
326 /*****************************************************************************
327 * Public functions
328 ****************************************************************************/
329 /* Chip event handler interrupt based */
330 void Chip_I2C_EventHandler(I2C_ID_T id, I2C_EVENT_T event)
331 {
332 struct i2c_interface *iic = &i2c[id];
333 volatile I2C_STATUS_T *stat;
334
335 /* Only WAIT event needs to be handled */
336 if (event != I2C_EVENT_WAIT) {
337 return;
338 }
339
340 stat = &iic->mXfer->status;
341 /* Wait for the status to change */
342 while (*stat == I2C_STATUS_BUSY) {}
343 }
344
345 /* Chip polling event handler */
346 void Chip_I2C_EventHandlerPolling(I2C_ID_T id, I2C_EVENT_T event)
347 {
348 struct i2c_interface *iic = &i2c[id];
349 volatile I2C_STATUS_T *stat;
350
351 /* Only WAIT event needs to be handled */
352 if (event != I2C_EVENT_WAIT) {
353 return;
354 }
355
356 stat = &iic->mXfer->status;
357 /* Call the state change handler till xfer is done */
358 while (*stat == I2C_STATUS_BUSY) {
359 if (Chip_I2C_IsStateChanged(id)) {
360 Chip_I2C_MasterStateHandler(id);
361 }
362 }
363 }
364
365 /* Initializes the LPC_I2C peripheral with specified parameter */
366 void Chip_I2C_Init(I2C_ID_T id)
367 {
368 enableClk(id);
369
370 /* Set I2C operation to default */
371 LPC_I2Cx(id)->CONCLR = (I2C_CON_AA | I2C_CON_SI | I2C_CON_STA | I2C_CON_I2EN);
372 }
373
374 /* De-initializes the I2C peripheral registers to their default reset values */
375 void Chip_I2C_DeInit(I2C_ID_T id)
376 {
377 /* Disable I2C control */
378 LPC_I2Cx(id)->CONCLR = I2C_CON_I2EN | I2C_CON_SI | I2C_CON_STA | I2C_CON_AA;
379
380 disableClk(id);
381 }
382
383 /* Set up clock rate for LPC_I2C peripheral */
384 void Chip_I2C_SetClockRate(I2C_ID_T id, uint32_t clockrate)
385 {
386 uint32_t SCLValue;
387
388 SCLValue = (getClkRate(id) / clockrate);
389 LPC_I2Cx(id)->SCLH = (uint32_t) (SCLValue >> 1);
390 LPC_I2Cx(id)->SCLL = (uint32_t) (SCLValue - LPC_I2Cx(id)->SCLH);
391 }
392
393 /* Get current clock rate for LPC_I2C peripheral */
394 uint32_t Chip_I2C_GetClockRate(I2C_ID_T id)
395 {
396 return getClkRate(id) / (LPC_I2Cx(id)->SCLH + LPC_I2Cx(id)->SCLL);
397 }
398
399 /* Set the master event handler */
400 int Chip_I2C_SetMasterEventHandler(I2C_ID_T id, I2C_EVENTHANDLER_T event)
401 {
402 struct i2c_interface *iic = &i2c[id];
403 if (!iic->mXfer) {
404 iic->mEvent = event;
405 }
406 return iic->mEvent == event;
407 }
408
409 /* Get the master event handler */
410 I2C_EVENTHANDLER_T Chip_I2C_GetMasterEventHandler(I2C_ID_T id)
411 {
412 return i2c[id].mEvent;
413 }
414
415 /* Transmit and Receive data in master mode */
416 int Chip_I2C_MasterTransfer(I2C_ID_T id, I2C_XFER_T *xfer)
417 {
418 struct i2c_interface *iic = &i2c[id];
419
420 iic->mEvent(id, I2C_EVENT_LOCK);
421 xfer->status = I2C_STATUS_BUSY;
422 iic->mXfer = xfer;
423
424 /* If slave xfer not in progress */
425 if (!iic->sXfer) {
426 startMasterXfer(iic->ip);
427 }
428 iic->mEvent(id, I2C_EVENT_WAIT);
429 iic->mXfer = 0;
430
431 /* Wait for stop condition to appear on bus */
432 while (!isI2CBusFree(iic->ip)) {}
433
434 /* Start slave if one is active */
435 if (SLAVE_ACTIVE(iic)) {
436 startSlaverXfer(iic->ip);
437 }
438
439 iic->mEvent(id, I2C_EVENT_UNLOCK);
440 return (int) xfer->status;
441 }
442
443 /* Master tx only */
444 int Chip_I2C_MasterSend(I2C_ID_T id, uint8_t slaveAddr, const uint8_t *buff, uint8_t len)
445 {
446 I2C_XFER_T xfer = {0};
447 xfer.slaveAddr = slaveAddr;
448 xfer.txBuff = buff;
449 xfer.txSz = len;
450 while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
451 return len - xfer.txSz;
452 }
453
454 /* Transmit one byte and receive an array of bytes after a repeated start condition is generated in Master mode.
455 * This function is useful for communicating with the I2C slave registers
456 */
457 int Chip_I2C_MasterCmdRead(I2C_ID_T id, uint8_t slaveAddr, uint8_t cmd, uint8_t *buff, int len)
458 {
459 I2C_XFER_T xfer = {0};
460 xfer.slaveAddr = slaveAddr;
461 xfer.txBuff = &cmd;
462 xfer.txSz = 1;
463 xfer.rxBuff = buff;
464 xfer.rxSz = len;
465 while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
466 return len - xfer.rxSz;
467 }
468
469 /* Sequential master read */
470 int Chip_I2C_MasterRead(I2C_ID_T id, uint8_t slaveAddr, uint8_t *buff, int len)
471 {
472 I2C_XFER_T xfer = {0};
473 xfer.slaveAddr = slaveAddr;
474 xfer.rxBuff = buff;
475 xfer.rxSz = len;
476 while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
477 return len - xfer.rxSz;
478 }
479
480 /* Check if master state is active */
481 int Chip_I2C_IsMasterActive(I2C_ID_T id)
482 {
483 return isMasterState(i2c[id].ip);
484 }
485
486 /* State change handler for master transfer */
487 void Chip_I2C_MasterStateHandler(I2C_ID_T id)
488 {
489 if (!handleMasterXferState(i2c[id].ip, i2c[id].mXfer)) {
490 i2c[id].mEvent(id, I2C_EVENT_DONE);
491 }
492 }
493
494 /* Setup slave function */
495 void Chip_I2C_SlaveSetup(I2C_ID_T id,
496 I2C_SLAVE_ID sid,
497 I2C_XFER_T *xfer,
498 I2C_EVENTHANDLER_T event,
499 uint8_t addrMask)
500 {
501 struct i2c_interface *iic = &i2c[id];
502 struct i2c_slave_interface *si2c = &i2c_slave[id][sid];
503 si2c->xfer = xfer;
504 si2c->event = event;
505
506 /* Set up the slave address */
507 if (sid != I2C_SLAVE_GENERAL) {
508 setSlaveAddr(iic->ip, sid, xfer->slaveAddr, addrMask);
509 }
510
511 if (!SLAVE_ACTIVE(iic) && !iic->mXfer) {
512 startSlaverXfer(iic->ip);
513 }
514 iic->flags |= 1 << (sid + 8);
515 }
516
517 /* I2C Slave event handler */
518 void Chip_I2C_SlaveStateHandler(I2C_ID_T id)
519 {
520 int ret;
521 struct i2c_interface *iic = &i2c[id];
522
523 /* Get the currently addressed slave */
524 if (!iic->sXfer) {
525 struct i2c_slave_interface *si2c;
526
527 I2C_SLAVE_ID sid = getSlaveIndex(iic->ip);
528 si2c = &i2c_slave[id][sid];
529 iic->sXfer = si2c->xfer;
530 iic->sEvent = si2c->event;
531 }
532
533 iic->sXfer->slaveAddr |= iic->mXfer != 0;
534 ret = handleSlaveXferState(iic->ip, iic->sXfer);
535 if (ret) {
536 if (iic->sXfer->status == I2C_STATUS_DONE) {
537 iic->sXfer = 0;
538 }
539 iic->sEvent(id, (I2C_EVENT_T) ret);
540 }
541 }
542
543 /* Disable I2C device */
544 void Chip_I2C_Disable(I2C_ID_T id)
545 {
546 LPC_I2Cx(id)->CONCLR = I2C_I2CONCLR_I2ENC;
547 }
548
549 /* State change checking */
550 int Chip_I2C_IsStateChanged(I2C_ID_T id)
551 {
552 return (LPC_I2Cx(id)->CONSET & I2C_CON_SI) != 0;
553 }
554