LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i2c_17xx_40xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC17xx/40xx 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 #ifdef CHIP_LPC175X_6X
40 static const CHIP_SYSCTL_PCLK_T I2C_PeriphClk[I2C_NUM_INTERFACE] = {
41  SYSCTL_PCLK_I2C0,
42  SYSCTL_PCLK_I2C1,
43  SYSCTL_PCLK_I2C2
44 };
45 #define I2C_GetClk(x) Chip_Clock_GetPeripheralClockRate(I2C_PeriphClk[x])
46 #else
47 #define I2C_GetClk(x) Chip_Clock_GetPeripheralClockRate()
48 #endif
49 
50 /* I2C common interface structure */
51 struct i2c_interface {
52  LPC_I2C_T *ip; /* IP base address of the I2C device */
53  CHIP_SYSCTL_CLOCK_T clk; /* Clock used by I2C */
54  I2C_EVENTHANDLER_T mEvent; /* Current active Master event handler */
55  I2C_EVENTHANDLER_T sEvent; /* Slave transfer events */
56  I2C_XFER_T *mXfer; /* Current active xfer pointer */
57  I2C_XFER_T *sXfer; /* Pointer to store xfer when bus is busy */
58  uint32_t flags; /* Flags used by I2C master and slave */
59 };
60 
61 /* Slave interface structure */
62 struct i2c_slave_interface {
65 };
66 
67 /* I2C interfaces */
72 };
73 
75 
76 /*****************************************************************************
77  * Public types/enumerations/variables
78  ****************************************************************************/
79 
80 /*****************************************************************************
81  * Private functions
82  ****************************************************************************/
83 
84 /*****************************************************************************
85  * Public functions
86  ****************************************************************************/
87 /* Chip event handler interrupt based */
89 {
90  struct i2c_interface *iic = &i2c[id];
91  volatile I2C_STATUS_T *stat;
92 
93  /* Only WAIT event needs to be handled */
94  if (event != I2C_EVENT_WAIT) {
95  return;
96  }
97 
98  stat = &iic->mXfer->status;
99  /* Wait for the status to change */
100  while (*stat == I2C_STATUS_BUSY) {}
101 }
102 
103 /* Chip polling event handler */
105 {
106  struct i2c_interface *iic = &i2c[id];
107  volatile I2C_STATUS_T *stat;
108 
109  /* Only WAIT event needs to be handled */
110  if (event != I2C_EVENT_WAIT) {
111  return;
112  }
113 
114  stat = &iic->mXfer->status;
115  /* Call the state change handler till xfer is done */
116  while (*stat == I2C_STATUS_BUSY) {
117  if (IP_I2C_IsStateChanged(iic->ip)) {
119  }
120  }
121 }
122 
123 /* Initializes the LPC_I2C peripheral with specified parameter */
125 {
126  /* Enable I2C Clocking */
128 
129  IP_I2C_Init(i2c[id].ip);
130 }
131 
132 /* De-initializes the I2C peripheral registers to their default reset values */
134 {
135  IP_I2C_DeInit(i2c[id].ip);
136 
137  /* Disable I2C clocking */
139 }
140 
141 /* Set up clock rate for LPC_I2C peripheral */
143 {
144  IP_I2C_SetClockRate(i2c[id].ip, I2C_GetClk(id) / clockrate);
145 }
146 
147 /* Get current clock rate for LPC_I2C peripheral */
149 {
150  return I2C_GetClk(id) / IP_I2C_GetClockDiv(i2c[id].ip);
151 }
152 
153 /* Set the master event handler */
155 {
156  struct i2c_interface *iic = &i2c[id];
157  if (!iic->mXfer) {
158  iic->mEvent = event;
159  }
160  return iic->mEvent == event;
161 }
162 
163 /* Get the master event handler */
165 {
166  return i2c[id].mEvent;
167 }
168 
169 /* Transmit and Receive data in master mode */
171 {
172  struct i2c_interface *iic = &i2c[id];
173 
174  iic->mEvent(id, I2C_EVENT_LOCK);
175  xfer->status = I2C_STATUS_BUSY;
176  iic->mXfer = xfer;
177 
178  /* If slave xfer not in progress */
179  if (!iic->sXfer) {
181  }
182  iic->mEvent(id, I2C_EVENT_WAIT);
183  iic->mXfer = 0;
184 
185  /* Wait for stop condition to appear on bus */
186  while (!IP_I2C_BusFree(iic->ip)) {}
187 
188  /* Start slave if one is active */
189  if (SLAVE_ACTIVE(iic)) {
191  }
192 
193  iic->mEvent(id, I2C_EVENT_UNLOCK);
194  return (int) xfer->status;
195 }
196 
197 /* Master tx only */
198 int Chip_I2C_MasterSend(I2C_ID_T id, uint8_t slaveAddr, const uint8_t *buff, uint8_t len)
199 {
200  I2C_XFER_T xfer = {0};
201  xfer.slaveAddr = slaveAddr;
202  xfer.txBuff = buff;
203  xfer.txSz = len;
204  while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
205  return len - xfer.txSz;
206 }
207 
208 /* Transmit one byte and receive an array of bytes after a repeated start condition is generated in Master mode.
209  * This function is useful for communicating with the I2C slave registers
210  */
211 int Chip_I2C_MasterCmdRead(I2C_ID_T id, uint8_t slaveAddr, uint8_t cmd, uint8_t *buff, int len)
212 {
213  I2C_XFER_T xfer = {0};
214  xfer.slaveAddr = slaveAddr;
215  xfer.txBuff = &cmd;
216  xfer.txSz = 1;
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 /* Sequential master read */
224 int Chip_I2C_MasterRead(I2C_ID_T id, uint8_t slaveAddr, uint8_t *buff, int len)
225 {
226  I2C_XFER_T xfer = {0};
227  xfer.slaveAddr = slaveAddr;
228  xfer.rxBuff = buff;
229  xfer.rxSz = len;
230  while (Chip_I2C_MasterTransfer(id, &xfer) == I2C_STATUS_ARBLOST) {}
231  return len - xfer.rxSz;
232 }
233 
234 /* Check if master state is active */
236 {
237  return IP_I2C_IsMasterState(i2c[id].ip);
238 }
239 
240 /* State change handler for master transfer */
242 {
243  if (!IP_I2C_MasterXfer_StateHandler(i2c[id].ip, i2c[id].mXfer)) {
244  i2c[id].mEvent(id, I2C_EVENT_DONE);
245  }
246 }
247 
248 /* Setup slave function */
250  I2C_SLAVE_ID sid,
251  I2C_XFER_T *xfer,
253  uint8_t addrMask)
254 {
255  struct i2c_interface *iic = &i2c[id];
256  struct i2c_slave_interface *si2c = &i2c_slave[id][sid];
257  si2c->xfer = xfer;
258  si2c->event = event;
259 
260  /* Set up the slave address */
261  if (sid != I2C_SLAVE_GENERAL) {
262  IP_I2C_SetSlaveAddress(iic->ip, sid, xfer->slaveAddr, addrMask);
263  }
264 
265  if (!SLAVE_ACTIVE(iic) && !iic->mXfer) {
267  }
268  iic->flags |= 1 << (sid + 8);
269 }
270 
271 /* I2C Slave event handler */
273 {
274  int ret;
275  struct i2c_interface *iic = &i2c[id];
276 
277  /* Get the currently addressed slave */
278  if (!iic->sXfer) {
279  struct i2c_slave_interface *si2c;
280 
282  si2c = &i2c_slave[id][sid];
283  iic->sXfer = si2c->xfer;
284  iic->sEvent = si2c->event;
285  }
286 
287  iic->sXfer->slaveAddr |= iic->mXfer != 0;
288  ret = IP_I2C_SlaveXfer_StateHandler(iic->ip, iic->sXfer);
289  if (ret) {
290  if (iic->sXfer->status == I2C_STATUS_DONE) {
291  iic->sXfer = 0;
292  }
293  iic->sEvent(id, (I2C_EVENT_T) ret);
294  }
295 }
296 
297 /* Disable I2C device */
299 {
300  IP_I2C_Disable(i2c[id].ip);
301 }
302 
303 /* State change checking */
305 {
306  return IP_I2C_IsStateChanged(i2c[id].ip);
307 }