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