1 /**
2  * @file xmc_uart.c
3  * @date 2019-07-01
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  *     - xmc_uart_ch_stop API implementation corrected.
44  *     - Modified XMC_UART_CH_Stop() API for not setting to IDLE the channel if it is busy <br>
45  *
46  * 2015-06-20:
47  *     - Removed GetDriverVersion API <br>
48  *
49  * 2015-09-01:
50  *     - Modified XMC_UART_CH_EnableEvent() and XMC_UART_CH_DisableEvent() for supporting multiple events configuration <br>
51  *
52  * 2016-07-22:
53  *     - Modified XMC_UART_CH_Init() to enable transfer status BUSY
54  *     - Modified XMC_UART_CH_Stop() to check for transfer status
55  *
56  * 2019-05-07:
57  *     - Added XMC_UART_CH_SetBaudrateEx() which allows to select between baudrate generator normal divider and fractional divider mode
58  *
59  * 2019-07-01:
60  *    - Fix XMC_UART_CH_SetBaudrateEx() compiler warning
61  *
62  * @endcond
63  *
64  */
65 
66 /*********************************************************************************************************************
67  * HEADER FILES
68  *********************************************************************************************************************/
69 
70 #include <xmc_scu.h>
71 #include <xmc_uart.h>
72 
73 /*********************************************************************************************************************
74  * MACROS
75  *********************************************************************************************************************/
76 
77 #define XMC_UART_CH_OVERSAMPLING (16UL)
78 #define XMC_UART_CH_OVERSAMPLING_MIN_VAL (4UL)
79 
80 /*********************************************************************************************************************
81  * API IMPLEMENTATION
82  *********************************************************************************************************************/
83 
XMC_UART_CH_Init(XMC_USIC_CH_t * channel,const XMC_UART_CH_CONFIG_t * const config)84 void XMC_UART_CH_Init(XMC_USIC_CH_t *channel, const XMC_UART_CH_CONFIG_t *const config)
85 {
86   uint32_t oversampling = XMC_UART_CH_OVERSAMPLING;
87 
88   /* USIC channel switched on*/
89   XMC_USIC_CH_Enable(channel);
90 
91   if(config->oversampling != 0U)
92   {
93     oversampling = (uint32_t)config->oversampling;
94   }
95 
96   /* Configure baud rate */
97   if (config->normal_divider_mode)
98   {
99     /* Normal divider mode */
100     (void)XMC_USIC_CH_SetBaudrateEx(channel, config->baudrate, oversampling);
101   }
102   else
103   {
104     /* Fractional divider mode */
105     (void)XMC_USIC_CH_SetBaudrate(channel, config->baudrate, oversampling);
106   }
107 
108   /* Configure frame format
109    * Configure the number of stop bits
110    * Pulse length is set to 0 to have standard UART signaling,
111    * i.e. the 0 level is signaled during the complete bit time
112    * Sampling point set equal to the half of the oversampling period
113    * Enable Sample Majority Decision
114    * Enable Transfer Status BUSY
115    */
116   channel->PCR_ASCMode = (uint32_t)(((config->stop_bits - 1UL) << USIC_CH_PCR_ASCMode_STPB_Pos) |
117                                     (((oversampling >> 1UL) + 1UL) << USIC_CH_PCR_ASCMode_SP_Pos) |
118                                     USIC_CH_PCR_ASCMode_SMD_Msk |
119                                     USIC_CH_PCR_ASCMode_RSTEN_Msk | USIC_CH_PCR_ASCMode_TSTEN_Msk);
120 
121   /* Set passive data level, high
122      Set word length. Data bits - 1
123      If frame length is > 0, frame_lemgth-1; else, FLE = WLE (Data bits - 1)
124      Transmission Mode: The shift control signal is considered active if it
125      is at 1-level. This is the setting to be programmed to allow data transfers */
126   channel->SCTR = (uint32_t)((((uint32_t)config->data_bits - 1UL) << USIC_CH_SCTR_WLE_Pos) |
127                              ((0x1UL << USIC_CH_SCTR_TRM_Pos) | USIC_CH_SCTR_PDL_Msk));
128 
129   if (config->frame_length != 0U)
130   {
131     channel->SCTR |= (uint32_t)(((uint32_t)config->frame_length - 1UL) << USIC_CH_SCTR_FLE_Pos);
132   }
133   else
134   {
135     channel->SCTR |= (uint32_t)(((uint32_t)config->data_bits - 1UL) << USIC_CH_SCTR_FLE_Pos);
136   }
137 
138   /* Enable transfer buffer */
139   channel->TCSR = (0x1UL << USIC_CH_TCSR_TDEN_Pos) |
140                   USIC_CH_TCSR_TDSSM_Msk;
141 
142   /* Clear protocol status */
143   channel->PSCR = 0xFFFFFFFFUL;
144 
145   /* Set parity settings */
146   channel->CCR = (uint32_t)config->parity_mode;
147 }
148 
XMC_UART_CH_SetBaudrate(XMC_USIC_CH_t * const channel,uint32_t rate,uint32_t oversampling)149 XMC_UART_CH_STATUS_t XMC_UART_CH_SetBaudrate(XMC_USIC_CH_t *const channel, uint32_t rate, uint32_t oversampling)
150 {
151   XMC_UART_CH_STATUS_t status;
152 
153   status = XMC_UART_CH_STATUS_ERROR;
154 
155   if ((rate <= (XMC_SCU_CLOCK_GetPeripheralClockFrequency() >> 2U)) && (oversampling >= XMC_UART_CH_OVERSAMPLING_MIN_VAL))
156   {
157     if (XMC_USIC_CH_SetBaudrate(channel, rate, oversampling) == XMC_USIC_CH_STATUS_OK)
158     {
159       status = XMC_UART_CH_STATUS_OK;
160     }
161   }
162   return status;
163 }
164 
XMC_UART_CH_SetBaudrateEx(XMC_USIC_CH_t * const channel,uint32_t rate,uint32_t oversampling,bool normal_divider_mode)165 XMC_UART_CH_STATUS_t XMC_UART_CH_SetBaudrateEx(XMC_USIC_CH_t *const channel, uint32_t rate, uint32_t oversampling, bool normal_divider_mode)
166 {
167   XMC_USIC_CH_STATUS_t status;
168 
169   if ((rate <= (XMC_SCU_CLOCK_GetPeripheralClockFrequency() >> 2U)) && (oversampling >= XMC_UART_CH_OVERSAMPLING_MIN_VAL))
170   {
171     if (normal_divider_mode)
172     {
173       /* Normal divider mode */
174       status = XMC_USIC_CH_SetBaudrateEx(channel, rate, oversampling);
175     }
176     else
177     {
178       /* Fractional divider mode */
179       status = XMC_USIC_CH_SetBaudrate(channel, rate, oversampling);
180     }
181   }
182   else
183   {
184     status = XMC_USIC_CH_STATUS_ERROR;
185   }
186 
187   return (XMC_UART_CH_STATUS_t)status;
188 }
189 
XMC_UART_CH_Transmit(XMC_USIC_CH_t * const channel,const uint16_t data)190 void XMC_UART_CH_Transmit(XMC_USIC_CH_t *const channel, const uint16_t data)
191 {
192   /* Check FIFO size */
193   if ((channel->TBCTR & USIC_CH_TBCTR_SIZE_Msk) == 0UL)
194   {
195     /* Wait till the Transmit Buffer is free for transmission */
196     while(XMC_USIC_CH_GetTransmitBufferStatus(channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
197     {
198     }
199 
200     /* Clear the Transmit Buffer indication flag */
201     XMC_UART_CH_ClearStatusFlag(channel, (uint32_t)XMC_UART_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION);
202 
203     /*Transmit data */
204     channel->TBUF[0U] = data;
205   }
206   else
207   {
208     channel->IN[0U] = data;
209   }
210 }
211 
XMC_UART_CH_GetReceivedData(XMC_USIC_CH_t * const channel)212 uint16_t XMC_UART_CH_GetReceivedData(XMC_USIC_CH_t *const channel)
213 {
214   uint16_t retval;
215 
216   /* Check FIFO size */
217   if ((channel->RBCTR & USIC_CH_RBCTR_SIZE_Msk) == 0U)
218   {
219     retval = (uint16_t)channel->RBUF;
220   }
221   else
222   {
223     retval = (uint16_t)channel->OUTR;
224   }
225 
226   return retval;
227 }
228 
XMC_UART_CH_Stop(XMC_USIC_CH_t * const channel)229 XMC_UART_CH_STATUS_t XMC_UART_CH_Stop(XMC_USIC_CH_t *const channel)
230 {
231   XMC_UART_CH_STATUS_t status = XMC_UART_CH_STATUS_OK;
232 
233   if (((XMC_USIC_CH_GetTransmitBufferStatus(channel) & (uint32_t) XMC_USIC_CH_TBUF_STATUS_BUSY) != 0U) ||
234       ((XMC_UART_CH_GetStatusFlag(channel) & XMC_UART_CH_STATUS_FLAG_TRANSFER_STATUS_BUSY) != 0))
235   {
236     status = XMC_UART_CH_STATUS_BUSY;
237   }
238   else
239   {
240     /* USIC channel in IDLE mode */
241     XMC_USIC_CH_SetMode(channel, XMC_USIC_CH_OPERATING_MODE_IDLE);
242   }
243   return status;
244 }
245 
XMC_UART_CH_EnableEvent(XMC_USIC_CH_t * const channel,const uint32_t event)246 void XMC_UART_CH_EnableEvent(XMC_USIC_CH_t *const channel, const uint32_t event)
247 {
248   channel->CCR |= (event&0x1fc00U);
249   channel->PCR_ASCMode |= (event&0xf8U);
250 }
251 
XMC_UART_CH_DisableEvent(XMC_USIC_CH_t * const channel,const uint32_t event)252 void XMC_UART_CH_DisableEvent(XMC_USIC_CH_t *const channel, const uint32_t event)
253 {
254   channel->CCR &= (uint32_t)~(event&0x1fc00U);
255   channel->PCR_ASCMode &= (uint32_t)~(event&0xf8U);
256 }
257