1 /*
2 * @brief LPC15xx I2C master driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2014
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 /*****************************************************************************
39 * Public types/enumerations/variables
40 ****************************************************************************/
41
42 /*****************************************************************************
43 * Private functions
44 ****************************************************************************/
45
46 /*****************************************************************************
47 * Public functions
48 ****************************************************************************/
49
50 /* Set up bus speed for LPC_I2C interface */
Chip_I2CM_SetBusSpeed(LPC_I2C_T * pI2C,uint32_t busSpeed)51 void Chip_I2CM_SetBusSpeed(LPC_I2C_T *pI2C, uint32_t busSpeed)
52 {
53 uint32_t scl = Chip_Clock_GetMainClockRate() / (Chip_I2C_GetClockDiv(pI2C) * busSpeed);
54 Chip_I2CM_SetDutyCycle(pI2C, (scl >> 1), (scl - (scl >> 1)));
55 }
56
57 /* Master transfer state change handler handler */
Chip_I2CM_XferHandler(LPC_I2C_T * pI2C,I2CM_XFER_T * xfer)58 uint32_t Chip_I2CM_XferHandler(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
59 {
60 uint32_t status = Chip_I2CM_GetStatus(pI2C);
61 /* Master Lost Arbitration */
62 if (status & I2C_STAT_MSTRARBLOSS) {
63 /* Set transfer status as Arbitration Lost */
64 xfer->status = I2CM_STATUS_ARBLOST;
65 /* Clear Status Flags */
66 Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS);
67 }
68 /* Master Start Stop Error */
69 else if (status & I2C_STAT_MSTSTSTPERR) {
70 /* Set transfer status as Bus Error */
71 xfer->status = I2CM_STATUS_BUS_ERROR;
72 /* Clear Status Flags */
73 Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTSTSTPERR);
74 }
75 /* Master is Pending */
76 else if (status & I2C_STAT_MSTPENDING) {
77 /* Branch based on Master State Code */
78 switch (Chip_I2CM_GetMasterState(pI2C)) {
79 /* Master idle */
80 case I2C_STAT_MSTCODE_IDLE:
81 /* Do Nothing */
82 break;
83
84 /* Receive data is available */
85 case I2C_STAT_MSTCODE_RXREADY:
86 /* Read Data */
87 *xfer->rxBuff++ = pI2C->MSTDAT;
88 xfer->rxSz--;
89 if (xfer->rxSz) {
90 /* Set Continue if there is more data to read */
91 Chip_I2CM_MasterContinue(pI2C);
92 }
93 else {
94 /* Set transfer status as OK */
95 xfer->status = I2CM_STATUS_OK;
96 /* No data to read send Stop */
97 Chip_I2CM_SendStop(pI2C);
98 }
99 break;
100
101 /* Master Transmit available */
102 case I2C_STAT_MSTCODE_TXREADY:
103 if (xfer->txSz) {
104 /* If Tx data available transmit data and continue */
105 pI2C->MSTDAT = *xfer->txBuff++;
106 xfer->txSz--;
107 Chip_I2CM_MasterContinue(pI2C);
108 }
109 else {
110 /* If receive queued after transmit then initiate master receive transfer*/
111 if (xfer->rxSz) {
112 /* Write Address and RW bit to data register */
113 Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | 0x1);
114 /* Enter to Master Transmitter mode */
115 Chip_I2CM_SendStart(pI2C);
116 }
117 else {
118 /* If no receive queued then set transfer status as OK */
119 xfer->status = I2CM_STATUS_OK;
120 /* Send Stop */
121 Chip_I2CM_SendStop(pI2C);
122 }
123 }
124 break;
125
126 case I2C_STAT_MSTCODE_NACKADR:
127 /* Set transfer status as NACK on address */
128 xfer->status = I2CM_STATUS_NAK_ADR;
129 Chip_I2CM_SendStop(pI2C);
130 break;
131
132 case I2C_STAT_MSTCODE_NACKDAT:
133 /* Set transfer status as NACK on data */
134 xfer->status = I2CM_STATUS_NAK_DAT;
135 Chip_I2CM_SendStop(pI2C);
136 break;
137
138 default:
139 /* Default case should not occur*/
140 xfer->status = I2CM_STATUS_ERROR;
141 break;
142 }
143 }
144 else {
145 /* Default case should not occur */
146 xfer->status = I2CM_STATUS_ERROR;
147 }
148 return xfer->status != I2CM_STATUS_BUSY;
149 }
150
151 /* Transmit and Receive data in master mode */
Chip_I2CM_Xfer(LPC_I2C_T * pI2C,I2CM_XFER_T * xfer)152 void Chip_I2CM_Xfer(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
153 {
154 /* set the transfer status as busy */
155 xfer->status = I2CM_STATUS_BUSY;
156 /* Clear controller state. */
157 Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
158 /* Write Address and RW bit to data register */
159 Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0));
160 /* Enter to Master Transmitter mode */
161 Chip_I2CM_SendStart(pI2C);
162 }
163
164 /* Transmit and Receive data in master mode */
Chip_I2CM_XferBlocking(LPC_I2C_T * pI2C,I2CM_XFER_T * xfer)165 uint32_t Chip_I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
166 {
167 uint32_t ret = 0;
168 /* start transfer */
169 Chip_I2CM_Xfer(pI2C, xfer);
170
171 while (ret == 0) {
172 /* wait for status change interrupt */
173 while (!Chip_I2CM_IsMasterPending(pI2C)) {}
174 /* call state change handler */
175 ret = Chip_I2CM_XferHandler(pI2C, xfer);
176 }
177 return ret;
178 }
179