1 /*
2 * @brief LPC15xx I2C slave 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 #ifndef __I2CS_15XX_H_
33 #define __I2CS_15XX_H_
34
35 #include "i2c_common_15xx.h"
36
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40
41 /** @defgroup I2CS_15XX CHIP: LPC15xx I2C slave-only driver
42 * @ingroup I2C_15XX
43 * This driver only works in slave mode.
44 * @{
45 */
46
47 /** @brief I2C slave service start callback
48 * This callback is called from the I2C slave handler when an I2C slave address is
49 * received and needs servicing. It's used to indicate the start of a slave transfer
50 * that will happen on the slave bus.
51 */
52 typedef void (*SlaveXferStart)(uint8_t addr);
53
54 /** @brief I2C slave send data callback
55 * This callback is called from the I2C slave handler when an I2C slave address needs
56 * data to send. Return 0 to NACK the master and terminate the transfer, or return
57 * a non-0 value with the value to send in *data.
58 */
59 typedef uint8_t (*SlaveXferSend)(uint8_t *data);
60
61 /** @brief I2C slave receive data callback
62 * This callback is called from the I2C slave handler when an I2C slave address has
63 * receive data. Return 0 to NACK the master and terminate the transfer, or return
64 * a non-0 value to continue the transfer.
65 */
66 typedef uint8_t (*SlaveXferRecv)(uint8_t data);
67
68 /** @brief I2C slave service done callback
69 * This callback is called from the I2C slave handler when an I2C slave address is
70 * received and needs servicing. It's used to indicate the start of a slave transfer
71 * that will happen on the slave bus.
72 */
73 typedef void (*SlaveXferDone)(void);
74
75 /**
76 * Slave transfer are performed using 3 callbacks. These 3 callbacks handle most I2C
77 * slave transfer cases. When the slave is setup and a slave interrupt is receive
78 * and processed with the Chip_I2CS_XferHandler() function in the I2C interrupt handler,
79 * one of these 3 callbacks is called. The callbacks can be used for unsized transfers
80 * from the master.
81 *
82 * When an address is received, the SlaveXferAddr() callback is called with the
83 * received address. Only addresses enabled in the slave controller will be handled.
84 * The slave controller can support up to 4 slave addresses.
85 *
86 * If the master is going to perform a read operation, the SlaveXferSend() callback
87 * is called. Place the data byte to send in *data and return a non-0 value to the
88 * caller, or return 0 to NACK the master. (Note the master ACKS/NACKS to slave
89 * on reads, so this won't necessarily stop the slave transfer.)<br>
90 *
91 * If the master performs a write operation, the SlaveXferRecv() callback is called
92 * with the received data. Return a non-0 value to the caller, or return 0 to NACK
93 * the master.<br>
94 *
95 * Once the transfer completes, the SlaveXferDone() callback will be called.<br>
96 */
97 typedef struct {
98 SlaveXferStart slaveStart; /*!< Called when an matching I2C slave address is received */
99 SlaveXferSend slaveSend; /*!< Called when a byte is needed to send to master */
100 SlaveXferRecv slaveRecv; /*!< Called when a byte is received from master */
101 SlaveXferDone slaveDone; /*!< Called when a slave transfer is complete */
102 } I2CS_XFER_T;
103
104 /**
105 * @brief Enable I2C slave interface
106 * @param pI2C : Pointer to selected I2C peripheral
107 * @return Nothing
108 * @note Do not call this function until the slave interface is fully configured.
109 */
Chip_I2CS_Enable(LPC_I2C_T * pI2C)110 STATIC INLINE void Chip_I2CS_Enable(LPC_I2C_T *pI2C)
111 {
112 pI2C->CFG = (pI2C->CFG & I2C_CFG_MASK) | I2C_CFG_SLVEN;
113 }
114
115 /**
116 * @brief Disable I2C slave interface
117 * @param pI2C : Pointer to selected I2C peripheral
118 * @return Nothing
119 */
Chip_I2CS_Disable(LPC_I2C_T * pI2C)120 STATIC INLINE void Chip_I2CS_Disable(LPC_I2C_T *pI2C)
121 {
122 pI2C->CFG = (pI2C->CFG & I2C_CFG_MASK) & ~I2C_CFG_SLVEN;
123 }
124
125 /**
126 * @brief Get I2C Status
127 * @param pI2C : Pointer to selected I2C peripheral
128 * @return I2C Status register value
129 * @note This function returns the value of the status register.
130 */
Chip_I2CS_GetStatus(LPC_I2C_T * pI2C)131 STATIC INLINE uint32_t Chip_I2CS_GetStatus(LPC_I2C_T *pI2C)
132 {
133 return pI2C->STAT;
134 }
135
136 /**
137 * @brief Clear I2C status bits (slave)
138 * @param pI2C : Pointer to selected I2C peripheral
139 * @param clrStatus : Status bit to clear, must be I2C_STAT_SLVDESEL
140 * @return Nothing
141 * @note This function clears selected status flags.
142 */
Chip_I2CS_ClearStatus(LPC_I2C_T * pI2C,uint32_t clrStatus)143 STATIC INLINE void Chip_I2CS_ClearStatus(LPC_I2C_T *pI2C, uint32_t clrStatus)
144 {
145 pI2C->STAT = clrStatus & I2C_STAT_SLVDESEL;
146 }
147
148 /**
149 * @brief Check if I2C slave is pending
150 * @param pI2C : Pointer to selected I2C peripheral
151 * @return Returns TRUE if the slave is pending else returns FALSE
152 * @note
153 */
Chip_I2CS_IsSlavePending(LPC_I2C_T * pI2C)154 STATIC INLINE bool Chip_I2CS_IsSlavePending(LPC_I2C_T *pI2C)
155 {
156 return (pI2C->STAT & I2C_STAT_SLVPENDING) != 0;
157 }
158
159 /**
160 * @brief Check if I2C slave is selected
161 * @param pI2C : Pointer to selected I2C peripheral
162 * @return Returns TRUE if the slave is is selected, otherwise FALSE
163 * @note
164 */
Chip_I2CS_IsSlaveSelected(LPC_I2C_T * pI2C)165 STATIC INLINE bool Chip_I2CS_IsSlaveSelected(LPC_I2C_T *pI2C)
166 {
167 return (pI2C->STAT & I2C_STAT_SLVSEL) != 0;
168 }
169
170 /**
171 * @brief Check if I2C slave is deselected
172 * @param pI2C : Pointer to selected I2C peripheral
173 * @return Returns TRUE if the slave is is deselected, otherwise FALSE
174 * @note
175 */
Chip_I2CS_IsSlaveDeSelected(LPC_I2C_T * pI2C)176 STATIC INLINE bool Chip_I2CS_IsSlaveDeSelected(LPC_I2C_T *pI2C)
177 {
178 return (pI2C->STAT & I2C_STAT_SLVDESEL) != 0;
179 }
180
181 /**
182 * @brief Get current state of the I2C slave
183 * @param pI2C : Pointer to selected I2C peripheral
184 * @return slave State Code, a value of type I2C_STAT_SLVCODE_*
185 * @note After the slave is pending this state code tells the reason
186 * for slave pending.
187 */
Chip_I2CS_GetSlaveState(LPC_I2C_T * pI2C)188 STATIC INLINE uint32_t Chip_I2CS_GetSlaveState(LPC_I2C_T *pI2C)
189 {
190 return (pI2C->STAT & I2C_STAT_SLVSTATE) >> 9;
191 }
192
193 /**
194 * @brief Returns the current slave address match index
195 * @param pI2C : Pointer to selected I2C peripheral
196 * @return slave match index, 0 - 3
197 */
Chip_I2CS_GetSlaveMatchIndex(LPC_I2C_T * pI2C)198 STATIC INLINE uint32_t Chip_I2CS_GetSlaveMatchIndex(LPC_I2C_T *pI2C)
199 {
200 return (pI2C->STAT & I2C_STAT_SLVIDX) >> 12;
201 }
202
203 /**
204 * @brief Slave Continue transfer operation (ACK)
205 * @param pI2C : Pointer to selected I2C peripheral
206 * @return Nothing
207 * @note This function sets the slave controller to continue transmission.
208 * This should be called only when slave is pending. The function writes a
209 * complete value to slave Control register, ORing is not advised.
210 */
Chip_I2CS_SlaveContinue(LPC_I2C_T * pI2C)211 STATIC INLINE void Chip_I2CS_SlaveContinue(LPC_I2C_T *pI2C)
212 {
213 pI2C->SLVCTL = I2C_SLVCTL_SLVCONTINUE;
214 }
215
216 /**
217 * @brief Slave NACK operation
218 * @param pI2C : Pointer to selected I2C peripheral
219 * @return Nothing
220 * @note This function sets the slave controller to NAK the master.
221 */
Chip_I2CS_SlaveNACK(LPC_I2C_T * pI2C)222 STATIC INLINE void Chip_I2CS_SlaveNACK(LPC_I2C_T *pI2C)
223 {
224 pI2C->SLVCTL = I2C_SLVCTL_SLVNACK;
225 }
226
227 /**
228 * @brief Transmit a single data byte through the I2C peripheral (slave)
229 * @param pI2C : Pointer to selected I2C peripheral
230 * @param data : Byte to transmit
231 * @return Nothing
232 * @note This function attempts to place a byte into the I2C slave
233 * Data Register
234 *
235 */
Chip_I2CS_WriteByte(LPC_I2C_T * pI2C,uint8_t data)236 STATIC INLINE void Chip_I2CS_WriteByte(LPC_I2C_T *pI2C, uint8_t data)
237 {
238 pI2C->SLVDAT = (uint32_t) data;
239 }
240
241 /**
242 * @brief Read a single byte data from the I2C peripheral (slave)
243 * @param pI2C : Pointer to selected I2C peripheral
244 * @return A single byte of data read
245 * @note This function reads a byte from the I2C receive hold register
246 * regardless of I2C state.
247 */
Chip_I2CS_ReadByte(LPC_I2C_T * pI2C)248 STATIC INLINE uint8_t Chip_I2CS_ReadByte(LPC_I2C_T *pI2C)
249 {
250 return (uint8_t) (pI2C->SLVDAT & I2C_SLVDAT_DATAMASK);
251 }
252
253 /**
254 * @brief Set a I2C slave address for slave operation
255 * @param pI2C : Pointer to selected I2C peripheral
256 * @param slvNum : Possible slave address number, between 0 - 3
257 * @param slvAddr : Slave Address for the index (7-bits, bit 7 = 0)
258 * @return Nothing
259 * @note Setting a slave address also enables the slave address. Do
260 * not 'pre-shift' the slave address.
261 */
Chip_I2CS_SetSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum,uint8_t slvAddr)262 STATIC INLINE void Chip_I2CS_SetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum, uint8_t slvAddr)
263 {
264 pI2C->SLVADR[slvNum] = (uint32_t) (slvAddr << 1);
265 }
266
267 /**
268 * @brief Return a I2C programmed slave address
269 * @param pI2C : Pointer to selected I2C peripheral
270 * @param slvNum : Possible slave address number, between 0 - 3
271 * @return Nothing
272 */
Chip_I2CS_GetSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum)273 STATIC INLINE uint8_t Chip_I2CS_GetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
274 {
275 return (pI2C->SLVADR[slvNum] >> 1) & 0x7F;
276 }
277
278 /**
279 * @brief Enable a I2C address
280 * @param pI2C : Pointer to selected I2C peripheral
281 * @param slvNum : Possible slave address number, between 0 - 3
282 * @return Nothing
283 */
Chip_I2CS_EnableSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum)284 STATIC INLINE void Chip_I2CS_EnableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
285 {
286 pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) & ~I2C_SLVADR_SADISABLE;
287 }
288
289 /**
290 * @brief Disable a I2C address
291 * @param pI2C : Pointer to selected I2C peripheral
292 * @param slvNum : Possible slave address number, between 0 - 3
293 * @return Nothing
294 */
Chip_I2CS_DisableSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum)295 STATIC INLINE void Chip_I2CS_DisableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
296 {
297 pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) | I2C_SLVADR_SADISABLE;
298 }
299
300 /**
301 * @brief Setup slave qialifier address
302 * @param pI2C : Pointer to selected I2C peripheral
303 * @param extend : true to extend I2C slave detect address 0 range, or false to match to corresponding bits
304 * @param slvAddr : Slave address qualifier, see SLVQUAL0 register in User Manual
305 * @return Nothing
306 * @note Do not 'pre-shift' the slave address.
307 */
Chip_I2CS_SetSlaveQual0(LPC_I2C_T * pI2C,bool extend,uint8_t slvNum)308 STATIC INLINE void Chip_I2CS_SetSlaveQual0(LPC_I2C_T *pI2C, bool extend, uint8_t slvNum)
309 {
310 slvNum = slvNum << 1;
311 if (extend) {
312 slvNum |= I2C_SLVQUAL_QUALMODE0;
313 }
314
315 pI2C->SLVQUAL0 = slvNum;
316 }
317
318 /**
319 * @brief Slave transfer state change handler
320 * @param pI2C : Pointer to selected I2C peripheral
321 * @param xfers : Pointer to a I2CS_MULTI_XFER_T structure see notes below
322 * @return Returns non-zero value on completion of transfer
323 * @note See @ref I2CS_XFER_T for more information on this function. When using
324 * this function, the I2C_INTENSET_SLVPENDING and I2C_INTENSET_SLVDESEL interrupts
325 * should be enabled and setup in the I2C interrupt handler to call this function
326 * when they fire.
327 */
328 uint32_t Chip_I2CS_XferHandler(LPC_I2C_T *pI2C, const I2CS_XFER_T *xfers);
329
330 /**
331 * @}
332 */
333
334 #ifdef __cplusplus
335 }
336 #endif
337
338 #endif /* __I2CS_15XX_H_ */
339