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