LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i2c_001.c
Go to the documentation of this file.
1 /*
2  * @brief I2C driver functions
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
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 "i2c_001.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 
41 /*****************************************************************************
42  * Public types/enumerations/variables
43  ****************************************************************************/
44 
45 /*****************************************************************************
46  * Private functions
47  ****************************************************************************/
48 /* Match the slave address */
49 static int IP_I2C_SlaveMatchAddr(uint8_t addr1, uint8_t addr2, uint8_t mask)
50 {
51  mask |= 1;
52  return (addr1 & ~mask) == (addr2 & ~mask);
53 }
54 
55 /* Get the index of the active slave */
56 static I2C_SLAVE_ID IP_I2C_SlaveIndexLookup(IP_I2C_001_T *pI2C, uint8_t slaveAddr)
57 {
58  if (!(slaveAddr >> 1)) {
59  return I2C_SLAVE_GENERAL; /* General call address */
60  }
61  if (IP_I2C_SlaveMatchAddr(pI2C->ADR0, slaveAddr, pI2C->MASK[0])) {
62  return I2C_SLAVE_0;
63  }
64  if (IP_I2C_SlaveMatchAddr(pI2C->ADR1, slaveAddr, pI2C->MASK[1])) {
65  return I2C_SLAVE_1;
66  }
67  if (IP_I2C_SlaveMatchAddr(pI2C->ADR2, slaveAddr, pI2C->MASK[2])) {
68  return I2C_SLAVE_2;
69  }
70  if (IP_I2C_SlaveMatchAddr(pI2C->ADR3, slaveAddr, pI2C->MASK[3])) {
71  return I2C_SLAVE_3;
72  }
73 
74  /* If everything is fine the code should never come here */
75  return I2C_SLAVE_GENERAL;
76 }
77 
78 /*****************************************************************************
79  * Public functions
80  ****************************************************************************/
81 /* Master transfer state change handler handler */
83 {
84  uint32_t cclr = I2C_CON_FLAGS;
85 
86  switch (IP_I2C_GetCurrentState(pI2C)) {
87  case 0x08: /* Start condition on bus */
88  case 0x10: /* Repeated start condition */
89  pI2C->DAT = (xfer->slaveAddr << 1) | (xfer->txSz == 0);
90  break;
91 
92  /* Tx handling */
93  case 0x18: /* SLA+W sent and ACK received */
94  case 0x28: /* DATA sent and ACK received */
95  if (!xfer->txSz) {
96  cclr &= ~(xfer->rxSz ? I2C_CON_STA : I2C_CON_STO);
97  }
98  else {
99  pI2C->DAT = *xfer->txBuff++;
100  xfer->txSz--;
101  }
102  break;
103 
104  /* Rx handling */
105  case 0x58: /* Data Received and NACK sent */
106  cclr &= ~I2C_CON_STO;
107 
108  case 0x50: /* Data Received and ACK sent */
109  *xfer->rxBuff++ = pI2C->DAT;
110  xfer->rxSz--;
111 
112  case 0x40: /* SLA+R sent and ACK received */
113  if (xfer->rxSz > 1) {
114  cclr &= ~I2C_CON_AA;
115  }
116  break;
117 
118  /* NAK Handling */
119  case 0x20: /* SLA+W sent NAK received */
120  case 0x30: /* DATA sent NAK received */
121  case 0x48: /* SLA+R sent NAK received */
122  xfer->status = I2C_STATUS_NAK;
123  cclr &= ~I2C_CON_STO;
124  break;
125 
126  case 0x38: /* Arbitration lost */
127  xfer->status = I2C_STATUS_ARBLOST;
128  break;
129 
130  /* Bus Error */
131  case 0x00:
132  xfer->status = I2C_STATUS_BUSERR;
133  cclr &= ~I2C_CON_STO;
134  }
135 
136  /* Set clear control flags */
137  pI2C->CONSET = cclr ^ I2C_CON_FLAGS;
138  pI2C->CONCLR = cclr;
139 
140  /* If stopped return 0 */
141  if (!(cclr & I2C_CON_STO) || (xfer->status == I2C_STATUS_ARBLOST)) {
142  if (xfer->status == I2C_STATUS_BUSY) {
143  xfer->status = I2C_STATUS_DONE;
144  }
145  return 0;
146  }
147  return 1;
148 }
149 
150 /* Find the slave address of SLA+W or SLA+R */
152 {
153  switch (IP_I2C_GetCurrentState(pI2C)) {
154  case 0x60:
155  case 0x68:
156  case 0x70:
157  case 0x78:
158  case 0xA8:
159  case 0xB0:
160  return IP_I2C_SlaveIndexLookup(pI2C, pI2C->DAT);
161  }
162 
163  /* If everything is fine code should never come here */
164  return I2C_SLAVE_GENERAL;
165 }
166 
167 /* Slave state machine handler */
169 {
170  uint32_t cclr = I2C_CON_FLAGS;
171  int ret = RET_SLAVE_BUSY;
172 
173  xfer->status = I2C_STATUS_BUSY;
174  switch (IP_I2C_GetCurrentState(pI2C)) {
175  case 0x80: /* SLA: Data received + ACK sent */
176  case 0x90: /* GC: Data received + ACK sent */
177  *xfer->rxBuff++ = pI2C->DAT;
178  xfer->rxSz--;
179  ret = RET_SLAVE_RX;
180  if (xfer->rxSz > 1) {
181  cclr &= ~I2C_CON_AA;
182  }
183  break;
184 
185  case 0x60: /* Own SLA+W received */
186  case 0x68: /* Own SLA+W received after losing arbitration */
187  case 0x70: /* GC+W received */
188  case 0x78: /* GC+W received after losing arbitration */
189  xfer->slaveAddr = pI2C->DAT & ~1;
190  if (xfer->rxSz > 1) {
191  cclr &= ~I2C_CON_AA;
192  }
193  break;
194 
195  case 0xA8: /* SLA+R received */
196  case 0xB0: /* SLA+R received after losing arbitration */
197  xfer->slaveAddr = pI2C->DAT & ~1;
198 
199  case 0xB8: /* DATA sent and ACK received */
200  pI2C->DAT = *xfer->txBuff++;
201  xfer->txSz--;
202  if (xfer->txSz > 0) {
203  cclr &= ~I2C_CON_AA;
204  }
205  ret = RET_SLAVE_TX;
206  break;
207 
208  case 0xC0: /* Data transmitted and NAK received */
209  case 0xC8: /* Last data transmitted and ACK received */
210  case 0x88: /* SLA: Data received + NAK sent */
211  case 0x98: /* GC: Data received + NAK sent */
212  case 0xA0: /* STOP/Repeated START condition received */
213  ret = RET_SLAVE_IDLE;
214  cclr &= ~I2C_CON_AA;
215  xfer->status = I2C_STATUS_DONE;
216  if (xfer->slaveAddr & 1) {
217  cclr &= ~I2C_CON_STA;
218  }
219  break;
220  }
221 
222  /* Set clear control flags */
223  pI2C->CONSET = cclr ^ I2C_CON_FLAGS;
224  pI2C->CONCLR = cclr;
225 
226  return ret;
227 }