1 /**
2 * @file xmc_i2c.c
3 * @date 2019-07-12
4 *
5 * @cond
6 *********************************************************************************************************************
7 * XMClib v2.1.24 - XMC Peripheral Driver Library
8 *
9 * Copyright (c) 2015-2019, Infineon Technologies AG
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
13 * following conditions are met:
14 *
15 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided with the distribution.
20 *
21 * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
22 * products derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with
33 * Infineon Technologies AG dave@infineon.com).
34 *********************************************************************************************************************
35 *
36 * Change History
37 * --------------
38 *
39 * 2015-02-20:
40 * - Initial <br>
41 *
42 * 2015-05-20:
43 - Modified XMC_I2C_CH_Stop() API for not setting to IDLE the channel if it is busy <br>
44 *
45 * 2015-06-20:
46 * - Removed GetDriverVersion API <br>
47 *
48 * 2015-08-14:
49 * - updated the XMC_I2C_CH_SetBaudrate API to support dynamic change from 400K to low frequencies <br>
50 *
51 * 2015-09-01:
52 * - Modified XMC_I2C_CH_EnableEvent() and XMC_I2C_CH_DisableEvent() for supporting multiple events configuration <br>
53 *
54 * 2015-10-02:
55 * - Fixed 10bit addressing
56 *
57 * 2019-05-07:
58 * - Added XMC_I2C_CH_SetBaudrateEx() which allows to select between baudrate generator normal divider and fractional divider mode
59 *
60 * 2019-07-12:
61 * - Fixed wrong oversampling setting in case of baudrate greater than 100Kbaud/s
62 *
63 * @endcond
64 *
65 */
66
67 /*********************************************************************************************************************
68 * HEADER FILES
69 *********************************************************************************************************************/
70 #include <xmc_i2c.h>
71
72 /*********************************************************************************************************************
73 * MACROS
74 *********************************************************************************************************************/
75 #define XMC_I2C_7BIT_ADDR_Pos (8U) /**< 7-bit address position */
76 #define TRANSMISSION_MODE (3U) /**< The shift control signal is considered active
77 without referring to the actual signal level. Data
78 frame transfer is possible after each edge of the signal.*/
79 #define WORDLENGTH (7U) /**< Word length */
80 #define SET_TDV (1U) /**< Transmission data valid */
81 #define XMC_I2C_10BIT_ADDR_MASK (0x7C00U) /**< Address mask for 10-bit mode */
82
83 /*********************************************************************************************************************
84 * ENUMS
85 *********************************************************************************************************************/
86
87 typedef enum XMC_I2C_CH_TDF
88 {
89 XMC_I2C_CH_TDF_MASTER_SEND = 0U,
90 XMC_I2C_CH_TDF_SLAVE_SEND = (uint32_t)1U << 8U,
91 XMC_I2C_CH_TDF_MASTER_RECEIVE_ACK = (uint32_t)2U << 8U,
92 XMC_I2C_CH_TDF_MASTER_RECEIVE_NACK = (uint32_t)3U << 8U,
93 XMC_I2C_CH_TDF_MASTER_START = (uint32_t)4U << 8U,
94 XMC_I2C_CH_TDF_MASTER_RESTART = (uint32_t)5U << 8U,
95 XMC_I2C_CH_TDF_MASTER_STOP = (uint32_t)6U << 8U
96 } XMC_I2C_CH_TDF_t;
97
98 typedef enum XMC_I2C_CH_MAX_SPEED
99 {
100 XMC_I2C_CH_MAX_SPEED_STANDARD = 100000U,
101 XMC_I2C_CH_MAX_SPEED_FAST = 400000U
102 } XMC_I2C_CH_MAX_SPEED_t;
103
104 typedef enum XMC_I2C_CH_CLOCK_OVERSAMPLING
105 {
106 XMC_I2C_CH_CLOCK_OVERSAMPLING_STANDARD = 10U,
107 XMC_I2C_CH_CLOCK_OVERSAMPLING_FAST = 25U
108 } XMC_I2C_CH_CLOCK_OVERSAMPLINGS_t;
109
110 /*********************************************************************************************************************
111 * API IMPLEMENTATION
112 *********************************************************************************************************************/
113 /* Initializes the USIC channel by setting the data format, slave address, baudrate, transfer buffer */
XMC_I2C_CH_Init(XMC_USIC_CH_t * const channel,const XMC_I2C_CH_CONFIG_t * const config)114 void XMC_I2C_CH_Init(XMC_USIC_CH_t *const channel, const XMC_I2C_CH_CONFIG_t *const config)
115 {
116 XMC_USIC_CH_Enable(channel);
117
118 /* Data format configuration */
119 channel->SCTR = ((uint32_t)TRANSMISSION_MODE << (uint32_t)USIC_CH_SCTR_TRM_Pos) | /* Transmision mode */
120 ((uint32_t)WORDLENGTH << (uint32_t)USIC_CH_SCTR_WLE_Pos) | /* 8 data bits */
121 USIC_CH_SCTR_FLE_Msk | /* unlimited data flow */
122 USIC_CH_SCTR_SDIR_Msk | /* MSB shifted first */
123 USIC_CH_SCTR_PDL_Msk; /* Passive Data Level */
124
125 XMC_I2C_CH_SetSlaveAddress(channel, config->address);
126 (void)XMC_I2C_CH_SetBaudrateEx(channel, config->baudrate, config->normal_divider_mode);
127
128
129 /* Enable transfer buffer */
130 channel->TCSR = ((uint32_t)SET_TDV << (uint32_t)USIC_CH_TCSR_TDEN_Pos) | USIC_CH_TCSR_TDSSM_Msk;
131
132 /* Clear status flags */
133 channel->PSCR = 0xFFFFFFFFU;
134
135 /* Disable parity generation */
136 channel->CCR = 0x0U;
137 }
138 /* Sets the slave address */
XMC_I2C_CH_SetSlaveAddress(XMC_USIC_CH_t * const channel,const uint16_t address)139 void XMC_I2C_CH_SetSlaveAddress(XMC_USIC_CH_t *const channel, const uint16_t address)
140 {
141 if ((address & XMC_I2C_10BIT_ADDR_MASK) == XMC_I2C_10BIT_ADDR_GROUP)
142 {
143 channel->PCR_IICMode = (address & 0xffU) | ((address << 1) & 0xfe00U);
144 }
145 else
146 {
147 channel->PCR_IICMode = ((uint32_t)address) << XMC_I2C_7BIT_ADDR_Pos;
148 }
149 }
150 /* Read the slave address */
XMC_I2C_CH_GetSlaveAddress(const XMC_USIC_CH_t * const channel)151 uint16_t XMC_I2C_CH_GetSlaveAddress(const XMC_USIC_CH_t *const channel)
152 {
153 uint32_t address = channel->PCR_IICMode & (uint32_t)USIC_CH_PCR_IICMode_SLAD_Msk;
154
155 if ((address & 0xffU) == 0U)
156 {
157 address = address >> XMC_I2C_7BIT_ADDR_Pos;
158 }
159 else
160 {
161 address = (address & 0xffU) | ((address >> 1) & 0x0300U);
162 }
163
164 return (uint16_t)address;
165 }
166
167 /* Sets the baudrate and oversampling based on standard speed or fast speed */
XMC_I2C_CH_SetBaudrate(XMC_USIC_CH_t * const channel,uint32_t rate)168 XMC_I2C_CH_STATUS_t XMC_I2C_CH_SetBaudrate(XMC_USIC_CH_t *const channel, uint32_t rate)
169 {
170 XMC_I2C_CH_STATUS_t status;
171
172 status = XMC_I2C_CH_STATUS_ERROR;
173
174 if (rate <= (uint32_t)XMC_I2C_CH_MAX_SPEED_STANDARD)
175 {
176 channel->PCR_IICMode &= (uint32_t)~USIC_CH_PCR_IICMode_STIM_Msk;
177 if (XMC_USIC_CH_SetBaudrate(channel, rate, (uint32_t)XMC_I2C_CH_CLOCK_OVERSAMPLING_STANDARD) == XMC_USIC_CH_STATUS_OK)
178 {
179 status = XMC_I2C_CH_STATUS_OK;
180 }
181 }
182 else if (rate <= (uint32_t)XMC_I2C_CH_MAX_SPEED_FAST)
183 {
184 channel->PCR_IICMode |= (uint32_t)USIC_CH_PCR_IICMode_STIM_Msk;
185 if (XMC_USIC_CH_SetBaudrate(channel, rate, (uint32_t)XMC_I2C_CH_CLOCK_OVERSAMPLING_FAST) == XMC_USIC_CH_STATUS_OK)
186 {
187 status = XMC_I2C_CH_STATUS_OK;
188 }
189 }
190 else
191 {
192 status = XMC_I2C_CH_STATUS_ERROR;
193 }
194
195 return status;
196 }
197
198 /* Sets the baudrate and oversampling based on standard speed or fast speed */
XMC_I2C_CH_SetBaudrateEx(XMC_USIC_CH_t * const channel,uint32_t rate,bool normal_divider_mode)199 XMC_I2C_CH_STATUS_t XMC_I2C_CH_SetBaudrateEx(XMC_USIC_CH_t *const channel, uint32_t rate, bool normal_divider_mode)
200 {
201 XMC_USIC_CH_STATUS_t status;
202
203 if (rate <= (uint32_t)XMC_I2C_CH_MAX_SPEED_STANDARD)
204 {
205 channel->PCR_IICMode &= (uint32_t)~USIC_CH_PCR_IICMode_STIM_Msk;
206 if (normal_divider_mode)
207 {
208 status = XMC_USIC_CH_SetBaudrateEx(channel, rate, (uint32_t)XMC_I2C_CH_CLOCK_OVERSAMPLING_STANDARD);
209 }
210 else
211 {
212 /* Fractional divider mode */
213 status = XMC_USIC_CH_SetBaudrate(channel, rate, (uint32_t)XMC_I2C_CH_CLOCK_OVERSAMPLING_STANDARD);
214 }
215 }
216 else if (rate <= (uint32_t)XMC_I2C_CH_MAX_SPEED_FAST)
217 {
218 channel->PCR_IICMode |= (uint32_t)USIC_CH_PCR_IICMode_STIM_Msk;
219 if (normal_divider_mode)
220 {
221 status = XMC_USIC_CH_SetBaudrateEx(channel, rate, (uint32_t)XMC_I2C_CH_CLOCK_OVERSAMPLING_FAST);
222 }
223 else
224 {
225 /* Fractional divider mode */
226 status = XMC_USIC_CH_SetBaudrate(channel, rate, (uint32_t)XMC_I2C_CH_CLOCK_OVERSAMPLING_FAST);
227 }
228 }
229 else
230 {
231 status = XMC_USIC_CH_STATUS_ERROR;
232 }
233
234 return (XMC_I2C_CH_STATUS_t)status;
235 }
236
237 /* Sends master start condition along with read/write command to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_MasterStart(XMC_USIC_CH_t * const channel,const uint16_t addr,const XMC_I2C_CH_CMD_t command)238 void XMC_I2C_CH_MasterStart(XMC_USIC_CH_t *const channel, const uint16_t addr, const XMC_I2C_CH_CMD_t command)
239 {
240 uint32_t temp;
241
242 temp = addr | (uint32_t)XMC_I2C_CH_TDF_MASTER_START;
243 if (command == XMC_I2C_CH_CMD_READ)
244 {
245 temp |= 0x1U;
246 }
247
248 /* Check FIFO size */
249 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
250 {
251 while (XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
252 {
253 /* check TDV, wait until TBUF is ready */
254 }
255
256 /* clear PSR_TBIF */
257 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
258
259 channel->TBUF[0] = temp;
260 }
261 else
262 {
263 channel->IN[0U] = temp;
264 }
265 }
266 /* Sends master repeated start condition along with read/write command to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_MasterRepeatedStart(XMC_USIC_CH_t * const channel,const uint16_t addr,const XMC_I2C_CH_CMD_t command)267 void XMC_I2C_CH_MasterRepeatedStart(XMC_USIC_CH_t *const channel, const uint16_t addr, const XMC_I2C_CH_CMD_t command)
268 {
269 uint32_t tmp;
270 tmp = addr | (uint32_t)XMC_I2C_CH_TDF_MASTER_RESTART;
271 if (command == XMC_I2C_CH_CMD_READ)
272 {
273 tmp |= 0x1U;
274 }
275
276 /* Check FIFO size */
277 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
278 {
279 while (XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
280 {
281 /* check TDV, wait until TBUF is ready */
282 }
283
284 /* clear PSR_TBIF */
285 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
286
287 channel->TBUF[0] = tmp;
288 }
289 else
290 {
291 channel->IN[0U] = tmp;
292 }
293 }
294
295 /* Sends master stop command to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_MasterStop(XMC_USIC_CH_t * const channel)296 void XMC_I2C_CH_MasterStop(XMC_USIC_CH_t *const channel)
297 {
298 /* Check FIFO size */
299 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
300 {
301 while (XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
302 {
303 /* check TDV, wait until TBUF is ready */
304 }
305
306 /* clear PSR_TBIF */
307 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
308
309 channel->TBUF[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_STOP;
310 }
311 else
312 {
313 channel->IN[0U] = (uint32_t)XMC_I2C_CH_TDF_MASTER_STOP;
314 }
315 }
316
317 /* Sends master send command along with data to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_MasterTransmit(XMC_USIC_CH_t * const channel,const uint8_t data)318 void XMC_I2C_CH_MasterTransmit(XMC_USIC_CH_t *const channel, const uint8_t data)
319 {
320 /* Check FIFO size */
321 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
322 {
323 while (XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
324 {
325 /* check TDV, wait until TBUF is ready */
326 }
327
328 /* clear PSR_TBIF */
329 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
330
331 channel->TBUF[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_SEND | data;
332 }
333 else
334 {
335 channel->IN[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_SEND | data;
336 }
337 }
338
339 /* Sends slave send command along with data to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_SlaveTransmit(XMC_USIC_CH_t * const channel,const uint8_t data)340 void XMC_I2C_CH_SlaveTransmit(XMC_USIC_CH_t *const channel, const uint8_t data)
341 {
342 /* Check FIFO size */
343 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
344 {
345 while(XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
346 {
347 /* check TDV, wait until TBUF is ready */
348 }
349
350 /* clear PSR_TBIF */
351 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
352
353 channel->TBUF[0] = (uint32_t)XMC_I2C_CH_TDF_SLAVE_SEND | data;
354 }
355 else
356 {
357 channel->IN[0] = (uint32_t)XMC_I2C_CH_TDF_SLAVE_SEND | data;
358 }
359 }
360
361 /* Sends master receive ack command to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_MasterReceiveAck(XMC_USIC_CH_t * const channel)362 void XMC_I2C_CH_MasterReceiveAck(XMC_USIC_CH_t *const channel)
363 {
364 /* Check FIFO size */
365 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
366 {
367 while(XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
368 {
369 /* check TDV, wait until TBUF is ready */
370 }
371
372 /* clear PSR_TBIF */
373 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
374
375 channel->TBUF[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_RECEIVE_ACK;
376 }
377 else
378 {
379 channel->IN[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_RECEIVE_ACK;
380 }
381 }
382
383 /* Sends master receive nack command to IN/TBUF register based on FIFO/non-FIFO modes. */
XMC_I2C_CH_MasterReceiveNack(XMC_USIC_CH_t * const channel)384 void XMC_I2C_CH_MasterReceiveNack(XMC_USIC_CH_t *const channel)
385 {
386 /* Check FIFO size */
387 if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0U)
388 {
389 while(XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
390 {
391 /* check TDV, wait until TBUF is ready */
392 }
393
394 /* clear PSR_TBIF */
395 XMC_I2C_CH_ClearStatusFlag(channel, (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
396
397 channel->TBUF[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_RECEIVE_NACK;
398 }
399 else
400 {
401 channel->IN[0] = (uint32_t)XMC_I2C_CH_TDF_MASTER_RECEIVE_NACK;
402 }
403 }
404
405 /* Reads the data from RBUF if FIFO size is 0 otherwise from OUTR. */
XMC_I2C_CH_GetReceivedData(const XMC_USIC_CH_t * const channel)406 uint8_t XMC_I2C_CH_GetReceivedData(const XMC_USIC_CH_t *const channel)
407 {
408 uint8_t retval;
409
410 /* Check FIFO size */
411 if ((channel->RBCTR & USIC_CH_RBCTR_SIZE_Msk) == 0U)
412 {
413 retval = (uint8_t)channel->RBUF;
414 }
415 else
416 {
417 retval = (uint8_t)channel->OUTR;
418 }
419
420 return retval;
421 }
422
423 /* Sets the operating mode of USIC to IDLE */
XMC_I2C_CH_Stop(XMC_USIC_CH_t * const channel)424 XMC_I2C_CH_STATUS_t XMC_I2C_CH_Stop(XMC_USIC_CH_t *const channel)
425 {
426 XMC_I2C_CH_STATUS_t status = XMC_I2C_CH_STATUS_OK;
427
428 if (((uint32_t)XMC_USIC_CH_GetTransmitBufferStatus(channel) & (uint32_t)XMC_USIC_CH_TBUF_STATUS_BUSY) != 0U)
429 {
430 status = XMC_I2C_CH_STATUS_BUSY;
431 }
432 else
433 {
434 /* USIC channel in IDLE mode */
435 XMC_USIC_CH_SetMode(channel, XMC_USIC_CH_OPERATING_MODE_IDLE);
436 }
437 return status;
438 }
439
XMC_I2C_CH_EnableEvent(XMC_USIC_CH_t * const channel,const uint32_t event)440 void XMC_I2C_CH_EnableEvent(XMC_USIC_CH_t *const channel, const uint32_t event)
441 {
442 channel->CCR |= (event&0x1fc00U);
443 channel->PCR_IICMode |= ((event) & 0x41fc0000U);
444 }
445
XMC_I2C_CH_DisableEvent(XMC_USIC_CH_t * const channel,const uint32_t event)446 void XMC_I2C_CH_DisableEvent(XMC_USIC_CH_t *const channel, const uint32_t event)
447 {
448 channel->CCR &= (uint32_t)~(event&0x1fc00U);
449 channel->PCR_IICMode &= (uint32_t)~((event) & 0x41fc0000U);
450 }
451