LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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, 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 "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 #define SLAVE_ACTIVE(iic) (((iic)->flags & 0xFF00) != 0)
38 
39 /* I2C common interface structure */
40 struct i2c_interface {
41  LPC_I2C_T *ip; /* IP base address of the I2C device */
42  CHIP_CCU_CLK_T clk; /* Clock used by I2C */
43  I2C_EVENTHANDLER_T mEvent; /* Current active Master event handler */
44  I2C_EVENTHANDLER_T sEvent; /* Slave transfer events */
45  I2C_XFER_T *mXfer; /* Current active xfer pointer */
46  I2C_XFER_T *sXfer; /* Pointer to store xfer when bus is busy */
47  uint32_t flags; /* Flags used by I2C master and slave */
48 };
49 
50 /* Slave interface structure */
51 struct i2c_slave_interface {
54 };
55 
56 /*****************************************************************************
57  * Public types/enumerations/variables
58  ****************************************************************************/
59 /* I2C interfaces */
63 };
64 
66 
67 /*****************************************************************************
68  * Private functions
69  ****************************************************************************/
70 
71 /*****************************************************************************
72  * Public functions
73  ****************************************************************************/
74 /* Chip event handler interrupt based */
76 {
77  struct i2c_interface *iic = &i2c[id];
78  volatile I2C_STATUS_T *stat;
79 
80  /* Only WAIT event needs to be handled */
81  if (event != I2C_EVENT_WAIT) {
82  return;
83  }
84 
85  stat = &iic->mXfer->status;
86  /* Wait for the status to change */
87  while (*stat == I2C_STATUS_BUSY) {}
88 }
89 
90 /* Chip polling event handler */
92 {
93  struct i2c_interface *iic = &i2c[id];
94  volatile I2C_STATUS_T *stat;
95 
96  /* Only WAIT event needs to be handled */
97  if (event != I2C_EVENT_WAIT) {
98  return;
99  }
100 
101  stat = &iic->mXfer->status;
102  /* Call the state change handler till xfer is done */
103  while (*stat == I2C_STATUS_BUSY) {
104  if (IP_I2C_IsStateChanged(iic->ip)) {
106  }
107  }
108 }
109 
110 /* Initializes the LPC_I2C peripheral with specified parameter */
112 {
113  /* Enable I2C Clocking */
114  Chip_Clock_Enable(i2c[id].clk);
115 
116  IP_I2C_Init(i2c[id].ip);
117 }
118 
119 /* De-initializes the I2C peripheral registers to their default reset values */
121 {
122  IP_I2C_DeInit(i2c[id].ip);
123 
124  /* Disable I2C clocking */
125  Chip_Clock_Disable(i2c[id].clk);
126 }
127 
128 /* Set up clock rate for LPC_I2C peripheral */
130 {
131  IP_I2C_SetClockRate(i2c[id].ip, Chip_Clock_GetRate(i2c[id].clk) / clockrate);
132 }
133 
134 /* Get current clock rate for LPC_I2C peripheral */
136 {
137  return Chip_Clock_GetRate(i2c[id].clk) / IP_I2C_GetClockDiv(i2c[id].ip);
138 }
139 
140 /* Set the master event handler */
142 {
143  struct i2c_interface *iic = &i2c[id];
144  if (!iic->mXfer) {
145  iic->mEvent = event;
146  }
147  return iic->mEvent == event;
148 }
149 
150 /* Get the master event handler */
152 {
153  return i2c[id].mEvent;
154 }
155 
156 /* Transmit and Receive data in master mode */
158 {
159  struct i2c_interface *iic = &i2c[id];
160 
161  iic->mEvent(id, I2C_EVENT_LOCK);
162  xfer->status = I2C_STATUS_BUSY;
163  iic->mXfer = xfer;
164 
165  /* If slave xfer not in progress */
166  if (!iic->sXfer) {
168  }
169 
170  iic->mEvent(id, I2C_EVENT_WAIT);
171  iic->mXfer = 0;
172 
173  /* Wait for stop condition to appear on bus */
174  while (!IP_I2C_BusFree(iic->ip)) {}
175 
176  /* Start slave if one is active */
177  if (SLAVE_ACTIVE(iic)) {
179  }
180 
181  iic->mEvent(id, I2C_EVENT_UNLOCK);
182 
183  return xfer->status;
184 }
185 
186 /* Master tx only */
187 int Chip_I2C_MasterSend(I2C_ID_T id, uint8_t slaveAddr, const uint8_t *buff, uint8_t len)
188 {
189  I2C_XFER_T xfer = {0};
190  xfer.slaveAddr = slaveAddr;
191  xfer.txBuff = buff;
192  xfer.txSz = len;
193  while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
194  return len - xfer.txSz;
195 }
196 
197 /* Transmit one byte and receive an array of bytes after a repeated start condition is generated in Master mode.
198  * This function is useful for communicating with the I2C slave registers
199  */
200 int Chip_I2C_MasterCmdRead(I2C_ID_T id, uint8_t slaveAddr, uint8_t cmd, uint8_t *buff, int len)
201 {
202  I2C_XFER_T xfer = {0};
203  xfer.slaveAddr = slaveAddr;
204  xfer.txBuff = &cmd;
205  xfer.txSz = 1;
206  xfer.rxBuff = buff;
207  xfer.rxSz = len;
208  while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
209  return len - xfer.rxSz;
210 }
211 
212 /* Sequential master read */
213 int Chip_I2C_MasterRead(I2C_ID_T id, uint8_t slaveAddr, uint8_t *buff, int len)
214 {
215  I2C_XFER_T xfer = {0};
216  xfer.slaveAddr = slaveAddr;
217  xfer.rxBuff = buff;
218  xfer.rxSz = len;
219  while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
220  return len - xfer.rxSz;
221 }
222 
223 /* Check if master state is active */
225 {
226  return IP_I2C_IsMasterState(i2c[id].ip);
227 }
228 
229 /* State change handler for master transfer */
231 {
232  if (!IP_I2C_MasterXfer_StateHandler(i2c[id].ip, i2c[id].mXfer)) {
233  i2c[id].mEvent(id, I2C_EVENT_DONE);
234  }
235 }
236 
237 /* Setup slave function */
239  I2C_SLAVE_ID sid,
240  I2C_XFER_T *xfer,
242  uint8_t addrMask)
243 {
244  struct i2c_interface *iic = &i2c[id];
245  struct i2c_slave_interface *si2c = &i2c_slave[id][sid];
246  si2c->xfer = xfer;
247  si2c->event = event;
248 
249  /* Set up the slave address */
250  if (sid != I2C_SLAVE_GENERAL) {
251  IP_I2C_SetSlaveAddress(iic->ip, sid, xfer->slaveAddr, addrMask);
252  }
253 
254  if (!SLAVE_ACTIVE(iic) && !iic->mXfer) {
256  }
257  iic->flags |= 1 << (sid + 8);
258 }
259 
260 /* I2C Slave event handler */
262 {
263  int ret;
264  struct i2c_interface *iic = &i2c[id];
265 
266  /* Get the currently addressed slave */
267  if (!iic->sXfer) {
268  struct i2c_slave_interface *si2c;
269 
271  si2c = &i2c_slave[id][sid];
272  iic->sXfer = si2c->xfer;
273  iic->sEvent = si2c->event;
274  }
275 
276  iic->sXfer->slaveAddr |= iic->mXfer != 0;
277  ret = IP_I2C_SlaveXfer_StateHandler(iic->ip, iic->sXfer);
278  if (ret) {
279  if (iic->sXfer->status == I2C_STATUS_DONE) {
280  iic->sXfer = 0;
281  }
282  iic->sEvent(id, (I2C_EVENT_T) ret);
283  }
284 }
285 
286 /* Disable I2C device */
288 {
289  IP_I2C_Disable(i2c[id].ip);
290 }
291 
292 /* State change checking */
294 {
295  return IP_I2C_IsStateChanged(i2c[id].ip);
296 }