LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
i2cm_18xx_43xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC18xx/43xx I2C master 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 
41 /*****************************************************************************
42  * Public types/enumerations/variables
43  ****************************************************************************/
44 
45 /*****************************************************************************
46  * Private functions
47  ****************************************************************************/
48 /* Get the ADC Clock Rate */
50 {
51  return (pI2C == LPC_I2C0)? CLK_APB1_I2C0 : CLK_APB3_I2C1;
52 }
53 
54 /*****************************************************************************
55  * Public functions
56  ****************************************************************************/
57 
58 /* Initializes the LPC_I2C peripheral with specified parameter */
60 {
61  /* Enable I2C clock */
63  /* Reset I2C state machine */
65 }
66 
67 /* De-initializes the I2C peripheral registers to their default reset values */
69 {
70  /* Reset I2C state machine */
72  /* Disable I2C clock */
74 }
75 
76 /* Set up bus speed for LPC_I2C interface */
77 void Chip_I2CM_SetBusSpeed(LPC_I2C_T *pI2C, uint32_t busSpeed)
78 {
79  uint32_t clockDiv = (Chip_Clock_GetRate(i2cm_getClkId(pI2C)) / busSpeed);
80 
81  Chip_I2CM_SetDutyCycle(pI2C, (clockDiv >> 1), (clockDiv - (clockDiv >> 1)));
82 }
83 
84 /* Master transfer state change handler handler */
86 {
87  uint32_t cclr = I2C_CON_FLAGS;
88 
89  switch (Chip_I2CM_GetCurState(pI2C)) {
90  case 0x08: /* Start condition on bus */
91  case 0x10: /* Repeated start condition */
92  pI2C->DAT = (xfer->slaveAddr << 1) | (xfer->txSz == 0);
93  break;
94 
95  /* Tx handling */
96  case 0x20: /* SLA+W sent NAK received */
97  case 0x30: /* DATA sent NAK received */
98  if ((xfer->options & I2CM_XFER_OPTION_IGNORE_NACK) == 0) {
99  xfer->status = I2CM_STATUS_NAK;
100  cclr &= ~I2C_CON_STO;
101  break;
102  }
103 
104  case 0x18: /* SLA+W sent and ACK received */
105  case 0x28: /* DATA sent and ACK received */
106  if (!xfer->txSz) {
107  if (xfer->rxSz) {
108  cclr &= ~I2C_CON_STA;
109  }
110  else {
111  xfer->status = I2CM_STATUS_OK;
112  cclr &= ~I2C_CON_STO;
113  }
114 
115  }
116  else {
117  pI2C->DAT = *xfer->txBuff++;
118  xfer->txSz--;
119  }
120  break;
121 
122  /* Rx handling */
123  case 0x58: /* Data Received and NACK sent */
124  case 0x50: /* Data Received and ACK sent */
125  *xfer->rxBuff++ = pI2C->DAT;
126  xfer->rxSz--;
127 
128  case 0x40: /* SLA+R sent and ACK received */
129  if ((xfer->rxSz > 1) || (xfer->options & I2CM_XFER_OPTION_LAST_RX_ACK)) {
130  cclr &= ~I2C_CON_AA;
131  }
132  if (xfer->rxSz == 0) {
133  xfer->status = I2CM_STATUS_OK;
134  cclr &= ~I2C_CON_STO;
135  }
136  break;
137 
138  /* NAK Handling */
139  case 0x48: /* SLA+R sent NAK received */
141  cclr &= ~I2C_CON_STO;
142  break;
143 
144  case 0x38: /* Arbitration lost */
145  xfer->status = I2CM_STATUS_ARBLOST;
146  break;
147 
148  case 0x00: /* Bus Error */
150  cclr &= ~I2C_CON_STO;
151  break;
152  default:
153  xfer->status = I2CM_STATUS_ERROR;
154  cclr &= ~I2C_CON_STO;
155  break;
156  }
157 
158  /* Set clear control flags */
159  pI2C->CONSET = cclr ^ I2C_CON_FLAGS;
160  /* Stop flag should not be cleared as it is a reserved bit */
161  pI2C->CONCLR = cclr & (I2C_CON_AA | I2C_CON_SI | I2C_CON_STA);
162 
163  return xfer->status != I2CM_STATUS_BUSY;
164 }
165 
166 /* Transmit and Receive data in master mode */
168 {
169  /* set the transfer status as busy */
170  xfer->status = I2CM_STATUS_BUSY;
171  /* Clear controller state. */
173  /* Enter to Master Transmitter mode */
174  Chip_I2CM_SendStart(pI2C);
175 }
176 
177 /* Transmit and Receive data in master mode */
179 {
180  uint32_t ret = 0;
181  /* start transfer */
182  Chip_I2CM_Xfer(pI2C, xfer);
183 
184  while (ret == 0) {
185  /* wait for status change interrupt */
186  while ( Chip_I2CM_StateChanged(pI2C) == 0) {}
187  /* call state change handler */
188  ret = Chip_I2CM_XferHandler(pI2C, xfer);
189  }
190  return ret;
191 }
192 
193 /* Master tx only */
194 uint32_t Chip_I2CM_Write(LPC_I2C_T *pI2C, const uint8_t *buff, uint32_t len)
195 {
196  uint32_t txLen = 0, err = 0;
197 
198  /* clear state change interrupt status */
199  Chip_I2CM_ClearSI(pI2C);
200  /* generate START condition */
201  Chip_I2CM_SendStart(pI2C);
202 
203  while ((txLen < len) && (err == 0)) {
204  /* wait for status change interrupt */
205  while ( Chip_I2CM_StateChanged(pI2C) == 0) {}
206 
207  /* check status and send data */
208  switch (Chip_I2CM_GetCurState(pI2C)) {
209  case 0x08: /* Start condition on bus */
210  case 0x10: /* Repeated start condition */
211  case 0x18: /* SLA+W sent and ACK received */
212  case 0x28: /* DATA sent and ACK received */
213  Chip_I2CM_WriteByte(pI2C, buff[txLen++]);
214  break;
215 
216  case 0x38: /* Arbitration lost */
217  break;
218 
219  default: /* we shouldn't be in any other state */
220  err = 1;
221  break;
222  }
223  /* clear state change interrupt status */
224  Chip_I2CM_ClearSI(pI2C);
225  }
226 
227  return txLen;
228 }
229 
230 /* Sequential master read */
231 uint32_t Chip_I2CM_Read(LPC_I2C_T *pI2C, uint8_t *buff, uint32_t len)
232 {
233  uint32_t rxLen = 0, err = 0;
234 
235  /* clear state change interrupt status */
236  Chip_I2CM_ClearSI(pI2C);
237  /* generate START condition and auto-ack data received */
238  pI2C->CONSET = I2C_CON_AA | I2C_CON_STA;
239 
240  while ((rxLen < len) && (err == 0)) {
241  /* wait for status change interrupt */
242  while ( Chip_I2CM_StateChanged(pI2C) == 0) {}
243 
244  /* check status and send data */
245  switch (Chip_I2CM_GetCurState(pI2C)) {
246  case 0x08: /* Start condition on bus */
247  case 0x10: /* Repeated start condition */
248  case 0x40: /* SLA+R sent and ACK received */
249  case 0x50: /* Data Received and ACK sent */
250  buff[rxLen++] = Chip_I2CM_ReadByte(pI2C);
251  break;
252 
253  case 0x38: /* Arbitration lost */
254  break;
255 
256  default: /* we shouldn't be in any other state */
257  err = 1;
258  break;
259  }
260  /* clear state change interrupt status */
261  Chip_I2CM_ClearSI(pI2C);
262  }
263 
264  return rxLen;
265 }